New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 784700 link

Starred by 1 user

Issue metadata

Status: WontFix
Owner: ----
Closed: May 2018
Cc:
EstimatedDays: ----
NextAction: ----
OS: Android
Pri: 3
Type: Bug

Blocking:
issue 768253



Sign in to add a comment

onServiceConnected() is posted on UI thread, delaying renderer initialization

Project Member Reported by dskiba@chromium.org, Nov 14 2017

Issue description

When renderer is started during navigation (as opposed to reusing a warmed up one), it can spend significant time idling between ChildProcessServiceImpl.bind() and ChildProcessServiceImpl.mBinder.setupConnection() calls.

That happens because Android schedules call to ServiceConnection.onServiceConnected() to the UI thread, which can be busy with other tasks (see [*]).

The attached trace was taken on 1GiB Android Go device (gobo @ OMB1.171105.001). As you can see onServiceConnected() was called 230ms after ChildProcessServiceImpl.bind(). All that time renderer was idling.

Legend for the screenshot:

[N] navigationStart
[C] android.view.Choreographer$FrameHandler

(1) ChildProcessConnection.ChildServiceConnectionImpl.bind
(2) ChildProcessServiceImpl.bind
(3) ChildProcessConnection.ChildServiceConnectionImpl.onServiceConnected
(4) ChildProcessConnection.onServiceConnectedOnLauncherThread
(5) ChildProcessConnection.doConnectionSetup (calls IChildProcessService.setupConnection)
(6) ChildProcessServiceImpl.mBinder.setupConnection (sets command line and unbocks mMainThread)
(7) ChildProcessServiceImpl.mMainThread is unblocked, loading continues



[*] https://cs.corp.google.com/aosp-oreo/frameworks/base/core/java/android/app/LoadedApk.java?l=1569


 
cold-navigation-trace.html.gz
2.7 MB Download
cold-navigation.png
61.2 KB View Download

Comment 1 by dskiba@chromium.org, Nov 14 2017

Description: Show this description

Comment 2 Deleted

Comment 3 by dskiba@chromium.org, Nov 14 2017

Summary: onServiceConnected() is posted on UI thread, delaying renderer initialization (was: Service connection reporting is blocked on UI thread)

Comment 4 by dskiba@chromium.org, Nov 14 2017

Blocking: 768253
Cc: lizeb@chromium.org yfried...@chromium.org boliu@chromium.org mariakho...@chromium.org
Labels: Performance-Loading LowMemory
Since it doesn't seem possible to change the thread where Android schedules onServiceConnected() callback, I can think of the following ways:

1. Somehow make sure UI thread is not blocked for long time until onServiceConnected() is called.

2. Pass enough information to bind() to start loading right away (i.e. everything that ChildProcessServiceImpl.processConnectionBundle() needs).

Folks, what do you think?

Comment 5 by boliu@chromium.org, Nov 14 2017

I've wondered if I could move onServiceConnected to launcher thread as well, but alas, android just posts it to the main looper I think. So can't do anything on our side, but might be worth talking to android..

> 2. Pass enough information to bind() to start loading right away (i.e. everything that ChildProcessServiceImpl.processConnectionBundle() needs).

No. This has caused problems before where android saves that bundle and reuses it to start a child process for the wrong browser process. So it's only safe to put things into that bundle that's constant for the installation of chrome, not things that can change on each run. The thing that caused problems before was command line args, which after mojo, changes with each child process launch.

Comment 6 by lizeb@google.com, Nov 14 2017

IIUC, all lifecycle events are dispatched to the UI thread, and that's pretty core to Android, as most apps wouldn't be able to cope with a change like that.

On the other hand, the reason why we're blocked is that we're doing the first UI draw, at least that's usually the long main thread task I see in traces. Perhaps Android can do something to make this task shorter, or break it down into multiple tasks.

@dskiba: Is this collected for a cold start with intent?

Comment 7 by dskiba@chromium.org, Nov 14 2017

#5: does a service know pid of the bound client? We could check and discard command line if bundle is reused, but the browser process is not there.

#6: this is the second navigation. I opened Chrome, it navigated to a previously opened tab, I closed that tab mid-loading, and clicked on a NTP tile.
 
Agree with Bo's response to 2. You only really get once onBind in a service, even if there are multiple connections so its dangerous to include params with the request. As to knowing the client: you can only check when a transaction is active (i.e. method call on bound service) you can't check during onBind.

Comment 9 by boliu@chromium.org, Nov 14 2017

> As to knowing the client: you can only check when a transaction is active (i.e. method call on bound service) you can't check during onBind.

Only a *synchronous* binder transaction. I think I've made a bunch of binder calls async already
Sorry folks, I'm going to bug you more on this, I can't walk away from 200ms improvement.

As I understand, the main issue is that Android reuses the bundle when it restarts the service?

But that should be happening now, right? How does everything work now in case renderer service is restarted by Android - when onBind() is called, and how browser discovers that renderer has restarted?
Labels: -Performance-Loading Performance-Startup
I appreciate the tenacity - yes Android will re-use the bundle when it restarts the service. You're right that it shouldn't be happening in general but I can't say I know what happens when android restarts a process and/or whether it just dies immediately cause nobody is bound to it.

There was also the case wehre if you exhaust all renderers and you still have memory you can re-use a renderer process. I forget if that's still possible - Bo would know

Comment 13 by boliu@chromium.org, Nov 27 2017

> But that should be happening now, right? How does everything work now in case renderer service is restarted by Android

Things stored in that bundle are static for that installation of chrome (under the assumption that android won't resue the bundle over package installs). So right now that's just the parameters for library loading, and things in the default CreationParams, which are supposed to be hard coded. There used to be a stern comment warning about adding more to the service bundle, but I can't find that comment anymore..

More context in crbug.com/664341, where android saving the bundle was reproducible, and impact of fixing the bug was very clear on crash graphs.

Comment 14 by boliu@chromium.org, Nov 27 2017

> There was also the case wehre if you exhaust all renderers and you still have memory you can re-use a renderer process. I forget if that's still possible - Bo would know

It's not about re-using renderers. It's re-using the same names service for different renderers.
Owner: dskiba@chromium.org
Status: Started (was: Untriaged)
Owner: ----
Status: WontFix (was: Started)
I'm not sure if the situation described here is a problem in reality. When Chrome reloads a tab on startup, it uses a warmed up renderer. When user navigates to a page from NTP, NTP renderer is used.

The only case I know of is Chrome Home, which doesn't create WebContents until user navigates. But Home is no more.

So I'm closing this as wontfix. It's a nice write up, but not very actionable.

Sign in to add a comment