首页 > chromium研究 > Chromium 源码分析: 进程启动和参数传递

Chromium 源码分析: 进程启动和参数传递

2012年9月28日 发表评论 阅读评论

转载时请注明出处和作者联系方式: http://mogoweb.net mogoweb@gmail.com

ContentShell相对于TestShell,不同之处在于使用了Content API,引入了多进程模型,在移植到android平台时,首先需要解决的问题就是启动多进程以及进程之间的通信。下面就分析一下android下是如何启动进程,以及进程间如何通信。

进程启动

我们知道,linux系统创建进程非常简单,调用fork即可以启动一个新进程。Android系统本身基于linux,是不是直接调用fork就可以了呢?我们可以使用ndk编写一个简单的程序验证一下,的确可以调用fork启动进程,例子在git://github.com/mogoweb/android-testcode.git上可以获取到。但是用fork启动的进程不受控,会引起一些奇怪的问题,所以不推荐使用fork。

chromium for android采用的是android的Service机制来启动进程。关于Service机制,<<Pro Android 3>>这本书有专门的一章讲述,android官方文档也有一篇专门讲Service的文章,请参看http://developer.android.com/guide/components/services.html。简单而言,Service就是在后台运行,无用户界面,它可以和应用程序在同一进程中运行,也可以在一个独立的进程中运行。前者称为local service,后者称为remote service。chromium采用后者,达到开启新进程的目的。看看ContentShell应用程序的AndroidManifest.xml文件,有如下行:

<!- The following service entries exist in order to allow us to
     start more than one sandboxed process. ->

<!- NOTE: If you change the values of "android:process" for any of the below services,
     you also need to update kHelperProcessExecutableName in chrome_constants.cc. ->
<service android:name="org.chromium.content.app.SandboxedProcessService0"
         android:process=":sandboxed_process0"
         android:permission="org.chromium.content_shell.permission.SANDBOX"
         android:exported="false" />
<service android:name="org.chromium.content.app.SandboxedProcessService1"
         android:process=":sandboxed_process1"
         android:permission="org.chromium.content_shell.permission.SANDBOX"
         android:exported="false" />
<service android:name="org.chromium.content.app.SandboxedProcessService2"
         android:process=":sandboxed_process2"
         android:permission="org.chromium.content_shell.permission.SANDBOX"
         android:exported="false" />
<service android:name="org.chromium.content.app.SandboxedProcessService3"
         android:process=":sandboxed_process3"
         android:permission="org.chromium.content_shell.permission.SANDBOX"
         android:exported="false" />
<service android:name="org.chromium.content.app.SandboxedProcessService4"
         android:process=":sandboxed_process4"
         android:permission="org.chromium.content_shell.permission.SANDBOX"
         android:exported="false" />

可见Service在使用前必须声明,不能随心所欲的创建,ContentShell事先声明了5个Service,如果查看SandboxedProcessService0 ~ SandboxedProcessService4的源码,可以了解到它们实际上是一样的。考虑到移动设备内存有限,加上一些复用技巧,定义5个Service足够满足需要了,当然最大多同时可开启的进程数限制为5个。

在ContentShell中,子进程被称为SandboxedProcess,启动过程如下图所示,其中灰色部分表示Java部分。启动过程中还涉及到不同的线程,SandboxedProcessService实际是在另一个进程中,图中并没有表现出来,请注意。

进程间参数传递

linux进程间通信的方式有很多,比如管道/命名管道/消息队列/socket等,它们各有优缺点。chromium android选择的是socketpair(出于什么样的考虑,选择socketpair不得而知,chromium windows版本选择的是named pipe)。使用socketpair面临一个重要的问题就是主进程创建的socket fd如何传递到SandboxedProcess。如果在linux下用fork创建新进程就不用操心这个问题了,因为主进程创建的fd,子进程也会复制一份(并非简单的把fd值赋值过去)。Android Service的方法调用差不多算是同一台机器上的RPC,首先需要解决的是函数参数及返回值的marshal/unmarshal,因为处在不同的地址空间,是无法靠指针来传递参数的。Android中Parcel类就是做这件事情的,而自定义类需要Parcelable接口,才能跨进程传递。

socket fd如何写入到Parcel类呢,直接当作int类型写入肯定是不对的,这时该ParcelFileDescriptor类登场了。ParcelFileDescriptor类有一个fromFd的静态方法,用于从fd构造ParcelFileDescriptor类,而ParcelFileDescriptor类实现了Parcelable接口。

将fd封装的代码位于SandboxedProcessConnection::doConnectionSetup(),将fd解包出来的代码位于SandboxedProcessService.java中。当子进程解出了socket fd后,就可以通过这个fd和主进程发送和接收消息了。

chromium将进程间的通信代码封装一层又一层,理解起来有些困难,在之后的文章中再慢慢剖析吧。

转载时请注明出处和作者联系方式: Chromium 源码分析: 进程启动和参数传递 mogoweb@gmail.com

分类: chromium研究 标签: ,
  1. maple
    2012年9月28日21:54 | #1

    应该是“https://github.com/mogoweb/android-testcode.git”

  2. alex
    2012年9月29日10:20 | #2

    @maple
    都可以

  1. 本文目前尚无任何 trackbacks 和 pingbacks.