概述
Android系统
是基于Linux的,启动必须经历3个阶段,即:Boot Loader
,Linux Kernel
,Android系统服务
,笔者今天就基于Android 8.1 系统源代码来分析一下启动过程
。
大家本地如果没有源代码的可以在线查看:
https://www.androidos.net.cn/sourcecode
启动流程图
下面是笔者根据一些博客以及系统源代码对比整理出来的一张流程图,由于整个过程涉及到的模块很多,目前只是整理了大致的模块流程,具体的细节后续会逐步整理说明。
本文设计到的几个关键类
及路径
关键类 | 路径 |
---|---|
init.rc | system/core/rootdir/init.rc |
init.cpp | system/core/init/init.cpp |
init.zygote64.rc | system/core/rootdir/init.zygote64.rc |
app_main.cpp | frameworks/base/cmds/app_process/app_main.cpp |
AndroidRuntime.cpp | frameworks/base/core/jni/AndroidRuntime.cpp |
ZygoteInit.java | frameworks/base/core/java/com/android/internal/os/ZygoteInit.java |
ZygoteServer.java | frameworks/base/core/java/com/android/internal/os/ZygoteServer.java |
Android系统启动必经的三个步骤:
1. 按下电源系统启动
当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行,加载引导程序
Bootloader
到RAM
,然后执行。
2. 引导程序Bootloader
引导程序是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。
3. linux内核启动
内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找
"init"
文件,然后启动root进程
或者系统的第一个进程
。
第一个进程:init进程
作为Android系统
中第一个被启动的进程,init进程的PID为0
,它会通过解析init.rc脚本
来构建系统的初始形态。
一个完整的init.rc脚本
通常由4种类型的声明组成,即:
Action(动作):
on ##触发条件
##执行命令
##执行多个命令
...
一个Action
实际是响应某一个事件的过程,即当
所描述的触发事件产生时,依次执行各种command(可以执行多个对应的命令)
。
Commands(命令):
命令会将所属事件被一个一个执行
Services(服务):
service [ ]*
表示service
的名称
表示可执行文件的路径
启动service
所带的参数
对此
service
的约束选项
Options(选项)
约束选项
Android中的DNS服务器
——ServiceManager
ServiceManager
可以理解为Binder机制中
的DNS服务器
,负责某Binder服务在ServiceManager注册时提供的名称
到底层Binder驱动分配的值
的解析。
servicemanager
是在system/core/rootdir/init.rc
描述并由init进程
启动的。
on post-fs
......
load_system_props
# start essential services
start logd
//启动servicemanager
start servicemanager
start hwservicemanager
start vndservicemanager
这是frameworks/native/cmds/servicemanager.rc
描述脚本
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart audioserver
onrestart restart media
onrestart restart surfaceflinger
onrestart restart inputflinger
onrestart restart drm
onrestart restart cameraserver
writepid /dev/cpuset/system-background/tasks
shutdown critical
Zygote进程
在Android中,Zygote
是整个系统创建新进程的核心进程。和ServiceManager类似
,它也是由init进程
解析init.rc脚本
时启动的。
由于系统不断升级,Android系统也不得不面对32位和64位机器同时存在的情况,所以Zygote
的启动也需要根据不同的情况进行区分:
import /init.environ.rc
import /init.usb.rc
import /init.${ro.hardware}.rc
import /vendor/etc/init/hw/init.${ro.hardware}.rc
import /init.usb.configfs.rc
import /init.${ro.zygote}.rc
......
Zygote进程
在内部会先启动虚拟机
,继而加载一些必要的系统资源和系统类
,最后进入一种监听状态。在之后的运作中,当其他系统模块(比如 AMS)
希望创建新进程时,只需向Zygote进程
发出请求,Zygote进程
监听到该请求后,会相应地fork出新的进程
,于是这个新进程在初生之时,就先天具有了自己的虚拟机以及系统资源
。
下面是不同的描述Zygote
的rc脚本
脚本 | 描述 |
---|---|
init.zygote32.rc | zygote进程 对应的执行程序是app_process (纯32位模式) |
init.zygote64.rc | zygote进程 对应的执行程序是app_process64 (纯64位模式) |
init.zygote32_64.rc | 启动两个zygote进程 (名为zygote和zygote_secondary ),对应的执行程序分别是 app_process32 (主模式)、app_process64 |
init.zygote64_32.rc | 启动两个zygote进程 (名为zygote和zygote_secondary ),对应的执行程序分别是 app_process64 (主模式)、app_process32 |
这里以64位机器为例:/system/core/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
writepid /dev/cpuset/foreground/tasks
上述脚本内容我们可以看到,启动的是一个名为Zygote的进程
,对应的程序名为:app_process64
在frameworks/base/cmds/app_process
目录下,我们找到Android.mk文件
:
LOCAL_PATH:= $(call my-dir)
app_process_common_shared_libs := \
libandroid_runtime \
libbinder \
libcutils \
libdl \
libhwbinder \
liblog \
libnativeloader \
libutils \
......
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= $(app_process_src_files)
LOCAL_LDFLAGS_32 := $(app_process_ldflags_32)
LOCAL_LDFLAGS_64 := $(app_process_ldflags_64)
LOCAL_SHARED_LIBRARIES := $(app_process_common_shared_libs)
LOCAL_WHOLE_STATIC_LIBRARIES := $(app_process_common_static_libs)
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
LOCAL_CFLAGS += $(app_process_cflags)
......
include $(BUILD_EXECUTABLE)
上述脚本决定了最终编译出来的目标文件
下面我们来看看frameworks/base/cmds/app_process/app_main.cpp
中main函数
的部分关键代码:
int main(int argc, char* const argv[])
{
.....
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
......
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
}
}
上面的函数用来解析启动app_process
时传入的参数:
--zygote:指明以ZygoteInit.java类中的main函数作为虚拟机执行入口
--start-system-server:告诉Zygote进程启动SystemServer进程
注意上述的AppRuntime本身是继承自AndroidRuntime的
,因此最终实际调用的还是AndroidRuntime中的start函数
虚拟机的启动
在上面的Zygote启动
中也看到了虚拟机的启动
代码了
下面来看看frameworks/base/core/jni/AndroidRuntime.cpp
中main函数
的实现:
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
//初始化JNI环境
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
//启动虚拟机
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
//虚拟机启动后回调
onVmCreated(env);
// 注册JNI函数
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
......
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
......
} else {
//通过反射找到ZygoteInit的main函数
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
......
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName);
......
上面的过程其实就是启动虚拟机
的过程,这里由于篇幅关系,并不大算深究每一个模块,而是先粗看整体的框架结构。虚拟机启动完成之后,会通过反射的形式
调用frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
中的main方法
:
ZygoteServer zygoteServer = new ZygoteServer();
......
try {
......
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
//启动SystemServer
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(ABI_LIST_ARG)) {
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
socketName = argv[i].substring(SOCKET_NAME_ARG.length());
} else {
throw new RuntimeException("Unknown command line argument: " + argv[i]);
}
}
//注册服务端的Socket
zygoteServer.registerServerSocket(socketName);
......
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
//预加载各类资源
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
......
if (startSystemServer) {
//正式启动SystemServer
Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
......
if (r != null) {
r.run();
return;
}
}
......
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
throw ex;
} finally {
zygoteServer.closeServerSocket();
}
因此在ZygoteInit中比较关键的两个操作:
1.注册一个Socket
:如果由新进程需要创建,系统会通过这个Socket
来通知它完成进程孵化工作
。
2.预加载各类资源:
主要用来预加载虚拟机所需要的各类资源。
紧接着就是下面的代码:
runSelectLoop(abiList);
这段代码的内部实现其实就是一个while死循环
,它用来作为Zygote的守护进程
启动SystemServer
前面的ServiceManager
,Zygote
,虚拟机
等启动过程有了一定的了解了,下面就是关键的SystemServer启动
了,之前的脚本也看到了一个叫--start-system-server
的参数,这个就是用来启动SystemServer
的。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
中
private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {
......
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"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);
}
//子进程
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
zygoteServer.closeServerSocket();
//启动各个System Server进程
return handleSystemServerProcess(parsedArgs);
}
return null;
}
在ZygoteInit中
通过forkSystemServer方法
创建了一个新进程,这个新进程(pid==0)
会在随后的过程中通过handleSystemServerProcess
来启动各种支撑系统运行的System Server
小结
在Android系统
中,每个进程都运行在对应的虚拟机上,因此Zygote
首先就负责创建出虚拟机
。
然后,为了反射调用java代码,必须有对应的JNI函数
,于是Zygote
进行了JNI函数的注册
。
当一切准备妥当后,Zygote进程
才进入到了java的世界
。
参考:
《深入理解Android内核设计思想》
https://blog.csdn.net/freekiteyu/article/details/79175010
https://www.cnblogs.com/pepsimaxin/p/9443002.html
https://www.cnblogs.com/pepsimaxin/p/9448874.html
https://www.cnblogs.com/tiantianbyconan/p/5013863.html