«

Android系统启动过程全解析

时间:2024-3-2 18:58     作者:韩俊     分类: Android


原文地址:http://www.jizhuomi.com/android/course/345.html

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代码

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666
onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on
onrestart restart media

这是脚本中service的格式:

Java代码

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

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++代码

ZygoteInit.java的main方法)。 if (0 == strcmp("--zygote", arg)) {

        bool startSystemServer = (i &lt; argc) ?   
                   strcmp(argv[i], &quot;--start-system-server&quot;) == 0 : false;   

        setArgv0(argv0, &quot;zygote&quot;);                  set_process_name(&quot;zygote&quot;);   

        runtime.start(&quot;com.android.internal.os.ZygoteInit&quot;,   
               startSystemServer);      
    }    

否则不启动system server:

C++代码

set_process_name(argv0);
runtime.mClassName = arg;
// Remainder of args get passed to startup class main() runtime.mArgC = argc-i;
runtime.mArgV = argv+i;
LOGV("App process is starting with pid=%d, class=%s.n",

 getpid(), runtime.getClassName());      runtime.start();  

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

C++代码

void AndroidRuntime::start() {
start("com.android.internal.os.RuntimeInit", false / Don't start the system server /);

}

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

C++代码

void AndroidRuntime::start(const char* className, const bool startSystemServer)
{
LOGD("n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<n");

     /* start the virtual machine */  

if (startVm(&amp;mJavaVM, &amp;env) != 0)   
       goto bail;   

startClass = env-&gt;FindClass(slashClassName);          if (startClass == NULL) {   

    LOGE(&quot;JavaVM unable to locate class '%s'n&quot;, slashClassName);   
       /* keep going */  

} else {              startMeth = env-&gt;GetStaticMethodID(startClass, &quot;main&quot;,   

        &quot;([Ljava/lang/String;)V&quot;);              if (startMeth == NULL) {   

        LOGE(&quot;JavaVM unable to find main() in '%s'n&quot;, className);   
           /* keep going */  

    } else {                  env-&gt;CallStaticVoidMethod(startClass, startMeth, strArray);      
    }          }      

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

C++代码

//JNI_CreateJavaVM在jni.h中有声明,代码位置:dalvik/libnativehelper/include/nativehelper/,在Jni.c中有定义 jint JNI_GetDefaultJavaVMInitArgs(void*);

jint JNI_CreateJavaVM(JavaVM, JNIEnv, void*);
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++代码

pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);

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

C++代码

static void setCommandLineDefaults()
{
gDvm.heapSizeStart = 2 1024 1024; // Spec says 16MB; too big for us. gDvm.heapSizeMax = 16 1024 1024; // Spec says 75% physical mem
gDvm.stackSize = kDefaultStackSize; }

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

C++代码

if (gDvm.zygote) { if (!dvmInitZygote())

    goto fail;      } else {   

if (!dvmInitAfterZygote())              goto fail;   

}

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

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

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

CALL_STATIC(void, Void, , , false);

再看CALL_STATIC的宏定义:

C++代码

define CALL_STATIC(_ctype, _jname, _retfail, _retok, _isref) static _ctype CallStatic##_jname##Method(JNIEnv* env, jclass jclazz,

    jmethodID methodID, ...)                                                      {                                                                             
    UNUSED_PARAMETER(jclazz);                                                         JNI_ENTER();                                                              
    JValue result;                                                                    va_list args;                                                          

    va_start(args, methodID);                                                         dvmCallMethodV(_self, (Method*)methodID, NULL, true, &amp;result, args);   

    va_end(args);                                                                     if (_isref &amp;&amp; !dvmCheckException(_self))                               

        result.l = addLocalReference(env, result.l);                                  JNI_EXIT();                                                               
    return _retok;                                                         
   }                                                                             
static _ctype CallStatic##_jname##MethodV(JNIEnv* env, jclass jclazz,      
       jmethodID methodID, va_list args)                                      

{                                                                                     UNUSED_PARAMETER(jclazz);                                                 
    JNI_ENTER();                                                                      JValue result;                                                            
    dvmCallMethodV(_self, (Method*)methodID, NULL, true, &amp;result, args);   
       if (_isref &amp;&amp; !dvmCheckException(_self))                               

        result.l = addLocalReference(env, result.l);                                  JNI_EXIT();                                                               
    return _retok;                                                         
   }                                                                             
static _ctype CallStatic##_jname##MethodA(JNIEnv* env, jclass jclazz,      
       jmethodID methodID, jvalue* args)                                         
{                                                                                     UNUSED_PARAMETER(jclazz);                                                 
    JNI_ENTER();                                                                      JValue result;                                                            
    dvmCallMethodA(_self, (Method*)methodID, NULL, true, &amp;result, args);   
       if (_isref &amp;&amp; !dvmCheckException(_self))                               

        result.l = addLocalReference(env, result.l);                                  JNI_EXIT();                                                               
    return _retok;                                                         
   }    

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

C++代码

stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(2, stringClass, NULL); assert(strArray != NULL);
classNameStr = env->NewStringUTF(className); assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr); startSystemServerStr = env->NewStringUTF(startSystemServer ?
"true" : "false");
env->SetObjectArrayElement(strArray, 1, startSystemServerStr);

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

C++代码

if (argv[1].equals("true")) {
startSystemServer();
} else if (!argv[1].equals("false")) {
throw new RuntimeException(argv[0] + USAGE_STRING);

}

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

C++代码

String args[] = { "--setuid=1000",

&quot;--setgid=1000&quot;,          &quot;--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003&quot;,   

&quot;--capabilities=130104352,130104352&quot;,          &quot;--runtime-init&quot;,   

&quot;--nice-name=system_server&quot;,          &quot;com.android.server.SystemServer&quot;,   

};

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

C++代码

static void Dalvik_dalvik_system_Zygote_forkSystemServer(
const u4 args, JValue pResult)

{ pid_t pid;
pid = forkAndSpecializeCommon(args); if (pid > 0) {

    int status;           
         LOGI(&quot;System server process %d has been created&quot;, pid);   

    gDvm.systemServerPid = pid;           
         if (waitpid(pid, &amp;status, WNOHANG) == pid) {   

        LOGE(&quot;System server process %d has died. Restarting Zygote!&quot;, pid);   
           kill(getpid(), SIGKILL);      
    }          }      
RETURN_INT(pid);      }  

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

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

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

子进程返回到startSystemServer方法。

C++代码

/ For child process / if (pid == 0) {
handleSystemServerProcess(parsedArgs); }

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

C++代码

/ Pass the remaining arguments to SystemServer.

  • "--nice-name=system_server com.android.server.SystemServer" */

RuntimeInit.zygoteInit(parsedArgs.remainingArgs); / should never reach here /

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

标签: android

热门推荐