在前一篇文章"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程序。源码如下:

 static int __init kernel_init(void * unused)
{ ... // “设置第一个运行程序是/init”
if (!ramdisk_execute_command)
ramdisk_execute_command = "/init"; ... init_post();
return ;
} static noinline int init_post(void)
__releases(kernel_lock)
{ ...
// 运行"/init"程序
if (ramdisk_execute_command) {
run_init_process(ramdisk_execute_command);
printk(KERN_WARNING "Failed to execute %s\n",
ramdisk_execute_command);
} ... run_init_process("/sbin/init");
run_init_process("/etc/init");
run_init_process("/bin/init");
run_init_process("/bin/sh"); ...
}

从中,我们发现: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。内容如下:

 LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
builtins.c \
init.c \
devices.c \
property_service.c \
util.c \
parser.c \
logo.c \
keychords.c \
signal_handler.c \
init_parser.c \
ueventd.c \
ueventd_parser.c \
watchdogd.c LOCAL_MODULE:= init include $(BUILD_EXECUTABLE) ...

说明: 在“完整的编译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中,源码如下:

 int main(int argc, char **argv)
{ ... // 创建目录
mkdir("/dev", );
mkdir("/proc", );
mkdir("/sys", ); mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", );
mkdir("/dev/socket", );
mount("devpts", "/dev/pts", "devpts", , NULL);
mount("proc", "/proc", "proc", , NULL);
mount("sysfs", "/sys", "sysfs", , NULL); ... init_parse_config_file("/init.rc"); ...
}

说明:在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。它的内容如下:

 LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS) LOCAL_SRC_FILES:= \
app_main.cpp LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libandroid_runtime LOCAL_MODULE:= app_process include $(BUILD_EXECUTABLE)

从中,我们知道/system/bin/app_process会执行app_main.cpp。

4.2 zygote对应的程序app_main.app

app_main.cpp的入口main()源码如下:

 int main(int argc, const char* const argv[])
{
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv; mArgLen = ;
for (int i=; i<argc; i++) {
mArgLen += strlen(argv[i]) + ;
}
mArgLen--; AppRuntime runtime;
const char* argv0 = argv[]; // Process command line arguments
// ignore argv[0]
argc--;
argv++; // Everything up to '--' or first non '-' arg goes to the vm int i = runtime.addVmArguments(argc, argv); // Parse runtime arguments. Stop at first unrecognized option.
bool zygote = false;
bool startSystemServer = false;
bool application = false;
const char* parentDir = NULL;
const char* niceName = NULL;
const char* className = NULL;
// 解析参数
while (i < argc) {
const char* arg = argv[i++];
if (!parentDir) {
parentDir = arg;
} else if (strcmp(arg, "--zygote") == ) {
// 设置zygote为true
zygote = true;
niceName = "zygote";
} else if (strcmp(arg, "--start-system-server") == ) {
// 设置startSystemServer为true
startSystemServer = true;
} else if (strcmp(arg, "--application") == ) {
application = true;
} else if (strncmp(arg, "--nice-name=", ) == ) {
niceName = arg + ;
} else {
className = arg;
break;
}
} if (niceName && *niceName) {
setArgv0(argv0, niceName);
set_process_name(niceName);
} runtime.mParentDir = parentDir; if (zygote) {
// 启动"com.android.internal.os.ZygoteInit"
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer ? "start-system-server" : "");
} else if (className) {
// Remainder of args get passed to startup class main()
runtime.mClassName = className;
runtime.mArgC = argc - i;
runtime.mArgV = argv + i;
runtime.start("com.android.internal.os.RuntimeInit",
application ? "application" : "tool");
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return ;
}
}

