您的位置:首页 > 移动开发 > Android开发

Android系统启动分析(Init->Zygote->SystemServer->Home activity)

2015-12-23 16:24 721 查看
整个Android系统的启动分为Linux Kernel的启动和Android系统的启动。Linux Kernel启动起来后,然后运行第一个用户程序,在Android中就是init程序。

-------------------------------------------------

以下的内容应该算是学习笔记,特地整理成文。

-------------------------------------------------

1 init程序

init是linux系统中用户空间的第一个进程。由于Android是基于linux内核的,所以init也是Android系统中用户空间的第一个进程,它的进程号是1。init程序并不是由一个源文件组成的,而是由一组源代码文件的目标文件链接而成,这些文件位于如下目录:

<android source code directory>/system/core/init/


它的主要职责在于:

1)、挂载目录,比如/sys, /dev, /proc

mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
......


2)、初始化属性,提供property service(属性服务)管理Android系统中的属性

3)、处理配置文件命令(主要是init.rc脚本文件)

4)、性能分析和执行其它进程

2.1 init分析

init进程的入口函数是main,主要做了这些工作:

1)、解析配置文件,主要是系统配置文件init.rc和与硬件平台相关的配置文件(如init.xxx.rc),在此阶段,也会解析service。

init.rc文件包含五个类型的声明:

Actions(动作以命令流程命名,有一个触发器决定动作是否发生)

on <trigger>
<command>
<command>


Commands

class_start <serviceclass>
Start all services of the specified class if they are not already running


Services(是init进程启动的程序,以及当服务退出时init进程会视情况重启服务)

Options(选项是对服务的描述,它们影响init进程如何以及何时启动服务)

service <name> <pathname> [ <argument> ]*
<option>
<option>


Imports

import <path>
Parse an init config file, extending the current configuration.


ActionService描述
onearly-init设置init进程以及它创建的子进程的优先级,设置init进程的安全环境
oninit设置全局环境,为cpu accounting创建cgroup(资源控制)挂载点
onfs挂载mtd分区
onpost-fs改变系统目录的访问权限
onpost-fs-data改变/data目录以及它的子目录的访问权限
onboot基本网络的初始化,内存管理等等
serviceservicemanager启动系统管理器管理所有的本地服务,比如位置、音频、Shared preference等等
servicezygote启动zygote作为应用进程
2)、执行各个阶段的动作,创建zygote的工作就是在其中某个阶段完成。

3)、调用property_init初始化属性相关的资源,并且通过property_start_service启动属性服务。

4)、init进入一个无限循环,然后等待响应。

2.2 属性服务

应用程序可以通过这个属性机制,查询或设置属性。这个属性服务是怎么实现的呢?其中与init.c和属性服务有关的代码:

property_init();
property_set_fd = start_property_service();


2.2.1 属性服务初始化

首先创建存储空间,property_service.c中有property_init函数

void property_init(void){
init_property_area(); // 初始化属性存储区域
// 加载default.prop文件
load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);
}


虽然属性区域是由init进程创建的,但Android系统希望其它进程也能读取这块内存里的东西。为了做到这一点,它做了以下的工作:

1)、把属性区域创建在共享内存上,而共享内存是可以跨进程的。

2)、Android利用gcc的constructor属性,指明了一个__libc_prenit函数,当bionic libc库被加载时,将自动调用这个__libc_preni,这个函数内部就将完成共享内存到本地进程的映射工作。这样一来,其它进程就知道了这个共享内存。

接着,客户端进程获取存储空间。

2.2.2 属性服务器的分析

2.2.2.1 启动属性服务器
init进程会启动一个属性服务器,而客户端只能通过与属性服务器交互来设置属性。

2.2.2.2 处理设置属性请求
接受请求的地方在init进程中,当属性服务器收到客户端请求时,init会调用handle_property_set_fd进行处理。

if(ufds[1].revents == POLLIN){
handle_property_set_fd(property_set_fd);
}


当客户端的权限满足要求时,init就调用property_set进行相关处理。

if(check_perms(msg.name, cr.uid, cr.gid)){
property_set((char *) msg.name, (char *) msg.value);
}


2.2.2.3 客户端发送请求
客户端通过property_set发送请求,property_set由libcutils库提供。

int property_set(const chatr *key, const char *value){
prop_msg msg;
unsigned resp;
// other code
......
msg.cmd = PROP_MSG_SETPROP; // 设置消息码
strcpy((char *) msg.name, key);
strcpy((char *) msg.value, value);
// 发送请求
return send_prop_msg(&msg);
}


