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

整个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.
Action Service 描述
on early-init 设置init进程以及它创建的子进程的优先级,设置init进程的安全环境
on init 设置全局环境,为cpu accounting创建cgroup(资源控制)挂载点
on fs 挂载mtd分区
on post-fs 改变系统目录的访问权限
on post-fs-data 改变/data目录以及它的子目录的访问权限
on boot 基本网络的初始化,内存管理等等
service servicemanager 启动系统管理器管理所有的本地服务,比如位置、音频、Shared preference等等
service zygote 启动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系统启动过程

posted @ 2015-12-23 16:24  LeoLiang  阅读(8849)  评论(2编辑  收藏  举报