前面讲了一个android重启问题,对android的启动流程比较感兴趣,特意梳理一下android的启动流程。
回顾
梳理启动流程之前,我们回忆一下android启动流程的大概。
一、bootloader
1、什么是bootloader?
BootLoader是在操作系统内核运行之前运行。可以初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境带到一个合适状态,以便为最终调用操作系统内核准备好正确的环境。
2、这个阶段会做什么?
(1)硬件初始化:关闭看门狗,屏蔽中断,初始化内存,设置栈,设置时钟,从flash引导内核到内存等
(2)通过bootargs向内核传递配置信息。如波特率
通常我司的还会做一些定制的内容,如初始化功放、点屏、显示开机logo等等。
二、kernel
1、内核引导阶段
通常使用汇编语言编写,主要检查内核与当前硬件是否匹配。这部分也与硬件体系结构相关。代码主要位于 kernel /arch/arm/kernel/head.S
bl switch_to_vhe
add sp, sp, #16
mov x29, #0
mov x30, #0
b start_kernel
2、内核启动阶段
引导阶段结束前,将调用start_kernel()进入内核启动阶段。内核启动阶段相关的代码主要位于android/kernel-5.10/init/main.c
启动init进程,再通过init进程,来读取init.rc中的相关配置,从而来启动其他相关进程以及其他操作。
asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
{
....
trap_init();//初始化内核中断和异常处理机制
mm_init();//初始化内存
.....
thread_stack_cache_init();
cred_init();
fork_init();
proc_caches_init();
uts_ns_init();
buffer_init();
key_init();
security_init();
dbg_late_init();
vfs_caches_init();
pagecache_init();
signals_init();
seq_file_init();
proc_root_init();
nsfs_init();
cpuset_init();
cgroup_init();
taskstats_init_early();
delayacct_init();
poking_init();
check_bugs();
acpi_subsystem_init();
arch_post_acpi_subsys_init();
sfi_init_late();
kcsan_init();
/* Do the rest non-__init'ed, we're now alive */
arch_call_rest_init();//启动init
prevent_tail_call_optimization();
}
三、init阶段:
static int __ref kernel_init(void *unused)
{
...
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
!try_to_run_init_process("/bin/init") ||
!try_to_run_init_process("/bin/sh"))
return 0;
panic("No working init found. Try passing init= option to kernel. "
"See Linux Documentation/admin-guide/init.rst for guidance.");
}
如何知道执行的那个init文件呢?
kernel_init启动后,完成一些init的初始化操作,然后去系统根目录下依次找ramdisk_execute_command和execute_command设置的应用程序,如果这两个目录都找不到,就依次去根目录下找/sbin/init,/etc/init,/bin/init,/bin/sh这四个应用程序进行启动,只要这些应用程序有一个启动了,其他就不启动了。
int main(int argc, char** argv) {
......
if (argc > 1) {
if (!strcmp(argv[1], "subcontext")) {
android::base::InitLogging(argv, &android::base::KernelLogger);
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
return SubcontextMain(argc, argv, &function_map);
}
if (!strcmp(argv[1], "selinux_setup")) {
return SetupSelinux(argv);
}
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
return FirstStageMain(argc, argv);
}
1、第一阶段:
int FirstStageMain(int argc, char** argv) {
............
//创建文件系统目录并挂在相关文件系统
// Get the basic filesystem setup we need put together in the initramdisk
// on / and then we'll let the rc file figure out the rest.
CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"));
CHECKCALL(mkdir("/dev/pts", 0755));
CHECKCALL(mkdir("/dev/socket", 0755));
CHECKCALL(mkdir("/dev/dm-user", 0755));
CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL));
......
//初始化日志输出系统
InitKernelLogging(argv);
.....
//执行命令/system/bin/init,回到main函数,初始化selinux和加载selinux规则
const char* path = "/system/bin/init";
const char* args[] = {path, "selinux_setup", nullptr};
auto fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
close(fd);
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
// panic and never fall through this conditional.
PLOG(FATAL) << "execv(\"" << path << "\") failed";
return 1;
}
int SetupSelinux(char** argv) {
......
//加载权限策略
LoadSelinuxPolicy(policy);
.....
SelinuxSetEnforcement();
....
//准备进入第二阶段
const char* path = "/system/bin/init";
const char* args[] = {path, "second_stage", nullptr};
execv(path, const_cast<char**>(args));
// execv() only returns if an error happened, in which case we
// panic and never return from this function.
PLOG(FATAL) << "execv(\"" << path << "\") failed";
return 1;
}
第二阶段
int SecondStageMain(int argc, char** argv) {
....
//初始化属性系统
PropertyInit();
//进行selinux第二阶段并恢复一些文件安全上下文
SelabelInitialize();
SelinuxRestoreContext();
//开启属性服务
StartPropertyService(&property_fd);
........
//匹配命令和函数之间的关系(ls、chmod.....)
const BuiltinFunctionMap& function_map = GetBuiltinFunctionMap();
Action::set_function_map(&function_map);
......
ActionManager& am = ActionManager::GetInstance();
ServiceList& sm = ServiceList::GetInstance();
//加载解析脚本
LoadBootScripts(am, sm);
....
//按照early-init --> init -->late-init的顺序把相关action加入触发器队列,然后在循环中,执行所有触发器队列中Action带command的执行函数
am.QueueEventTrigger("early-init");
....
// Restore prio before main loop
setpriority(PRIO_PROCESS, 0, 0);
while (true) {
....
//1、遍历并启动每个系统服务。
//2、监测并处理子进程状态,如果是系统服务,重新拉起
....
}
return 0;
}
3、第三阶段:
第三阶段主要是解析rc文件,启动服务。Zygote就在此启动。我们需要先简单了解一下rc文件的语法;
总结一下:init阶段
四、Zygote阶段:
Init进程启动后,最重要的一个进程就是Zygote进程,Zygote是所有应用的鼻祖。SystemServer和其它所有虚拟机进程都是由Zygote fork而来 。Zygote进程由app_process启动,Zygote是一个C/S模型,Zygote进程作为服务端,其他进程作为客户端向它发出“孵化-fork”请求,而Zygote接收到这个请求后就“孵化-fork”出一个新的进程。
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
priority -20
user root
group root readproc reserved_disk
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
onrestart exec_background - system system -- /system/bin/vdc volume abort_fuse
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart media.tuner
onrestart restart netd
onrestart restart wificond
onrestart restart vendor.tv-input-1-0
task_profiles ProcessCapacityHigh
critical window=${zygote.critical_window.minute:-off} target=zygote-fatal
第一个zygote进程通过应用程序/system/bin/app_process来启动它
参数1:-Xzygote 该参数将作为虚拟机启动时所需的参数
参数2:/system/bin 代表虚拟机程序所在目录
参数3:–zygote 指明以ZygoteInit.java类中的main函数作为虚拟机执行入口
int main(int argc, char* const argv[])
{
.....
//根据参数启动zygote、start-system-server
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}
.....
if (startSystemServer) {
args.add(String8("start-system-server"));
}
.....
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.");
}
}
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
.........
//启动虚拟机
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote, primary_zygote) != 0) {
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
//注册jni
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
....
//通过JNI方式调用ZygoteInit.main(),正在进入java世界
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
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 {
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
public static void main(String[] argv) {
Runnable caller;
try {
.......
//预加载资源,加快启动速度
preload(bootTimingsTraceLog);
....
//建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
zygoteServer = new ZygoteServer(isPrimaryZygote);
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
// {@code r == null} in the parent (zygote) process, and {@code r != null} in the
// child (system_server) process.
if (r != null) {
r.run();
return;
}
}
Log.i(TAG, "Accepting command socket connections");
// The select loop returns early in the child process after a fork and
// loops forever in the zygote.
//zygote任务完成,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。
caller = zygoteServer.runSelectLoop(abiList);
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with fatal exception", ex);
throw ex;
} finally {
if (zygoteServer != null) {
zygoteServer.closeServerSocket();
}
}
// We're in the child process and have exited the select loop. Proceed to execute the
// command.
if (caller != null) {
caller.run();
}
}
zygote总结:
1)zygote进程的入口app_main.cpp;
2)调用AndroidRuntime的startVM()方法创建虚拟机,再调用startReg()注册JNI函数;
3)通过JNI方式调用ZygoteInit.main(),第一次进入Java世界;
4)registerZygoteSocket()建立socket通道,zygote作为通信的服务端,用于响应客户端请求;
5)preload()预加载通用类、drawable和color资源等,用于提高app启动效率;
6)通过startSystemServer来fork system_server进程,也是上层framework的运行载体。
7)zygote任务完成,调用runSelectLoop(),随时待命,当接收到请求创建新进程请求时立即唤醒并执行相应工作。
8)启动SystemServer进程。