整个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准备就绪后,就会通知各个模块,继续执行上层应用。

先附一张体系结构图:

Zygote->SystemServer->Home activity)_第1张图片" width="650" height="564" style="border:1px solid black;">

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

下面是启动流程图:

Zygote->SystemServer->Home activity)_第2张图片" width="650" height="660" style="border:1px solid black;">

参考:

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

Android启动过程深入解析

Android系统启动过程

更多相关文章

  1. 一款霸榜 GitHub 的开源 Linux 资源监视器!
  2. Android中native_handle private_handle_t ANativeWindowBuffer
  3. MediaRecorderClient决定使用stagefright还是opencore实现录音录
  4. listview中放Button 点击 长按事件
  5. Android(安卓)glide-transformations 使用demo 实现Blur等效果
  6. android 自定义view添加自定义xml属性
  7. android 设置布局横屏竖屏
  8. 解决init: sys_prop: permission denied uid:1003 name:service.
  9. Android(安卓)JNI 几个常用方法

随机推荐

  1. android用户界面之菜单(Menu)教程实例汇
  2. android adb和串口调试.
  3. Android设备的识别
  4. Android(安卓)个人手机通讯录开发
  5. 从零开始学习Android一
  6. 升级Android(安卓)ADT 和SDK
  7. This app has been built with an incorr
  8. Android(安卓)Listview 隐藏滚动条
  9. 开发技术前线 第七期 周报
  10. android利用handler线程间的通信