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. runtime.mClassName = arg;
  3. // Remainder of args get passed to startup class main()
  4. runtime.mArgC = argc-i;
  5. runtime.mArgV = argv+i;
  6. LOGV("App process is starting with pid=%d, class=%s.\n",
  7. getpid(), runtime.getClassName());
  8. 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("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
  4. /* start the virtual machine */
  5. if (startVm(&mJavaVM, &env) != 0)
  6. goto bail;
  7. startClass = env->FindClass(slashClassName);
  8. if (startClass == NULL) {
  9. LOGE("JavaVM unable to locate class ‘%s‘\n", slashClassName);
  10. /* keep going */
  11. } else {
  12. startMeth = env->GetStaticMethodID(startClass, "main",
  13. "([Ljava/lang/String;)V");
  14. if (startMeth == NULL) {
  15. LOGE("JavaVM unable to find main() in ‘%s‘\n", className);
  16. /* keep going */
  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. 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;

然后调用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. LOGI("System server process %d has been created", pid);
  9. gDvm.systemServerPid = pid;
  10. if (waitpid(pid, &status, WNOHANG) == pid) {
  11. LOGE("System server process %d has died. Restarting Zygote!", pid);
  12. kill(getpid(), SIGKILL);
  13. }
  14. }
  15. RETURN_INT(pid);
  16. }

具体的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。

Android系统启动过程全解析,布布扣,bubuko.com

时间: 2024-08-24 22:32:40

Android系统启动过程全解析的相关文章

Eclipse,到了说再见的时候了——Android Studio最全解析

去年的Google大会上,Google带给我们一个小玩具--Android Studio,说它是玩具,是因为它确实比较菜,界面过时,操作不流畅,效率也不高,但是现在,虽然版本还是0.6,甚至都没到1.0,但是我们可以发现亲儿子到底是亲儿子,现在的Android Studio已经今非昔比,用了一段时间,简直爱不释手,我觉得,It's time to say goodbye eclipse!本文将带领大家彻底的了解一下Android Studio,注意:由于天朝的原因,我们的了解过程会比较曲折,但是

Android系统启动过程

Android系统启动过程 首先Android框架架构图:(来自网上,我觉得这张图看起来很清晰) Linux内核启动之后就到Android Init进程,进而启动Android相关的服务和应用. 启动的过程如下图所示:(图片来自网上,后面有地址)   下面将从Android4.0源码中,和网络达人对此的总结中,对此过程加以学习了解和总结, 以下学习过程中代码片段中均有省略不完整,请参照源码. 一 Init进程的启动 init进程,它是一个由内核启动的用户级进程.内核自行启动(已经被载入内存,开始

Android动画机制全解析

导论 本文着重讲解Android3.0后推出的属性动画框架Property Animation--Animator. 产生原因 3.0之前已有的动画框架--Animation存在一些局限性, Animation框架定义了透明度,旋转,缩放和位移几种常见的动画,而且控制的是整个View,实现原理是每次绘制视图时View所在的ViewGroup中的drawChild函数获取该View的Animation的Transformation值,然后调用canvas.concat(transformToApp

Android启动过程深入解析

Android启动过程深入解析 2014/06/20 分享到:7 本文由 伯乐在线 - 云海之巅 翻译.未经许可,禁止转载!英文出处:kpbird.欢迎加入翻译小组. 当按下Android设备电源键时究竟发生了什么? Android的启动过程是怎么样的? 什么是Linux内核? 桌面系统linux内核与Android系统linux内核有什么区别? 什么是引导装载程序? 什么是Zygote? 什么是X86以及ARM linux? 什么是init.rc? 什么是系统服务? 当我们想到Android启

Android异步载入全解析之大图处理

Android异步载入全解析之大图处理 异步载入中很重要的一部分就是对图像的处理,这也是我们前面用异步载入图像做示例的原因. 一方面是由于图像处理不好的话会很占内存,并且easyOOM,还有一方面,图像也比文字要大,载入比較慢.所以,在解说了怎样进行多线程.AsyncTask进行多线程载入后,先暂停下后面的学习.来对图像的异步处理进行一些优化工作. 为什么要对图像处理 为什么要对图像进行处理,这是一个很直接的问题.一张图像.无论你拿手机.相机.单反还是什么玩意拍出来,它就有一定的大小,可是在不同

Android异步载入全解析之使用多线程

异步载入之使用多线程 初次尝试 异步.异步,事实上说白了就是多任务处理.也就是多线程执行.多线程那就会有各种问题,我们一步步来看.首先.我们创建一个class--ImageLoaderWithoutCaches,从命名上.大家也看出来,这个类,我们实现的是不带缓存的图像载入,不多说,我们再创建一个方法--showImageByThread,通过多线程来载入图像: /** * Using Thread * @param imageView * @param url */ public void s

Android异步载入全解析之IntentService

Android异步载入全解析之IntentService 搞什么IntentService 前面我们说了那么多,异步处理都使用钦定的AsyncTask.再不济也使用的Thread,那么这个IntentService是个什么鬼. 相对与前面我们提到的这两种异步载入的方式来说.IntentService有一个最大的特点.就是--IntentService不受大部分UI生命周期的影响.它为后台线程提供了一个更直接的操作方式.只是,IntentService的不足主要体如今下面几点: 不能够直接和UI做

Android 系统启动过程简单记录

本文记录Android系统启动过程,包含从linux kernerl到luancher启动完成的过程: 1.linux内核完成系统设置后,会在系统文件中寻找'init'文件,然后启动root进程或者说系统的第一个进程: 2.init进程是linux内核完成系统设置之后启动的第一个进程或者说root进程,它也是其他所有进程的父进程,其有两个作用,一个是挂载目录,比如/sys,/dev等,二是运行init.rc脚本或init.xxx.rc脚本: 3.Init.rc脚本是Android自己规定的初始化

Android 系统启动过程详解

android 使用 linux 内核,一般运行在 ARM 体系架构上,android 设备启动的过程,应用层之下基本等同于linux, 从应用层第一个程序init开始有所区别,下面开始介绍. step1, boot rom 主要作用是加载 boot loader 进入内存并执行,boot rom 一般固化在芯片上,设备启动加电自检后从固定的地址开始执行 step2,boot loader 分2步执行,boot rom只加载了第一部分bootloader代码进入内存,这部分代码随即加载第二部分b