static int send_prop_msg(prop_msg *msg){
int s;
int r;
// 建立和属性服务器的socket链接
s = socket_local_client(PROP_SERVICE_NAME, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
if(s < 0){
return -1;
}
// 通过socket发送
while((r = send(s, msg, sizeof(prop_msg), 0)) < 0){
if((errno == EINTR) || (errno == EAGAIN)){
continue;
}
break;
}

if(r == sizeof(prop_msg)){
r = 0;
} else {
r = -1;
}

close(s);
return r;
}


2 zygote分析

zygote本身是一个Native的应用程序,与驱动、内核等无关。它是由init进程根据init.rc文件中的配置创建的。zygote最初的名字叫“app_process”,这个名字是在Android.mk文件中指定的。在运行中,app_process通过linux下的pctrl系统调用将自己的名字换成了zygote。

在Java中,我们知道不同的虚拟机实例会为不同的应用分配不同的内存。假如Android应用应该尽可能快地启动,但如果Android系统为每一个应用启动不同的Dalvik虚拟机实例,就会消耗大量的内存以及时间。因此,为了克服这个问题,Android系统创造了”zygote”。zygote让Dalvik虚拟机共享代码、低内存占用以及最小的启动时间成为可能。

zygote进程由init通过fork而来,在init.rc中设置的启动参数如下:

-Xzygote /system/bin --zygote --start-system-server


zygote的原型app_process对应的源文件是App_main.cpp。

int main(int argc, const char* const argv[]){
......
AppRuntime runtime;
......
int i = runtime.addVmArguments(argc, argv);
if(i < argc){
runtime.mParentDir = argv[i++];
}

if(i < argc){
arg = argv[i++];
if(0 == strcmp("--zygote", arg)){
bool startSystemServer = (i < argc) ? strcmp(argv[i], "--start-system-server") == 0: false;
setArgv0(argv0, "zygote");
set_process_name("zygote"); // 设置进程名
runtime.start("com.android.internal.os.ZygoteInit", startSystemServer);
}
......
}
......
}


2.1 AppRuntime分析

AppRuntime从AndroidRuntime类派生,它的声明和实现在App_main.cpp中。AppRuntime重载了onStarted, onZygoteInit和onExit函数。其中AndroidRuntime::start(const char* className, const bool startSystemServer)函数做了几件事情:

2.1.1 创建虚拟机--startVm

int AndroidRuntime::startVm(JavaVm** pJavaVM, JNIEnv** pEnv){
// JNI check是指Native层调用JNI函数时,系统所做的一些检查工作。例如,调用NewUTFString函数时,系统会检查传入的字符串是不是符合UTF-8的要求。
property_get("dalvik.vm.checkjni", propBuf, "");
......
// 设置虚拟机的heapsize,默认为16MB
strcpy(heapsizeOptsBuf, "-Xmx");
property_get("dalvik.vm.heapsize", heapsizeOptsBuf + 4, "16m");
......
if(checkJni){
opt.optionsString = "-Xcheck:jni";
mOptions.add(opt);
// JNI check中的资源检查,系统中创建的Global Reference个数不能超过2000
opt.optionString = "-Xjnigreflimit:2000";
mOptions.add(opt);
}

// 调用JNI_CreateJavaVM创建虚拟机,pEnv返回当前线程的JNIEnv变量
if(JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0){
goto bail;
}

return 0;

bail:
free(stackTraceFile);
return result;
}


2.1.2 注册JNI函数--startReg

int AndroidRuntime::startReg(JNIEnv* env){
......
if(register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0){
env->PopLocalFrame(NULL);
return -1;
}
env->PopLocalFrame(NULL);
return 0;
}


static int register_jni_procs(const RegJNIRec array[], size_t count, JNIEnv* env){
for(size_t i = 0; i < count; i++){
if(array[i].mProc(env) < 0){
return -1;
}
}
return 0;
}


statci const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_debug_JNITest),
REG_JNI(register_com_android_internal_os_RuntimeInit),
REG_JNI(register_android_os_SystemClock),
......
}


上面的mProc就是为Java类注册JNI函数。

2.1.3 通过JNI调用Java函数,进入Java世界

env->CallStaticVoidMethod(startClass, startMeth, strArray);


CallStaticVoidMethod最终将调用com.android.internal.os.ZygoteInit的main函数。

