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里面的片段:
- 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的格式:
- 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装载至虚拟机。
- ZygoteInit.java的main方法)。
- 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);
- }
否则不启动system server:
- 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。
- void AndroidRuntime::start()
- {
- start("com.android.internal.os.RuntimeInit",
- false /* Don't start the system server */);
- }
在AndroidRuntime.cpp的start方法内,先启动JAVA虚拟机,在定位执行className类的main方法(如果才存在的话)。
- void AndroidRuntime::start(const char* className, const bool startSystemServer)
- {
- LOGD("\n>>>>>>>>>>>>>> AndroidRuntime START <<<<<<<<<<<<<<\n");
- /* start the virtual machine */
- if (startVm(&mJavaVM, &env) != 0)
- goto bail;
- startClass = env->FindClass(slashClassName);
- if (startClass == NULL) {
- LOGE("JavaVM unable to locate class '%s'\n", slashClassName);
- /* keep going */
- } else {
- startMeth = env->GetStaticMethodID(startClass, "main",
- "([Ljava/lang/String;)V");
- if (startMeth == NULL) {
- LOGE("JavaVM unable to find main() in '%s'\n", className);
- /* keep going */
- } else {
- env->CallStaticVoidMethod(startClass, startMeth, strArray);
- }
- }
- }
先看怎么启动虚拟机的,在startVm方法内,先将一些系统参数选项,包括虚拟机相关的属性,保存到一个JavaVMOption的实例内,比如虚拟机的堆大小,是否check jni,JNI版本信息,最后将这些参数传给JNI_CreateJavaVM,创建JAVA虚拟机实例。
- //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进行了赋值。
- pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL);
在dvmStartup在Init.c定义,先调用setCommandLineDefaults进行一些默认的设置,比如虚拟机的默认heap大小。
- 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。
- 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的宏定义:
- #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, &result, args);\
- va_end(args); \
- if (_isref && !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, &result, args);\
- if (_isref && !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, &result, args);\
- if (_isref && !dvmCheckException(_self)) \
- result.l = addLocalReference(env, result.l); \
- JNI_EXIT(); \
- return _retok; \
- }
因此CallStaticVoidMethod调用的是dvmCallMethodV方法,至于怎么样再调用到ZygoteInit的main方法,有待研究,现在直接看ZygoteInit的main方法,它的参数是这样定义的:
- 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方法会读取这个参数。
- 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了,调用事的参数如下:
- String args[] = {
- "--setuid=1000",
- "--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
- "--capabilities=130104352,130104352",
- "--runtime-init",
- "--nice-name=system_server",
- "com.android.server.SystemServer",
- };
这些参数解析到一个ZygoteConnection.Arguments对象中。forkSystemServer方法实际上是JNI方法,在vm/native/dalvik_system_Zygote.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("System server process %d has been created", pid);
- gDvm.systemServerPid = pid;
- if (waitpid(pid, &status, WNOHANG) == pid) {
- LOGE("System server process %d has died. Restarting Zygote!", pid);
- kill(getpid(), SIGKILL);
- }
- }
- RETURN_INT(pid);
- }
具体的fork操作在forkAndSpecializeCommon里面进行,父进程检查子进程是否died。
在forkAndSpecializeCommon,先判断是否zygote模式,是否剩余有足够的heap空间,最后才执行fork()系统调用。
fork之后,父进程不做操作,子进程调用dvmInitAfterZygote去为自己申请堆空间。
子进程返回到startSystemServer方法。
- /* For child process */
- if (pid == 0) {
- handleSystemServerProcess(parsedArgs);
- }
调用handleSystemServerProcess方法,在里面先设置uid的权限,再调用RuntimeInit.zygoteInit。
- /*
- * 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系统启动过程全解析的更多相关文章
- Android系统启动过程-uBoot+Kernel+Android
摘要:本文是参考大量网上资源在结合自己查看源代码总结出来的,让自己同时也让大家加深对Android系统启动过程有一个更加深入的了解!再次强调,本文的大多数功劳应归功于那些原创者们,同时一些必要的参考链 ...
- Android系统启动过程[典☆☆☆]
Android系统启动过程 首先Android框架架构图:(来自网上,我觉得这张图看起来很清晰) Linux内核启动之后就到Android Init进程,进而启动Android相关的服务和应用. 启动 ...
- Android系统启动过程【转】
转自:http://www.cnblogs.com/bastard/archive/2012/08/28/2660389.html Android系统启动过程 首先Android框架架构图:(来自网上 ...
- Android异步载入全解析之使用多线程
异步载入之使用多线程 初次尝试 异步.异步,事实上说白了就是多任务处理.也就是多线程执行.多线程那就会有各种问题,我们一步步来看.首先.我们创建一个class--ImageLoaderWithoutC ...
- Android异步载入全解析之IntentService
Android异步载入全解析之IntentService 搞什么IntentService 前面我们说了那么多,异步处理都使用钦定的AsyncTask.再不济也使用的Thread,那么这个Intent ...
- Android 系统启动过程简单记录
本文记录Android系统启动过程,包含从linux kernerl到luancher启动完成的过程: 1.linux内核完成系统设置后,会在系统文件中寻找‘init’文件,然后启动root进程或者说 ...
- Android 深入浅出 - Android系统启动过程
Activity的类继承关系及跟踪Activity的启动 Android系统启动过程 https://study.163.com/course/courseLearn.htm?courseId=213 ...
- Android异步载入全解析之大图处理
Android异步载入全解析之大图处理 异步载入中很重要的一部分就是对图像的处理,这也是我们前面用异步载入图像做示例的原因. 一方面是由于图像处理不好的话会很占内存,并且easyOOM,还有一方面,图 ...
- Android异步载入全解析之使用AsyncTask
Android异步载入全解析之使用AsyncTask 概述 既然前面提到了多线程,就不得不提到线程池,通过线程池,不仅能够对并发线程进行管理.更能够提高他们运行的效率.优化整个App.当然我们能够自己 ...
随机推荐
- InnoDB一定会在索引中加上主键吗
InnoDB一定会在索引中加上主键吗 http://www.penglixun.com/tech/database/will_innodb_store_pk_in_index.html
- TeamViewer
TeamViewer远程连接非常好用
- Java SE 6 新特性: Java DB 和 JDBC 4.0
http://www.ibm.com/developerworks/cn/java/j-lo-jse65/index.html 长久以来,由于大量(甚至几乎所有)的 Java 应用都依赖于数据库,如何 ...
- Jedis的Sharded源代码分析
概述 Jedis是Redis官方推荐的Java客户端,更多Redis的客户端可以参考Redis官网客户端列表.当业务的数据量非常庞大时,需要考虑将数据存储到多个缓存节点上,如何定位数据应该存储的节点, ...
- TabWidget/TabHost的两种使用方法
1.概念 盛放Tab的容器就是TabHost.TabHost的实现有两种方式: 第一种继承TabActivity,从TabActivity中用getTabHost()方法获取TabHost.各个Tab ...
- 【剑指offer 面试题13】在 O(1) 时间删除链表结点
#include <iostream> using namespace std; //构造链表结点 struct ListNode { int val; ListNode *next; L ...
- sql联接那点儿事儿
1.交叉联接(cross join) select * from t.toy ,b.boy from toy as t cross join boy as b 其效果同select * from t. ...
- 《锋利的Jquery第二版》读书笔记 第一章
按照书本介绍顺序整理jquery库相关的语法.要点. window.onload与$(document).ready()功能类似,前者需要所有资源加载完毕,且不能同时编写多个:后者加载完DOM结构即执 ...
- [HIve - LanguageManual] Transform [没懂]
Transform/Map-Reduce Syntax SQL Standard Based Authorization Disallows TRANSFORM TRANSFORM Examples ...
- 内核源码分析之软中断(基于3.16-rc4)
1.和软中断相关的数据结构: softing_vec数组(kernel/softirq.c) static struct softirq_action softirq_vec[NR_SOFTIRQS] ...