• Android系统启动过程全解析


        Android系统是一款基于Linux的移动操作系统,那么Android是如何启动起来的呢?本文就详细阐述Android系统的启动过程。

           从内核之上,我们首先应该从文件系统的init开始,因为 init 是内核进入文件系统后第一个运行的程序,通常我们可以在linux的命令行中指定内核第一个调用谁,如果没指定那么内核将会到/sbin/、/bin/ 等目录下查找默认的init,如果没有找到那么就报告出错。

           init.c位置:system/core/init/init.c。

           在init.c的main函数里面完成以下步骤:

           1、创建设备节点。

           2、初始化log系统。

           3、解析init.rc文件,解析函数在同一目录的parser.c里面实现。

           4、初始化属性服务器,在同一目录下的property_service.c里面实现。

           。。。。

           最后、进入loop等待事件到来。

           init.rc的解析过程

           init.rc是一个初始化脚本,路径(不确定):device/renesas/emev/init.rc

           在init.c的main函数里面,调用parser.c的parse_config_file("/init.rc");执行解析过程。

           先读取文件内容到data里面,再调用parse_config(fn, data);进行解析。

           init.rc包含Android初始化语言的四大类声明:行为类(Actions)、命令类(Commands)、服务类(Services)、选项类(Options),解析完会形成两个列表service_list 和action_list。

           其中有一个很重要的服务就是zygote,在init.rc里面的片段:

    Java代码
    1. service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server   
    2.     socket zygote stream 666  
    3.     onrestart write /sys/android_power/request_state wake   
    4.     onrestart write /sys/power/state on   
    5.     onrestart restart media  

           这是脚本中service的格式:

    Java代码
    1. service <name> <pathname> [ <argument> ]*   
    2. <option>   
    3. <option>   
    4. ...  

           zygote对应的可执行文件为app_process,android2.2中它的源代码位置:framework/base/cmds/app_process。

           app_main.cpp的main函数,它先调用AndroidRuntime::addVmArguments将它的参数“-Xzygote /system/bin”传给AndroidRuntime作为启动JavaVM用。接着如果定位余下的参数,如果有"--zygote",执行下面代码,从参数可以知道,这时候要求启动start system server,并且将com.android.internal.os.ZygoteInit装载至虚拟机。

    C++代码
    1. ZygoteInit.java的main方法)。      
    2.         if (0 == strcmp("--zygote", arg)) {      
    3.             bool startSystemServer = (i < argc) ?      
    4.                     strcmp(argv[i], "--start-system-server") == 0 : false;      
    5.             setArgv0(argv0, "zygote");      
    6.             set_process_name("zygote");      
    7.             runtime.start("com.android.internal.os.ZygoteInit",      
    8.                 startSystemServer);      
    9.         }    

           否则不启动system server:

    C++代码
    1. set_process_name(argv0);      
    2.      
    3. runtime.mClassName = arg;      
    4.      
    5. // Remainder of args get passed to startup class main()      
    6. runtime.mArgC = argc-i;      
    7. runtime.mArgV = argv+i;      
    8.      
    9.      
    10. LOGV("App process is starting with pid=%d, class=%s. ",      
    11.      getpid(), runtime.getClassName());      
    12. runtime.start();  

           runtime是AppRuntime对象,继承自AndroidRuntime,在AndroitRuntime.app里的start()函数如下,默认装载的是RuntimeInit进程,不启动system server。

    C++代码
    1. void AndroidRuntime::start()      
    2. {      
    3.     start("com.android.internal.os.RuntimeInit",      
    4.         false /* Don't start the system server */);      
    5. }   

           在AndroidRuntime.cpp的start方法内,先启动JAVA虚拟机,在定位执行className类的main方法(如果才存在的话)。

    C++代码
    1. void AndroidRuntime::start(const char* className, const bool startSystemServer)      
    2. {      
    3.     LOGD(" >>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<< ");      
    4.      
    5.      
    6.     /* start the virtual machine */     
    7.     if (startVm(&mJavaVM, &env) != 0)      
    8.         goto bail;      
    9.      
    10.      
    11.     startClass = env->FindClass(slashClassName);      
    12.     if (startClass == NULL) {      
    13.         LOGE("JavaVM unable to locate class '%s' ", slashClassName);      
    14.         /* keep going */     
    15.     } else {      
    16.         startMeth = env->GetStaticMethodID(startClass, "main",      
    17.             "([Ljava/lang/String;)V");      
    18.         if (startMeth == NULL) {      
    19.             LOGE("JavaVM unable to find main() in '%s' ", className);      
    20.             /* keep going */     
    21.         } else {      
    22.             env->CallStaticVoidMethod(startClass, startMeth, strArray);      
    23.         }      
    24.     }      
    25. }    

           先看怎么启动虚拟机的,在startVm方法内,先将一些系统参数选项,包括虚拟机相关的属性,保存到一个JavaVMOption的实例内,比如虚拟机的堆大小,是否check jni,JNI版本信息,最后将这些参数传给JNI_CreateJavaVM,创建JAVA虚拟机实例。

    C++代码
    1. //JNI_CreateJavaVM在jni.h中有声明,代码位置:dalvik/libnativehelper/include/nativehelper/,在Jni.c中有定义      
    2. jint JNI_GetDefaultJavaVMInitArgs(void*);      
    3. jint JNI_CreateJavaVM(JavaVM**, JNIEnv**, void*);      
    4. jint JNI_GetCreatedJavaVMs(JavaVM**, jsize, jsize*);    

           在JNI_CreateJavaVM中,先检查JNI的版本,为JavaVM,JNIEnv开辟空间,保存通用接口,最后解析传进来的参数,最后调用dvmStartup启动虚拟机(有些传给JNI_CreateJavaVM的参数,也直接传给了dvmStartup)。

           这里的JNIEnv实际是JNIEnvExt强制转换过来的,JNIEnvExt是JNIEnv结构体的扩展,JNIEnExt前端与JNIEnv完全对齐,都是JNI函数指针。相当于JNIEnExt对JNIEnv进行了赋值。

    C++代码
    1. pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);   

           在dvmStartup在Init.c定义,先调用setCommandLineDefaults进行一些默认的设置,比如虚拟机的默认heap大小。

    C++代码
    1. static void setCommandLineDefaults()      
    2. {      
    3.     gDvm.heapSizeStart = 2 * 1024 * 1024;   // Spec says 16MB; too big for us.      
    4.     gDvm.heapSizeMax = 16 * 1024 * 1024;    // Spec says 75% physical mem      
    5.     gDvm.stackSize = kDefaultStackSize;      
    6. }    

           然后调用dvmProcessOptions处理传进来的参数,比如是否执行zygote,最后,根据gDvm.zygote的值,是否申请一个新的堆,这个值在有参数-Xzygote置1。

    C++代码
    1. if (gDvm.zygote) {      
    2.     if (!dvmInitZygote())      
    3.         goto fail;      
    4. else {      
    5.     if (!dvmInitAfterZygote())      
    6.         goto fail;      
    7. }  

           到这里,虚拟机算是启动成功了。

           回到AndroidRuntime.cpp的start方法,现在我们要启动ZygoteInit进程,找到ZygoteInit的main方法,调用env->CallStaticVoidMethod(startClass, startMeth, strArray);去启动它。

           CallStaticVoidMethod在Jni.c里面有定义,但不是直接定义的,因此用CallStaticVoidMethod作为函数名直接查定义是查不到的,是这样定义的:

           CALL_STATIC(void, Void, , , false);

           再看CALL_STATIC的宏定义:

    C++代码
    1. #define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref)                     
    2.     static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,          
    3.         jmethodID methodID, ...)                                                  
    4.     {                                                                             
    5.         UNUSED_PARAMETER(jclazz);                                                 
    6.         JNI_ENTER();                                                              
    7.         JValue result;                                                            
    8.         va_list args;                                                             
    9.         va_start(args, methodID);                                                 
    10.         dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);      
    11.         va_end(args);                                                             
    12.         if (_isref && !dvmCheckException(_self))                                  
    13.             result.l = addLocalReference(env, result.l);                          
    14.         JNI_EXIT();                                                               
    15.         return _retok;                                                            
    16.     }                                                                             
    17.     static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,         
    18.         jmethodID methodID, va_list args)                                         
    19.     {                                                                             
    20.         UNUSED_PARAMETER(jclazz);                                                 
    21.         JNI_ENTER();                                                              
    22.         JValue result;                                                            
    23.         dvmCallMethodV(_self, (Method*)methodID, NULL, true, &result, args);      
    24.         if (_isref && !dvmCheckException(_self))                                  
    25.             result.l = addLocalReference(env, result.l);                          
    26.         JNI_EXIT();                                                               
    27.         return _retok;                                                            
    28.     }                                                                             
    29.     static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,         
    30.         jmethodID methodID, jvalue* args)                                         
    31.     {                                                                             
    32.         UNUSED_PARAMETER(jclazz);                                                 
    33.         JNI_ENTER();                                                              
    34.         JValue result;                                                            
    35.         dvmCallMethodA(_self, (Method*)methodID, NULL, true, &result, args);      
    36.         if (_isref && !dvmCheckException(_self))                                  
    37.             result.l = addLocalReference(env, result.l);                          
    38.         JNI_EXIT();                                                               
    39.         return _retok;                                                            
    40.     }    

           因此CallStaticVoidMethod调用的是dvmCallMethodV方法,至于怎么样再调用到ZygoteInit的main方法,有待研究,现在直接看ZygoteInit的main方法,它的参数是这样定义的:

    C++代码
    1. stringClass = env->FindClass("java/lang/String");      
    2. assert(stringClass != NULL);      
    3. strArray = env->NewObjectArray(2, stringClass, NULL);      
    4. assert(strArray != NULL);      
    5. classNameStr = env->NewStringUTF(className);      
    6. assert(classNameStr != NULL);      
    7. env->SetObjectArrayElement(strArray, 0, classNameStr);      
    8. startSystemServerStr = env->NewStringUTF(startSystemServer ?      
    9.                                              "true" : "false");      
    10. env->SetObjectArrayElement(strArray, 1, startSystemServerStr);   

           申请一个String变量,给把类名作为第0个参数,第二个参数是"ture"或"false",用来决定是否启动system service,在ZygoteInit的main方法会读取这个参数。

    C++代码
    1. if (argv[1].equals("true")) {      
    2.     startSystemServer();      
    3. else if (!argv[1].equals("false")) {      
    4.     throw new RuntimeException(argv[0] + USAGE_STRING);      
    5. }  

           它读取到第一个参数是"true",所以调用startSystemServer启动system server,在startSystemServer中,调用Zygote的forkSystemServer,fork出来的子进程,就是system server了,调用事的参数如下:

    C++代码
    1. String args[] = {      
    2.     "--setuid=1000",      
    3.     "--setgid=1000",      
    4.     "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",      
    5.     "--capabilities=130104352,130104352",      
    6.     "--runtime-init",      
    7.     "--nice-name=system_server",      
    8.     "com.android.server.SystemServer",      
    9. };  

           这些参数解析到一个ZygoteConnection.Arguments对象中。forkSystemServer方法实际上是JNI方法,在vm/native/dalvik_system_Zygote.c中有定义。

    C++代码
    1. static void Dalvik_dalvik_system_Zygote_forkSystemServer(      
    2.         const u4* args, JValue* pResult)      
    3. {      
    4.     pid_t pid;      
    5.     pid = forkAndSpecializeCommon(args);      
    6.     if (pid > 0) {      
    7.         int status;      
    8.      
    9.      
    10.         LOGI("System server process %d has been created", pid);      
    11.         gDvm.systemServerPid = pid;      
    12.      
    13.      
    14.         if (waitpid(pid, &status, WNOHANG) == pid) {      
    15.             LOGE("System server process %d has died. Restarting Zygote!", pid);      
    16.             kill(getpid(), SIGKILL);      
    17.         }      
    18.     }      
    19.     RETURN_INT(pid);      
    20. }  

           具体的fork操作在forkAndSpecializeCommon里面进行,父进程检查子进程是否died。

           在forkAndSpecializeCommon,先判断是否zygote模式,是否剩余有足够的heap空间,最后才执行fork()系统调用。

           fork之后,父进程不做操作,子进程调用dvmInitAfterZygote去为自己申请堆空间。

           子进程返回到startSystemServer方法。

    C++代码
    1. /* For child process */     
    2. if (pid == 0) {      
    3.     handleSystemServerProcess(parsedArgs);      
    4. }   

           调用handleSystemServerProcess方法,在里面先设置uid的权限,再调用RuntimeInit.zygoteInit。

    C++代码
    1. /*    
    2.  * Pass the remaining arguments to SystemServer.    
    3.  * "--nice-name=system_server com.android.server.SystemServer"    
    4.  */     
    5. RuntimeInit.zygoteInit(parsedArgs.remainingArgs);      
    6. /* should never reach here */    

           在zygoteInit里面调用invokeStaticMain,invokeStaticMain先将com.android.server.Systemserver类的main方法取出,作为Method对象,然后和参数一起传给ZygoteInit.MethodAndArgsCaller,MethodAndArgsCaller继承自Runner,最终MethodAndArgsCaller调用Method.invode函数启动System Server。

  • 相关阅读:
    网页打开微信链接 无法返回
    wap尝试调取app(网易新闻为例)
    兼容性
    图片旋转效果
    a标签发送邮件
    windows 下的bash 环境安装npm
    css 设置滚动条的样式
    前端h5遇到的问题及解决办法
    safari input默认样式
    delphi 新版内存表 FDMemTable
  • 原文地址:https://www.cnblogs.com/xiaochao1234/p/3818761.html
Copyright © 2020-2023  润新知