public static void main(String argv[]){
try{
SamplingProfilerIntegration.start();
// 1. 注册zygote用的socket. 基于AF_UNIX类型,是一个本机socket
registerZygoteSocket();
// 2. 预加载类和资源
preloadClasses();
preloadResources();
......
// 强制执行一次垃圾回收
gc();

if(argv[1].equals("true")){
startSystemServer(); // 3. 启动system_server进程。该进程是framework的核心。
} else if(!argv[1].equals("false")){
throw new RuntimeException(argv[0] + USAGE_STRING);
}

if(ZYGOTE_FORK_MODE){
runForkMode();
} else {
runSelectLoopMode(); // 4. zygote调用这个函数,进入等待唤醒的状态
}
closeServerSocket();
} catch(MethodAndArgsCaller caller){
caller.run();
} catch(RuntimeException ex){
closeServerSocket();
throw ex;
}
......
}


3 SystemServer分析

SystemServer是由Zygote通过Zygote.forkSystemServer函数fork出来的。

pid = Zygote.forkSystemServer();
if(pid == 0){ // 子进程返回0,即systemServer
handleSystemServerProcess(parseArgs);
}


在handleSystemServerProcess函数中,首先会关闭从Zygote继承下来的socket,并设置SystemServer进程的一些参数,然后调用RuntimeInit.java中的ZygoteInit函数。

public static final void zygoteInit(String[] argv) throws ZygoteInit.MethodAndArgsCaller {
commonInit();
// native层的初始化
zygoteInitNative();
......
invokeStaticMain(startClass, startArgs); // 调用com.android.server.SystemServer类的main函数
}


SystemServer调用了zygoteInitNative后,将与Binder通信系统建立联系,这样SystemServer就可以使用Binder了。zygoteInitNative中调用了onZygoteInit()

virtual void onZygoteInit(){
sp<ProcessState> proc = ProcessState::self();
if(proc->supportsProcesses()){
proc->startThreadPool(); // 启动一个线程,用于Binder通信
}
}


而另外一个关键函数invokeStaticMain

private static void invokeStaticMain(String className, String[] argv) throws ZygoteInit.MethodAndArgsCaller {
// 参数传入,className = "com.android.server.SystemServer"
......
Method m;
try{
m = cl.getMethod("main", new Class[] { String[].class }); // 找到com.android.server.SystemServer类的main函数
} catch(NoSuchMethodException ex){
......
} catch(SecurityException ex){
......
}

......
throw new ZygoteInit.MethodAndArgsCaller(m, argv); // 主动抛出一个异常
}


抛出的异常在哪里被捕获呢?上面已经给出过了。也就是在ZygoteInit.java中

......
catch(MethodAndArgsCaller caller){
caller.run(); // 调用caller的run函数
}


而MethodAndArgsCaller的run函数如下:

public void run(){
try{
mMethod.invoke(null, new Object[] { mArgs }); // mMethod为com.android.server.SystemServer的main函数
} catch(IllegalAccessException ex){
......
}
}


为什么要主动抛出这样一个异常来执行main函数呢?

《深入理解Android 卷I》中是这样解释的:这个调用是在ZygoteInit.main中,相当于Native的main函数,也即入口函数,位于堆栈的顶层。如果不采用抛异常的方式,而是在invokeStaticMain那调用,则会浪费之前函数调用所占用的一些调用堆栈。

那么,这个main函数又做了什么工作呢?

public static void main(String[] args){
System.loadLibrary("android_servers"); // 加载libandroid_servers.so
init1(args); // 调用native的init1函数
}


其中init1函数创建了一些系统服务,然后把调用线程加入到Binder通信中。期间还通过JNI调用了com.android.server.SystemServer类的init2函数,通过单独创建一个线程,用以启动系统的各项服务,如PowerManagerService, BatteryService, WindowManagerService, ActivityManagerService等。

public static final void init2(){
Slog.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}


这个函数的主要功能是创建新的线程ServerThread,它的override的run方法在SystemServer.java中,主要做了以下一些工作:

private void run() {
......
// Initialize native services.
System.loadLibrary("android_servers");
......
// Initialize the system context.
createSystemContext();
......
startCoreServices();
startOtherServices();
......
}


/**
* Starts some essential services that are not tangled up in the bootstrap process.
*/
private void startCoreServices() {
// Tracks the battery level.  Requires LightService.
mSystemServiceManager.startService(BatteryService.class);

// Tracks application usage stats.
mSystemServiceManager.startService(UsageStatsService.class);
mActivityManagerService.setUsageStatsManager(
LocalServices.getService(UsageStatsManagerInternal.class));
// Update after UsageStatsService is available, needed before performBootDexOpt.
mPackageManagerService.getUsageStatsIfNoPackageUsageInfo();

// Tracks whether the updatable WebView is in a ready state and watches for update installs.
mSystemServiceManager.startService(WebViewUpdateService.class);
}


