大学IT网 - 最懂大学生的IT学习网站! QQ资料交流群:367606806
当前位置:大学IT网 > Android技巧 > Android系统启动过程全解析

Android系统启动过程全解析

关键词:系统启动过程AndroidAndroid系统  阅读(694) 赞(17)

[摘要]本文是对Android系统启动过程全解析的讲解,对学习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. servicezygote/system/bin/app_process-Xzygote/system/bin--zygote--start-system-server
  2. socketzygotestream666
  3. onrestartwrite/sys/android_power/request_statewake
  4. onrestartwrite/sys/power/stateon
  5. onrestartrestartmedia

这是脚本中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. boolstartSystemServer=(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. runtime.mClassName=arg;
  3. //Remainderofargsgetpassedtostartupclassmain()
  4. runtime.mArgC=argc-i;
  5. runtime.mArgV=argv+i;
  6. LOGV("Appprocessisstartingwithpid=%d,class=%s.\n",
  7. getpid(),runtime.getClassName());
  8. runtime.start();

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

C++代码
  1. voidAndroidRuntime::start()
  2. {
  3. start("com.android.internal.os.RuntimeInit",
  4. false/*Don'tstartthesystemserver*/);
  5. }

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

C++代码
  1. voidAndroidRuntime::start(constchar*className,constboolstartSystemServer)
  2. {
  3. LOGD("\n>>>>>>>>>>>>>>AndroidRuntimeSTART<<<<<<<<<<<<<<\n");
  4. /*startthevirtualmachine*/
  5. if(startVm(&mJavaVM,&env)!=0)
  6. gotobail;
  7. startClass=env->FindClass(slashClassName);
  8. if(startClass==NULL){
  9. LOGE("JavaVMunabletolocateclass'%s'\n",slashClassName);
  10. /*keepgoing*/
  11. }else{
  12. startMeth=env->GetStaticMethodID(startClass,"main",
  13. "([Ljava/lang/String;)V");
  14. if(startMeth==NULL){
  15. LOGE("JavaVMunabletofindmain()in'%s'\n",className);
  16. /*keepgoing*/
  17. }else{
  18. env->CallStaticVoidMethod(startClass,startMeth,strArray);
  19. }
  20. }

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

C++代码
  1. //JNI_CreateJavaVM在jni.h中有声明,代码位置:dalvik/libnativehelper/include/nativehelper/,在Jni.c中有定义
  2. jintJNI_GetDefaultJavaVMInitArgs(void*);
  3. jintJNI_CreateJavaVM(JavaVM**,JNIEnv**,void*);
  4. jintJNI_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. staticvoidsetCommandLineDefaults()
  2. {
  3. gDvm.heapSizeStart=2*1024*1024;//Specsays16MB;toobigforus.
  4. gDvm.heapSizeMax=16*1024*1024;//Specsays75%physicalmem
  5. gDvm.stackSize=kDefaultStackSize;

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

C++代码
  1. if(gDvm.zygote){
  2. if(!dvmInitZygote())
  3. gotofail;
  4. }else{
  5. if(!dvmInitAfterZygote())
  6. gotofail;
  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. #defineCALL_STATIC(_ctype,_jname,_retfail,_retok,_isref)\
  2. static_ctypeCallStatic##_jname##Method(JNIEnv*env,jclassjclazz,\
  3. jmethodIDmethodID,...)\
  4. {\
  5. UNUSED_PARAMETER(jclazz);\
  6. JNI_ENTER();\
  7. JValueresult;\
  8. va_listargs;\
  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_ctypeCallStatic##_jname##MethodV(JNIEnv*env,jclassjclazz,\
  18. jmethodIDmethodID,va_listargs)\
  19. {\
  20. UNUSED_PARAMETER(jclazz);\
  21. JNI_ENTER();\
  22. JValueresult;\
  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_ctypeCallStatic##_jname##MethodA(JNIEnv*env,jclassjclazz,\
  30. jmethodIDmethodID,jvalue*args)\
  31. {\
  32. UNUSED_PARAMETER(jclazz);\
  33. JNI_ENTER();\
  34. JValueresult;\
  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. }elseif(!argv[1].equals("false")){
  4. thrownewRuntimeException(argv[0]+USAGE_STRING);
  5. }

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

C++代码
  1. Stringargs[]={
  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. staticvoidDalvik_dalvik_system_Zygote_forkSystemServer(
  2. constu4*args,JValue*pResult)
  3. {
  4. pid_tpid;
  5. pid=forkAndSpecializeCommon(args);
  6. if(pid>0){
  7. intstatus;
  8. LOGI("Systemserverprocess%dhasbeencreated",pid);
  9. gDvm.systemServerPid=pid;
  10. if(waitpid(pid,&status,WNOHANG)==pid){
  11. LOGE("Systemserverprocess%dhasdied.RestartingZygote!",pid);
  12. kill(getpid(),SIGKILL);
  13. }
  14. }
  15. RETURN_INT(pid);
  16. }

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

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

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

子进程返回到startSystemServer方法。

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

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

C++代码
  1. /*
  2. *PasstheremainingargumentstoSystemServer.
  3. *"--nice-name=system_servercom.android.server.SystemServer"
  4. */
  5. RuntimeInit.zygoteInit(parsedArgs.remainingArgs);
  6. /*shouldneverreachhere*/

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



相关评论