从中,我们可以知道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()的源码如下:

 void AndroidRuntime::start(const char* className, const char* options)
{
ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
className != NULL ? className : "(unknown)"); blockSigpipe(); /*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
if (strcmp(options, "start-system-server") == ) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = ;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
} const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, );
} //const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack); /* start the virtual machine */
JNIEnv* env;
if (startVm(&mJavaVM, &env) != ) {
return;
}
onVmCreated(env); /*
* Register android functions.
*/
if (startReg(env) < ) {
ALOGE("Unable to register all android natives\n");
return;
} /*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
jstring optionsStr; stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, , classNameStr);
optionsStr = env->NewStringUTF(options);
env->SetObjectArrayElement(strArray, , optionsStr); /*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
// 将"com.android.internal.os.ZygoteInit"转换为"com/android/internal/os/ZygoteInit"
char* slashClassName = toSlashClassName(className);
// 获取"com/android/internal/os/ZygoteInit"对应的class对象
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
// 找到"com/android/internal/os/ZygoteInit"中main()方法的methodID
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
// 执行"com/android/internal/os/ZygoteInit"中main()方法
env->CallStaticVoidMethod(startClass, startMeth, strArray); #if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName); ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != )
ALOGW("Warning: VM did not shut down cleanly\n");
}

说明:start()是通过JNI回调java层的方法,它主要的目的是执行"com/android/internal/os/ZygoteInit"中main()方法,即frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中的main()函数。

5. ZygoteInit.java

frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中的main()源码如下:

 public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start(); registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis()); // Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup
gc(); // If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
} if (argv[1].equals("start-system-server")) {
// 调用startSystemServer()
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
} Log.i(TAG, "Accepting command socket connections"); if (ZYGOTE_FORK_MODE) {
runForkMode();
} else {
runSelectLoopMode();
} closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}

说明:main()会执行startSystemServer()来启动系统服务。

startSystemServer()也是定义在ZygoteInit.java中,源码如下:

 private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null; int pid; try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs); /* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
} /* For child process */
if (pid == 0) {
handleSystemServerProcess(parsedArgs);
} return true;
}

说明
     startSystemServer()会通过Zygote.forkSystemServer()函数来创建一个新的进程来启动SystemServer组件,返回值pid等0的地方就是新的进程要执行的路径,即新创建的进程会执行handleSystemServerProcess()函数。

handleSystemServerProcess()也是定义在ZygoteInit.java中,源码如下:

 private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller { closeServerSocket(); // set umask to 0077 so new files and directories will default to owner-only permissions.
Libcore.os.umask(S_IRWXG | S_IRWXO); if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
} if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
null, parsedArgs.remainingArgs);
} else {
/*
* Pass the remaining arguments to SystemServer.
*/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs);
} /* should never reach here */
}

说明:handleSystemServerProcess()会调用 RuntimeInit.zygoteInit()器初始化zygote。

6. RuntimeInit.java

zygoteInit()定义在frameworks/base/core/java/com/android/internal/os/RuntimeInit.java中,源码如下:

 public static final void zygoteInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote"); redirectLogStreams(); commonInit();
nativeZygoteInit(); // 通过applicationInit()启动SystemServer
applicationInit(targetSdkVersion, argv);
}

说明:zygoteInit()会调用applicationInit()函数初始化应用程序SystemServer。

applicationInit()也定义在RuntimeInit.java中,源码如下:

 private static void applicationInit(int targetSdkVersion, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
nativeSetExitWithoutCleanup(true); VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion); final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
} // invokeStaticMain()会执行SystemServer的main()方法。
invokeStaticMain(args.startClass, args.startArgs);
}

说明:applicationInit()会调用invokeStaticMain()来执行SystemServer的main()方法。

invokeStaticMain()也定义在RuntimeInit.java中,源码如下:

 private static void invokeStaticMain(String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl; try {
// 根据“反射”查找SystemServer对应的Class
cl = Class.forName(className);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
} Method m;
try {
// 获取SystemServer对应的main()方法
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
} int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
} // 通过ZygoteInit.MethodAndArgsCaller()执行该main()方法
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}

说明
    首先,我们要搞清楚invokeStaticMain()的输入参数className,实际上它的值是"com.android.server.SystemServer"。
              我们看从startSystemServer()方法中的args成员开始查看,在args通过ZygoteConnection.Arguments(args)解析之后得到parsedArgs对象;其中,parsedArgs.remainingArgs就是"com.android.server.SystemServer"。。
    接着,parseArgs传递给handleSystemServerProcess();
   再接着,将parsedArgs.remainingArgs,也就是"com.android.server.SystemServer"传递给了RuntimeInit.zygoteInit()。

7. ZygoteInit.MethodAndArgsCaller

MethodAndArgsCaller是一个实现了Runnable的类,它定义在frameworks/base/core/java/com/android/internal/os/ZygoteInit.java中。源码如下:

 public static class MethodAndArgsCaller extends Exception
