onServiceConnected() is posted on UI thread, delaying renderer initialization |
||||||
Issue descriptionWhen 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
,
Nov 14 2017
,
Nov 14 2017
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?
,
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.
,
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?
,
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.
,
Nov 14 2017
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.
,
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
,
Nov 23 2017
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?
,
Nov 23 2017
,
Nov 23 2017
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
,
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.
,
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.
,
Dec 4 2017
,
May 30 2018
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 |
||||||
Comment 1 by dskiba@chromium.org
, Nov 14 2017