引言
在Zygote完全解析(1)一文中对于Zygote的产生,Zygote孵化进程的原理以及ZygoteInit完成的工作进行了分析。文章的最后,提到了ZygoteInit的main()方法完成的功能如下:
本文将详细分析ZygoteInit.main()方法中的主要4项工作是如何完成的。
1.绑定socket
registerZygoteSocket()方法的代码如下:
|
|
代码非常简单,主要就是先获取socket的文件描述符,然后据此创建一个LocalServerSocket对象并将其赋值给sServerSocket静态变量。
在System.getenv(ANDROID_SOCKET_ENV); 中的套接字由init进程记录在ANDROID_SOCKET_ENV环境变量中,在init.rc中有生成该socket的相关内容,如下所示:
|
|
第一行在上一篇博客中已经说明过了,第二行是socket的名称、种类、访问权限,后面两行到以后再进行说明。
2.预加载应用程序Framework中的类与平台资源
2.1 预加载应用程序Framework中的类
ZygoteInit类会调用proloadClasses()与preloadResources()两个方法,这两个方法分别用于将应用程序Framework中的类,以及图标、图像、字符串等资源加载到内存中,并对装载的类与资源生成链接信息。新生成的Android应用程序在使用这些已经装载的类或资源时,直接使用即可,不需要重新生成链接信息。
此外,还加载许多其他的类,比如图形相关的类andriod.graphics,以及通信相关的类android.net等。
preloadClasses()方法的主要代码如下:
|
|
在code_1处获取一个输入流,以便读取”preloaded-classes”文件(frameworks/base/preloaded-classes)中记录的类,该文件的部分内容如下所示:
|
|
总共有1265个类会被预加载,可以想象一下,如果每启动一个应用程序,就加载一遍这些类,那么将会耗费巨大的时间(感兴趣的读者可以打上log进行测试)。
2.2 预加载应用程序Framework中的资源
在Android应用程序Framework中使用的字符串、颜色、图像文件、音频文件等都被称为资源。应用程序不能直接访问这些资源,需要通过Android开发工具自动生成的R类来访问。与预加载类相似,Android应用程序也会预先加载使用的资源,这样在使用这些资源时的效率会大大提高。
preloadResources()方法的代码如下所示:
|
|
加载资源时,有时会出现因重复调用而造成资源重复加载的情形,为了避免出现这种情况,定义了一个成员变量,用来记录资源加载的状态。若指定资源已经被加载,就会抛出IllegalStateException,并终止方法的执行。
接下来,在code_1和code_2处加载Drawable与Color State资源,frameworks/base/core/res/res/values/arrays.xml文件中记录的preloaded_drawables与preloaded_color_state_lists会被加载到内存中。代码中的M,N分别表示加载的Drawable和Color State资源的个数,打log可以进行查看,也可以查看到加载这些资源所耗费的时间(非常惊人).
3.启动SystemServer
startSystemServer()的代码如下所示:
|
|
1)args[]数组中保存了SystemServer的启动参数,参数的含义也很好理解,无非是为SystemServier设置名称、uid和gid,以及进程分组等。在字符串数组中,最后一个参数com.android.server.SystemServer用于指定SystemServer类;
2)与运行其他应用程序不同,startSystemServer()方法会调用forkSystemServer()方法来创建新进程,并运行SystemServer.系统在运行普通的Android应用程序时,只负责创建应用程序进程,至于进程是否创建成功则并不检查。但是SystemServer则是必须运行的,因此在forkSystemServer()方法中必须检查生成SystemServer进程工作是否正常;
3)code_3处,这个调用比较复杂,首先是handleSystemServerProcess()方法的代码:
|
|
注释已经写得很清楚了,主要作用就是为新fork的进程完成遗留的工作,再跟踪RuntimeInit.zygoteInit()方法,其代码如下:
|
|
其中commonInit()和zygoteInitNative()都是完成一些zygote的初始化工作,感兴趣的读者可以自己去看源码,此处不展开来讲。注意最后一句代码,是调用传入的Java类的main()方法,而在这里就是com.android.server.SystemServer类的main()方法,其代码如下:
|
|
显然,main()方法中主要就是对于目标栈进行了优化,同时加载了android_servers这个native库,加载它的目的是调用init1()这个native方法。
init1()方法的声明如下:
|
|
注释已经说得非常清楚了,就不再解释它的作用了。为了寻找它对应的方法,我们找到了framework/base/service/jni/Android.mk,其内容如下:
|
|
注意底部的libandroid_servers,说明这正是我们要找的mk文件,而它对应的源文件中显然onload.cpp是含有JNI_OnLoad()函数的源文件,下面是onload.cpp的代码:
|
|
显然,我们要找的是register_android_server_SystemServer(env);这个函数(其他几个都是加载具体的本地服务方法映射),register_android_server_SystemServer()函数的代码如下:
|
|
显然,SystemServer中的init1()方法对应的native方法是android_server_SystemServer_init()方法,而该方法调用的是system_init()方法,而这个system_init()方法在frameworks/base/cmds/system_server/library/system_init.cpp中,其源码如下:
|
|
- 1)启动了Surface Flinger服务,Surface Flinger是基于C++的服务,而System Server是Java进程,它不能直接调用Surface Flinger服务。因而System Server必须经由JNI通过调用system_init()函数来运行Surface Flinger服务。
- 2)要完全读懂这段源码,需要等学习完Binder IPC机制之后。 简单地说就是如果是模拟器,则在这里启动并注册AudioFlinger,MediaPlayerService,CameraService,AudioPolicyService(真机的话是在main_mediaserver.cpp中启动这些服务);
- 3)那么剩下的主要就是调用SystemServer的init2()方法了。其中callStatic()函数是JNI包装函数,它允许在C++代码中经由JNI调用Java类的静态方法。
下面我们看一下init2()方法:
|
|
init2()的代码非常简单,就是新建并运行一个ServerThread,下面我们看一下ServerThread的run()方法:
|
|
代码虽然有点长,但是其实非常简单,主要就是各Java服务的注册。同本地系统服务一样,Java系统服务必须先把相关服务注册到Context Manager中,其他模块才能使用这些服务。但是Java系统服务的注册方式与基于C++的本地系统服务不同,它通过调用ServiceManager类的addService()静态方法,将自身注册到Context Manager中。
到这里,我们可以归纳出Android Framework的启动过程:
上面这个图也大致描述出了Android系统的启动过程。下一篇博客中我们将介绍SystemServer是如何处理来自所绑定的socket的请求从而运行新的应用程序的。