/**
* Starts a miscellaneous grab bag of stuff that has yet to be refactored
* and organized.
*/
private void startOtherServices() {
......
try {
Slog.i(TAG, "Reading configuration...");
SystemConfig.getInstance();

traceBeginAndSlog("StartSchedulingPolicyService");
ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

mSystemServiceManager.startService(TelecomLoaderService.class);

traceBeginAndSlog("StartTelephonyRegistry");
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
......
}
......
}


至此,让我们总结一下SystemServer

1)、ZygoteInit调用startSystemServer创建system_server进程。

2)、SystemServer调用handleSystemServerProcess完成自己的使命。

3)、handleSystemServerProcess抛出异常,最终调用com.android.server.SystemServer的main函数。

4)、main函数加载libandroid_server.so并调用native的init1函数。

5)、init1函数通过JNI调用com.android.server.SystemServer类的init2函数。init2函数创建一个线程,用于加载各种service。

6)、init1函数最终加入到Binder通信系统。

4 Zygote的分裂

zygote分裂出system_server后,就等待runSelectLoopMode等待并处理来自客户的请求。那么,谁会向zygote发送消息呢?这里以一个activity的启动为例作分析。

4.1 ActivityManagerService发送请求

ActivityManagerService由SystemServer创建。假设通过startActivity来启动一个新的acitivity,而这个activity属于一个还未启动的进程,那么这个进程又如何启动呢?先看ActivityManagerService中的startProcessLocked函数

private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr){
......
int pid = Process.start("android.app.ActivityThread", mSimpleProcessManagement ? app.processName : null, uid, uid, gids, debugFlags, null);
......
}


Process.start位于android.os.Process中,而它又调用了startViaZygote, zygoteSendArgsAndGetPid。而在zygoteSendArgsAndGetPid中,首先打开了和zygote通信的socket,接着把请求的参数发到zygote,然后读取zygote处理完的结果,得知是某个进程的pid。

由于ActivityManagerService驻留于SystemServer进程中,所以正是SystemServer向Zygote发送了消息。

还记得前面提过的runSelectLoopMode函数么?它在里面又调用了ZygoteConnection的runOnce

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
try{
args = readArgumentList(); // 读取SystemServer发送过来的参数
descriptors = mSocket.getAncillaryFileDescriptors();
}

......

pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits);
......
if(pid ==0){
handleClientProc(parsedArgs, descriptors, newStderr); //子进程处理
return true;
} else {
return handleParentProc(pid, descriptors, parsedArgs);
}
}


由此可见,zygote分裂子进程后,自己将在handleParentProc中做一些扫尾工作,然后继续等待请求进行下一次分裂。

4.2 zygote响应请求的流程

1)、Zygote进程调用runSelectLoopMode

2)、SystemServer进程发送消息到Zygote

3)、Zygote通过fork创建子进程

4)、子进程调用android.app.ActivityThread的main函数

5 Home界面启动

待Application Framework层的ActivityManagerService准备就绪后,就会通知各个模块,继续执行上层应用。

先附一张体系结构图:



// We now tell the activity manager it is okay to run third party
// code.  It will call back into us once it has gotten to the state
// where third party code can really run (but before it has actually
// started launching the initial applications), for us to complete our
// initialization.
mActivityManagerService.systemReady(new Runnable() {
@Override
public void run() {
Slog.i(TAG, "Making services ready");
......
try {
mActivityManagerService.startObservingNativeCrashes();
} catch (Throwable e) {
reportWtf("observing native crashes", e);
}
......
try {
if (networkScoreF != null) networkScoreF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Score Service ready", e);
}
......
try {
if (networkManagementF != null) networkManagementF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Managment Service ready", e);
}
......
try {
if (networkStatsF != null) networkStatsF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Stats Service ready", e);
}
......
try {
if (networkPolicyF != null) networkPolicyF.systemReady();
} catch (Throwable e) {
reportWtf("making Network Policy Service ready", e);
}
......
try {
if (connectivityF != null) connectivityF.systemReady();
} catch (Throwable e) {
reportWtf("making Connectivity Service ready", e);
}
......
try {
if (audioServiceF != null) audioServiceF.systemReady();
} catch (Throwable e) {
reportWtf("Notifying AudioService running", e);
}
......
}
});


public void systemReady(final Runnable goingCallback) {
......
// Start up initial activity.
mBooting = true;
startHomeActivityLocked(mCurrentUserId, "systemReady");
......
}


这样一来,就启动了Home界面,完成了整个Android启动流程。

下面是启动流程图:



参考:

《深入理解Android 卷I》 邓凡平 著

Android启动过程深入解析

Android系统启动过程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: