整个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 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启动流程。

下面是启动流程图:

更多相关文章

  1. android 开发BUG
  2. Android系统启动流程(四)Launcher启动过程与系统启动流程
  3. Android深入理解Context–Context使用的误区
  4. Android笔记 - Android启动之Launcher启动
  5. [原创] Android(安卓)Activity onNewIntent() 详解
  6. Android嵌入式底层开发技术(应试)
  7. Android开发中 AndroidManifest.xml配置之service,receiver标签配
  8. Android(安卓)NDK开发实例教程
  9. Android系统编译环境变量的设置

随机推荐

  1. PHP中经典的四大排序算法
  2. 一文搞懂PHP类和对象、抽象类、接口
  3. 如何通过imagick让PHP生成PSD文件缩略图(
  4. 实例详解php cookie与session会话基本用
  5. PHP 中的 -> 和 :: 的区别
  6. php判断复选框是否被选中的方法
  7. 关于编译安装msgpack-php的方法
  8. 新手入门PHP必知的七种数据类型
  9. PHP性能优化利器:生成器
  10. 对php-cli环境的理解