在前一篇文章"Android之 看“马达”如何贯通Android系统 (从硬件设计 --> 驱动 --> HAL --> JNI --> Framework --> Application)"中,我们谈到“马达等系统服务都是通过SystemServer启动/管理的”。本章,我们就Android的系统启动流程进行分析;也说说SystemServer到底是如何工作的。
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3405100.html
在详细说明之后,我们先建立个整体思路:
Kernel中启动的第一个用户进程是init程序;而init会通过解析init.rc来启动zygote服务;而zygote又会进一步的启动SystemServer。在SystemServer中,Android会启动一系列的系统服务共用户调用。整个流程大致如此。下面,我们通过源码来查看一下各个环节到底是如何运作的。
1. kernel启动init服务
在Linux的内核init/main.c中,启动的/init程序。源码如下:
1 static int __init kernel_init(void * unused) 2 { 3 4 ... 5 6 // “设置第一个运行程序是/init” 7 if (!ramdisk_execute_command) 8 ramdisk_execute_command = "/init"; 9 10 ... 11 12 init_post(); 13 return 0; 14 } 15 16 17 static noinline int init_post(void) 18 __releases(kernel_lock) 19 { 20 21 ... 22 // 运行"/init"程序 23 if (ramdisk_execute_command) { 24 run_init_process(ramdisk_execute_command); 25 printk(KERN_WARNING "Failed to execute %s\n", 26 ramdisk_execute_command); 27 } 28 29 ... 30 31 run_init_process("/sbin/init"); 32 run_init_process("/etc/init"); 33 run_init_process("/bin/init"); 34 run_init_process("/bin/sh"); 35 36 ... 37 }
从中,我们发现:kernel_init()中会将ramdisk_execute_command的值初始化为"/init",进而在init_post()中调用run_init_process(),从而执行"/init"程序。
我们所说的kernel内核空间到用户空间启动的第一个init程序,实际上就是"/init"程序。
2. init服务的定义
2.1 init的配置文件
Android系统中init程序对应的Android.mk所在路径:system/core/init/Android.mk。内容如下:
1 LOCAL_PATH:= $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_SRC_FILES:= \ 5 builtins.c \ 6 init.c \ 7 devices.c \ 8 property_service.c \ 9 util.c \ 10 parser.c \ 11 logo.c \ 12 keychords.c \ 13 signal_handler.c \ 14 init_parser.c \ 15 ueventd.c \ 16 ueventd_parser.c \ 17 watchdogd.c 18 19 LOCAL_MODULE:= init 20 21 include $(BUILD_EXECUTABLE) 22 23 ...
说明: 在“完整的编译Android系统” 或 “对init执行模块编译(即$ mmm system/core/init)”的时候,会在system下生产文件out/.../root/init。"/root/init"意味着init在rootfs文件系统下,而不是system文件系统下。这也意味着,init会被解压到系统的根目录,即对应/init文件!
2.2 init的程序入口
init程序的入口函数main()定义在system/core/init/init.c中,源码如下:
1 int main(int argc, char **argv) 2 { 3 4 ... 5 6 // 创建目录 7 mkdir("/dev", 0755); 8 mkdir("/proc", 0755); 9 mkdir("/sys", 0755); 10 11 mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); 12 mkdir("/dev/pts", 0755); 13 mkdir("/dev/socket", 0755); 14 mount("devpts", "/dev/pts", "devpts", 0, NULL); 15 mount("proc", "/proc", "proc", 0, NULL); 16 mount("sysfs", "/sys", "sysfs", 0, NULL); 17 18 ... 19 20 init_parse_config_file("/init.rc"); 21 22 ... 23 }
说明:在init程序中,我们会进行一些列的初始化,包括创建目录,解析"init.rc"文件,启动相应的系统服务和守护进程等。zygote服务定义在init.rc中,它是在init中启动的。
3. init启动解析init.rc,并启动zygote
init.rc的路径:system/core/rootdir/init.rc。zygote在init.rc中的定义如下:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
从中,我们知道:zygote是service名称,而/system/bin/app_process是zygote对应的进程。后面的内容是service的参数。
4. zygote服务
4.1 zygote服务的配置文件
通过init.rc中zygote的定义,我们知道zygote对应是通过/system/bin/app_process是启动的。app_process对应的Android.mk的路径:frameworks/base/cmds/app_process/Android.mk。它的内容如下:
1 LOCAL_PATH:= $(call my-dir) 2 include $(CLEAR_VARS) 3 4 LOCAL_SRC_FILES:= \ 5 app_main.cpp 6 7 LOCAL_SHARED_LIBRARIES := \ 8 libcutils \ 9 libutils \ 10 libbinder \ 11 libandroid_runtime 12 13 LOCAL_MODULE:= app_process 14 15 include $(BUILD_EXECUTABLE)
从中,我们知道/system/bin/app_process会执行app_main.cpp。
4.2 zygote对应的程序app_main.app
app_main.cpp的入口main()源码如下:
1 int main(int argc, const char* const argv[]) 2 { 3 // These are global variables in ProcessState.cpp 4 mArgC = argc; 5 mArgV = argv; 6 7 mArgLen = 0; 8 for (int i=0; i<argc; i++) { 9 mArgLen += strlen(argv[i]) + 1; 10 } 11 mArgLen--; 12 13 AppRuntime runtime; 14 const char* argv0 = argv[0]; 15 16 // Process command line arguments 17 // ignore argv[0] 18 argc--; 19 argv++; 20 21 // Everything up to '--' or first non '-' arg goes to the vm 22 23 int i = runtime.addVmArguments(argc, argv); 24 25 // Parse runtime arguments. Stop at first unrecognized option. 26 bool zygote = false; 27 bool startSystemServer = false; 28 bool application = false; 29 const char* parentDir = NULL; 30 const char* niceName = NULL; 31 const char* className = NULL; 32 // 解析参数 33 while (i < argc) { 34 const char* arg = argv[i++]; 35 if (!parentDir) { 36 parentDir = arg; 37 } else if (strcmp(arg, "--zygote") == 0) { 38 // 设置zygote为true 39 zygote = true; 40 niceName = "zygote"; 41 } else if (strcmp(arg, "--start-system-server") == 0) { 42 // 设置startSystemServer为true 43 startSystemServer = true; 44 } else if (strcmp(arg, "--application") == 0) { 45 application = true; 46 } else if (strncmp(arg, "--nice-name=", 12) == 0) { 47 niceName = arg + 12; 48 } else { 49 className = arg; 50 break; 51 } 52 } 53 54 if (niceName && *niceName) { 55 setArgv0(argv0, niceName); 56 set_process_name(niceName); 57 } 58 59 runtime.mParentDir = parentDir; 60 61 if (zygote) { 62 // 启动"com.android.internal.os.ZygoteInit" 63 runtime.start("com.android.internal.os.ZygoteInit", 64 startSystemServer ? "start-system-server" : ""); 65 } else if (className) { 66 // Remainder of args get passed to startup class main() 67 runtime.mClassName = className; 68 runtime.mArgC = argc - i; 69 runtime.mArgV = argv + i; 70 runtime.start("com.android.internal.os.RuntimeInit", 71 application ? "application" : "tool"); 72 } else { 73 fprintf(stderr, "Error: no class name or --zygote supplied.\n"); 74 app_usage(); 75 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied."); 76 return 10; 77 } 78 }
从中,我们可以知道main()最终会调用以下代码:
runtime.start("com.android.internal.os.ZygoteInit", startSystemServer ? "start-system-server" : "");
我们接着看start()的代码。start()的源码定义在frameworks/base/core/jni/AndroidRuntime.cpp中。
runtime是AppRuntime成员。AppRuntime定义在app_main.cpp中,声明如下:
class AppRuntime : public AndroidRuntime { ... }
显然AppRuntime继承于AndroidRuntime。
4. AndroidRuntime.cpp
start()的源码如下:
1 void AndroidRuntime::start(const char* className, const char* options) 2 { 3 ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n", 4 className != NULL ? className : "(unknown)"); 5 6 blockSigpipe(); 7 8 /* 9 * 'startSystemServer == true' means runtime is obsolete and not run from 10 * init.rc anymore, so we print out the boot start event here. 11 */ 12 if (strcmp(options, "start-system-server") == 0) { 13 /* track our progress through the boot sequence */ 14 const int LOG_BOOT_PROGRESS_START = 3000; 15 LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, 16 ns2ms(systemTime(SYSTEM_TIME_MONOTONIC))); 17 } 18 19 const char* rootDir = getenv("ANDROID_ROOT"); 20 if (rootDir == NULL) { 21 rootDir = "/system"; 22 if (!hasDir("/system")) { 23 LOG_FATAL("No root directory specified, and /android does not exist."); 24 return; 25 } 26 setenv("ANDROID_ROOT", rootDir, 1); 27 } 28 29 //const char* kernelHack = getenv("LD_ASSUME_KERNEL"); 30 //ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); 31 32 /* start the virtual machine */ 33 JNIEnv* env; 34 if (startVm(&mJavaVM, &env) != 0) { 35 return; 36 } 37 onVmCreated(env); 38 39 /* 40 * Register android functions. 41 */ 42 if (startReg(env) < 0) { 43 ALOGE("Unable to register all android natives\n"); 44 return; 45 } 46 47 /* 48 * We want to call main() with a String array with arguments in it. 49 * At present we have two arguments, the class name and an option string. 50 * Create an array to hold them. 51 */ 52 jclass stringClass; 53 jobjectArray strArray; 54 jstring classNameStr; 55 jstring optionsStr; 56 57 stringClass = env->FindClass("java/lang/String"); 58 assert(stringClass != NULL); 59 strArray = env->NewObjectArray(2, stringClass, NULL); 60 assert(strArray != NULL); 61 classNameStr = env->NewStringUTF(className); 62 assert(classNameStr != NULL); 63 env->SetObjectArrayElement(strArray, 0, classNameStr); 64 optionsStr = env->NewStringUTF(options); 65 env->SetObjectArrayElement(strArray, 1, optionsStr); 66 67 /* 68 * Start VM. This thread becomes the main thread of the VM, and will 69 * not return until the VM exits. 70 */ 71 // 将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit" 72 char* slashClassName = toSlashClassName(className); 73 // 获取"com/android/internal/os/ZygoteInit"对应的class对象 74 jclass startClass = env->FindClass(slashClassName); 75 if (startClass == NULL) { 76 ALOGE("JavaVM unable to locate class '%s'\n", slashClassName); 77 /* keep going */ 78 } else { 79 // 找到"com/android/internal/os/ZygoteInit"中main()方法的methodID 80 jmethodID startMeth = env->GetStaticMethodID(startClass, "main", 81 "([Ljava/lang/String;)V"); 82 if (startMeth == NULL) { 83 ALOGE("JavaVM unable to find main() in '%s'\n", className); 84 /* keep going */ 85 } else { 86 // 执行"com/android/internal/os/ZygoteInit"中main()方法 87 env->CallStaticVoidMethod(startClass, startMeth, strArray); 88 89 #if 0 90 if (env->ExceptionCheck()) 91 threadExitUncaughtException(env); 92 #endif 93 } 94 } 95 free(slashClassName); 96 97 ALOGD("Shutting down VM\n"); 98 if (mJavaVM->DetachCurrentThread() != JNI_OK) 99 ALOGW("Warning: unable to detach main thread\n"); 100 if (mJavaVM->DestroyJavaVM() != 0) 101 ALOGW("Warning: VM did not shut down cleanly\n"); 102 }