implements Runnable {
private final Method mMethod; private final String[] mArgs; public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
} public void run() {
try {
// 通过反射,执行方法mMethod
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}

说明:MethodAndArgsCaller()是个线程,它会执行方法mMethod。也就是执行"com.android.server.SystemServer"中的main()方法。
至此,我们就启动了SystemServer了!

Android之 系统启动流程的更多相关文章

  1. 【Android 系统开发】 Android 系统启动流程简介

    作者 : 万境绝尘 (octopus_truth@163.com) 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/3889548 ...

  2. Android系统启动流程(一)解析init进程启动过程

    整体流程大致如下:     1.init简介 init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等.in ...

  3. Android系统启动流程(四)Launcher启动过程与系统启动流程

    此前的文章我们学习了init进程.Zygote进程和SyetemServer进程的启动过程,这一篇文章我们就来学习Android系统启动流程的最后一步:Launcher的启动流程,并结合本系列的前三篇 ...

  4. 【乘风破浪】Android系统启动流程整理

    前言 对于一个Android应用层开发者来说,了解Android系统的启动流程对理解Android系统有很大的帮助.这其中包含了大量的细节,而且前面很多步骤包含了C/C++实现的native层逻辑,作 ...

  5. 【转】android 电池(二):android关机充电流程、充电画面显示

    关键词:android 电池关机充电 androidboot.mode charger关机充电 充电画面显示 平台信息:内核:linux2.6/linux3.0系统:android/android4. ...

  6. Android的开机流程

    Android的开机流程 1. 系统引导bootloader 1) 源码:bootable/bootloader/* 2) 说明:加电后,CPU将先执行bootloader程序,此处有三种选择 a) ...

  7. android 电池(二):android关机充电流程、充电画面显示【转】

    本文转载自:http://blog.csdn.net/xubin341719/article/details/8498580 上一篇我们讲了锂电池的充放电的流程和电池的一些特性,这一节我们重点说一下a ...

  8. android开机启动流程说明

    android开机启动流程说明 第一步:启动linux 1.Bootloader 2.Kernel 第二步android系统启动:入口为init.rc(system\core\rootdir) 1./ ...

  9. Linux操作系统启动流程梳理

    接触linux系统运维已经好几年了,常常被问到linux系统启动流程问题,刚好今天有空来梳理下这个过程:一般来说,所有的操作系统的启动流程基本就是: 总的来说,linux系统启动流程可以简单总结为以下 ...

随机推荐

  1. jquery-事件之页面框架加载后自动执行

    jQuery事件之页面框架加载后自动执行 1)概述 HTML执行是按自上而下编译,而<script>一般写在body结束之前.如果在HTML加载的过程中卡住, 比如加载图片等,没有显示出来 ...

  2. vue之给a标签赋值

    <li v-for="(bp,index) in bpLists"> <a class="bidPublicityTitle" :href=& ...

  3. laravel5.3之后可以使用withCount()这个方法

    比如:文章控制器ArticleController.php查询文章列表数据的时候用withCount连接Comment,Zan模型直接统计每篇文章的评论和点赞数量. 使用之前需要在文章模型文件Arti ...

  4. 算法之DP

    一般DP 都是有模板的,先初始化,然后找到不同状态下数值的关系,使得某个状态可用另一个状态由一个固定的方式转移而来,列出状态转移方程,这就是DP: 例题 P1216 [USACO1.5]数字三角形 N ...

  5. js时间格式化函数(兼容IOS)

    * 时间格式化 * @param {Object} dateObj 时间对象 * @param {String} fmt 格式化字符串 */ dateFormat(dateObj, fmt) { le ...

  6. SQL Server 4

    一.视图 1.创建视图 1)选中数据库中的表中的视图处,右键选择新建视图,即: 2)在弹出“添加表”对话框中,单击“表”标签,选择要添加的表,点击添加,即: 3)选中要建立联系的列名的复选框,然后拖动 ...

  7. 【LOJ】#2278. 「HAOI2017」字符串

    题解 好神仙的题啊 感觉转二维平面能想到,算重复情况的方法真想不到啊 通过扒stdcall代码获得的题解QAQQQQ 我们先把\(p_i\)正串反串建出一个AC自动机来 然后我们把s串放在上面跑匹配, ...

  8. 【LOJ】#2082. 「JSOI2016」炸弹攻击 2

    题解 想到n3发现思路有点卡住了 对于每个发射塔把激光塔和敌人按照极角排序,对于一个激光塔,和它转角不超过pi的激光塔中间夹的敌人总和就是答案 记录前缀和,用two-Points扫一下就行 代码 #i ...

  9. SpringBoot与SpringCloud学习指南

    推荐一个Spring Boot的导航网站:Spring Boot 中文导航 Spring boot使用的各种示例,以最简单.最实用为标准 spring-boot-helloWorld:spring-b ...

  10. 树状数组解决LIS---O(nlogn)

    树状数组解决LIS---O(nlogn)之前写过二分查找的LIS,现在不怎么记得了,正好用Bit来搞一波.f[i]表示以a[i]结尾的LIS的长度.t[x]表示以数值x结尾的LIS的长度.即t[x]= ...