Google Chrome for Android: How the sandboxed processes are created

For desktop chrome on Linux, renderer processes are created by signalling a zygote to fork itself. A zygote process is one that listens for spawn requests from a master process and forks itself in response.

Using fork() on Android is discouraged. Google Chrome has a multi-process architecture, and runs on Android. So, I was curious to know how chrome is now creating renderer processes on android and does it use fork()/exec()??

Found some things mentioned below, may be useful. Any corrections are welcome! This post assumes you are familiar with chrome and its multi-process architecture. When built/debugged chromium for android using tar ball from this link and looked at the code, below are some observations:

  • It doesn’t have a special zygote that fork()/exec() to launch a sandboxed process.
  • Google Chrome for android uses Android’s Bound Services to create sandboxed process or you can say sandboxed process are launched as Android’s Bound Services. And each service is launched in seperate process.
  • These bound services are created using AIDL – Android Interface Definition Language
  • Service can be launched in a seperate process using android:process attribute in Android.manifest
    example – android:process=”:sandboxed_process” will run a service in new process named sandboxed_process
  • Service is marked private to the chrome application using android_export = false in AndroidMenifest.xml
  • from the manifest, looks like, maximum 5/6 sandboxed process can be launched:
    - sandboxed_process, sandboxed_process0, sandboxed_process1,…,sandboxed_process4, each process is created with intent
    org.chromium.content.browser.ISandboxedProcessService, ISandboxedProcessService0,
    ISandboxedProcessService1,.., org.chromium.content.browser.ISandboxedProcessService4 respectively

To understand this, you need to know the details:

Source code:
Most of the related java side code is in sub folder: content/android/java/org/chromium/content/browser/
and native code is in sub folder: content/browser/android/

I have gathered some call stacks as well, it will give you exact classes, files, etc.
Load Url:
Thread [1] (Suspended)
25 Java_SandboxedProcessLauncher_start() sandboxed_process_launcher_jni.h:47 0x5ccbc984
24 content::browser::android::StartSandboxedProcess() sandboxed_process_launcher.cc:44 0x5ccbc984
23 ChildProcessLauncher::Context::LaunchInternal() child_process_launcher_android.cc:115 0x5ccc2f38
22 ChildProcessLauncher::Context::Launch() child_process_launcher_android.cc:56 0x5ccc331a
21 ChildProcessLauncher() child_process_launcher_android.cc:176 0x5ccc33a2
20 RenderProcessHostImpl::Init() render_process_host_impl.cc:442 0x5cd2ad00
19 RenderProcessHostImpl::Init() render_process_host_impl.cc:350 0x5cd2ad00
18 RenderViewHost::CreateRenderView() render_view_host.cc:218 0x5cd2f2ba
17 TabContents::CreateRenderViewForRenderManager() tab_contents.cc:2376 0x5cd4f1a2
16 RenderViewHostManager::InitRenderView() render_view_host_manager.cc:556 0x5cd496f2
15 RenderViewHostManager::CreatePendingRenderView() render_view_host_manager.cc:538 0x5cd49c8a
14 RenderViewHostManager::UpdateRendererStateForNavigate() render_view_host_manager.cc:688 0x5cd4a314
13 RenderViewHostManager::Navigate() render_view_host_manager.cc:90 0x5cd4a4e8
12 TabContents::NavigateToEntry() tab_contents.cc:863 0x5cd4defc
11 TabContents::NavigateToEntry() tab_contents.cc:860 0x5cd4e182
10 TabContents::NavigateToPendingEntry() tab_contents.cc:852 0x5cd4e212
9 NavigationControllerImpl::NavigateToPendingEntry() navigation_controller_impl.cc:1292 0x5cd4695e
8 NavigationControllerImpl::LoadEntry() navigation_controller_impl.cc:326 0x5cd477fa
7 NavigationControllerImpl::LoadURLWithUserAgentOverride() navigation_controller_impl.cc:580 0x5cd47fb0
6 NavigationControllerImpl::LoadURL() navigation_controller_impl.cc:562 0x5cd47e4a
5 ChromeView::LoadUrlInternal() chrome_view.cc:1296 0x5bde7260
4 Tab::LoadUrl() tab.cc:540 0x5be07fca
3 LoadUrl() tab_jni.h:147 0x5be080aa
2 0x40884b74
1 0x40884b74

Client side callback when a service is connected:
Thread [ main] (Suspended (breakpoint at line 111 in SandboxedProcessConnection$AsyncBoundServiceConnection))
SandboxedProcessConnection$AsyncBoundServiceConnection.onServiceConnected(ComponentName, IBinder) line: 111
LoadedApk$ServiceDispatcher.doConnected(ComponentName, IBinder) line: 1072
LoadedApk$ServiceDispatcher$RunConnection.run() line: 1089
ActivityThread$H(Handler).handleCallback(Message) line: 605
ActivityThread$H(Handler).dispatchMessage(Message) line: 92
Looper.loop() line: 137
ActivityThread.main(String[]) line: 4697
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object…) line: 511
ZygoteInit$MethodAndArgsCaller.run() line: 790
ZygoteInit.main(String[]) line: 557
NativeStart.main(String[]) line: not available [native method]

After service is created:
Thread [ main] (Suspended)
SandboxedProcessConnection.doConnectionSetup() line: 278
SandboxedProcessConnection.onServiceConnected(ComponentName, IBinder) line: 234
SandboxedProcessConnection.access$200(SandboxedProcessConnection, ComponentName, IBinder) line: 22
SandboxedProcessConnection$AsyncBoundServiceConnection.onServiceConnected(ComponentName, IBinder) line: 113
LoadedApk$ServiceDispatcher.doConnected(ComponentName, IBinder) line: 1072
LoadedApk$ServiceDispatcher$RunConnection.run() line: 1089
ActivityThread$H(Handler).handleCallback(Message) line: 605
ActivityThread$H(Handler).dispatchMessage(Message) line: 92
Looper.loop() line: 137
ActivityThread.main(String[]) line: 4697
Method.invokeNative(Object, Object[], Class, Class[], Class, int, boolean) line: not available [native method]
Method.invoke(Object, Object…) line: 511
ZygoteInit$MethodAndArgsCaller.run() line: 790
ZygoteInit.main(String[]) line: 557
NativeStart.main(String[]) line: not available [native method]

References: http://code.google.com/p/chromium/wiki/LinuxZygote

  1. Here is some extra info:

    For sandboxing, there is one more attribute:
    android:isolatedProcess=true , with this, the service will run under a special process that is isolated from the rest of the system and has no permissions of its own. The only communication with it is through the Service API (binding and starting). – http://developer.android.com/guide/topics/manifest/service-element.html#isolated

    Here is the example service declaration from chrome code:
    src/content/shell/android/java/AndroidManifest.xml :

    android:process=":sandboxed_process0"

    android:permission="org.chromium.content_shell.permission.SANDBOX"

    android:isolatedProcess="true"

    android:exported="false">

    android:process=":sandboxed_process1"

    android:permission="org.chromium.content_shell.permission.SANDBOX"

    android:isolatedProcess="true"

    android:exported="false">

  2. Hi Arun,

    Your blog stoped my searching.. this is exactly what i am looking for. Thanks for the info.
    Keep posted about Internals of Chrome Browser.

Leave a Reply

%d bloggers like this: