安卓手机启动时发生的那些事儿——中篇
序
上篇文章我们谈到安卓手机启动时的前两部分,分别是BIOS和BootLoader阶段、Linux内核启动阶段,这篇文章,我们就来一起学习真正的进入安卓系统的启动流程。
一、概览
首先复习一下上篇所学,在安卓手机上,整个系统的启动可以分为三个过程,如下:
- BIOS和BootLoader阶段
- Linux内核启动
- Android系统启动
第一阶段主要由硬件和汇编语言完成,第二部分主要由C语言完成,第三部分主要由java完成。下面我们一起进入这第三部分的学习。
二、Linux内核启动安卓系统
上篇文章我们学到了运行Linux内核中的start_kernel(),然后start_kernel()函数最后通过调用kernel_thread()寻找init.rc文件,并启动init进程(pid = 1)。这一部分也就进行到了Native层,Linux 中的所有进程都是有init进程创建并运行的。Native层主要包括 init 进程以及其 fork 出来的用户空间的守护进程、 HAL 层、开机动画等。init进程是所有用户进程的鼻祖。其启动的主要内容如下:
- Media Server(多媒体服务)、servicemanager(binder服务管家)、bootanim(开机动画)等重要服务;
- installd(用于App安装)、ueventd、adbd、lmkd(用于内存管理)等用户守护进程;
- Zygote进程,Zygote进程是Android系统的第一个Java进程,Zygote是所有Java进程的父进程,Zygote进程本身是由init进程孵化而来的。
init进程的入口函数主要代码如下:
/*位于安卓源码的system/core/init/init.cpp文件*/
int main(int argc, char** argv) {
if (!strcmp(basename(argv[0]), "ueventd")) {
return ueventd_main(argc, argv);
}
if (!strcmp(basename(argv[0]), "watchdogd")) {
return watchdogd_main(argc, argv);
}
if (REBOOT_BOOTLOADER_ON_PANIC) {
install_reboot_signal_handlers();
}
add_environment("PATH", _PATH_DEFPATH);
bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
if (is_first_stage) {
boot_clock::time_point start_time = boot_clock::now();
// 清理umask.
umask(0);
// 创建和挂载启动所需的文件目录
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
#define MAKE_STR(x) __STRING(x)
mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
chmod("/proc/cmdline", 0440);
gid_t groups[] = { AID_READPROC };
setgroups(arraysize(groups), groups);
mount("sysfs", "/sys", "sysfs", 0, NULL);
mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
InitKernelLogging(argv);
······
}
//对属性服务进行初始化
property_init();
······
//创建epoll句柄
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
if (epoll_fd == -1) {
PLOG(ERROR) << "epoll_create1 failed";
exit(1);
}
//用于设置子进程信号处理函数,如果子进程(Zygote)异常退出,init会根据调用该函数中设定的信号处理函数来处理
signal_handler_init();
//导入默认的环境变量
property_load_boot_defaults();
export_oem_lock_status();
//启动属性服务
start_property_service();
set_usb_controller();
const BuiltinFunctionMap function_map;
Action::set_function_map(&function_map);
Parser& parser = Parser::GetInstance();
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
//解析init.rc文件
parser.ParseConfig("/init.rc");
parser.set_is_system_etc_init_loaded(
parser.ParseConfig("/system/etc/init"));
parser.set_is_vendor_etc_init_loaded(
parser.ParseConfig("/vendor/etc/init"));
parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
} else {
parser.ParseConfig(bootscript);
parser.set_is_system_etc_init_loaded(true);
parser.set_is_vendor_etc_init_loaded(true);
parser.set_is_odm_etc_init_loaded(true);
}
if (false) parser.DumpState();
ActionManager& am = ActionManager::GetInstance();
······
while (true) {
int epoll_timeout_ms = -1;
if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
//内部遍历执行每个action中携带的command对应的执行函数
am.ExecuteOneCommand();
}
if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
//重启死去的进程
restart_processes();
if (process_needs_restart_at != 0) {
epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
}
if (am.HasMoreCommands()) epoll_timeout_ms = 0;
}
epoll_event ev;
int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
if (nr == -1) {
PLOG(ERROR) << "epoll_wait failed";
} else if (nr == 1) {
((void (*)()) ev.data.ptr)();
}
}
return 0;
}
init进程做的其中一件重要的事情就是解析init.rc文件,init.rc文件是由Android初始化语言(AIL)编写的脚本,主要用来启动各种服务,我们关注的Zygote进程就是由init.rc拆分后的init.zyygoteXX.rc定义的,以64位系统为例,就是init.zyygote64.rc文件。主要代码如下:
/*位于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
这段service的主要作用就是通知init进程创建名为zygote的进程,程序路径位于/system/bin/app_process64,后面是要传递的参数。class main指的是Zygote的classname为main。
而在init.rc有如下配置代码:
on nonencrypted
class_start main
class_start late_start
其中class_start是一个COMMAND,对应的函数为do_class_start,而main就是Zygote的classname,因此class_start min是用来启动Zygote的,do_class_start函数在builtins.cpp定义,关键代码如下:
static int do_class_start(const std::vector<std::string>& args) {
/* Starting a class does not start services
* which are explicitly disabled. They must
* be started individually.
*/
ServiceManager::GetInstance().
ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
return 0;
}
而ForEachServiceInClass函数会遍历Service链表,找到classname为main的Zygote,并执行StartIfNotDisabled函数,该函数代码如下:
bool Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
return true;
}
可以看到,如果没有被对应的rc文件设置disable选项,则会调用Start()函数来启动该Service,因此我们来查看Start函数,主要代码如下:
bool Service::Start() {
// Starting a service removes it from the disabled or reset state and
// immediately takes it out of the restarting state if it was in there.
flags_ &= (~(SVC_DISABLED|SVC_RESTARTING|SVC_RESET|SVC_RESTART|SVC_DISABLED_START));
// 如果Service已经启动,则不启动
if (flags_ & SVC_RUNNING) {
return false;
}
bool needs_console = (flags_ & SVC_CONSOLE);
if (needs_console) {
if (console_.empty()) {
console_ = default_console;
}
int console_fd = open(console_.c_str(), O_RDWR | O_CLOEXEC);
if (console_fd < 0) {
PLOG(ERROR) << "service '" << name_ << "' couldn't open console '" << console_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
close(console_fd);
}
//判断需要启动的Service对应的执行文件是否存在
struct stat sb;
if (stat(args_[0].c_str(), &sb) == -1) {
PLOG(ERROR) << "cannot find '" << args_[0] << "', disabling '" << name_ << "'";
flags_ |= SVC_DISABLED;
return false;
}
······
pid_t pid = -1;
if (namespace_flags_) {
pid = clone(nullptr, nullptr, namespace_flags_ | SIGCHLD, nullptr);
} else {
pid = fork();
}
//当前代码在子进程进行
if (pid == 0) {
umask(077);
······
//调用execve函数Service子进程就会被启动
if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
PLOG(ERROR) << "cannot execve('" << strs[0] << "')";
}
_exit(127);
}
······
return true;
}
调用execve函数,Service子进程会被启动,并进入执行该Service的main函数,如果该Service是Zygote,则执行/system/bin/app_process64,对应app_main.cpp文件。其中的main函数代码如下:
int main(int argc, char* const 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.");
}
}
可知这个函数调用了runtime的start函数启动Zygote,至此Zygote就启动了。
让我们总结下init进程的工作:
- 创建和挂载启动所需要的文件目录
- 初始化和启动属性服务
- 解析init.rc并启动Zygote进程
接下来,我们就即将进入真正的安卓系统启动过程。
三、安卓系统启动
3.1 概述
在安卓系统中,DVM、和ART、应用程序进程以及运行系统的关键服务的SystemServer都是由Zygote进程来创建的,因此我们也称呼Zygote进程为受精卵进程或孵化器进程。下面我们就一起来学习Zygote进程启动过程。
3.2 启动Java框架,即进入FrameWork层
上一小节讲到,init启动Zygote是靠app_main.cpp的main函数中的runtime的start方法。我们就从这里继续分析学习。
int main(int argc, char* const argv[])
{
······
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;
}
······
}
······
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
······
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.");
}
}
上面第一段代码主要是标识当前是什么进程,由于Zygote进程都是通过fork自身来创建子进程,所以有必要检查当前运行在哪个进程当中。
如果运行在Zygote进程,就会执行第三段代码,调用runtime的start函数。该函数的主要关键如下:
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
······
/* 启动java虚拟机 */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
//为java虚拟机注册JNI方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
······
//从app_main的main函数知道className为com.android.internal.os.ZygoteInit
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}
//将className的“.”替换为“/”
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
} else {
//找到Zygote的main方法
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 {
//通过JNI调用ZygoteInit的main方法
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
······
}
根据注释可以看到,这个函数的主要作用,就是启动Java虚拟机,并为其注册JNI方法,然后根据className找到ZygoteInit,顺利通过JNI调用其main函数。至于为什么要使用JNI,是因为ZygoteInit是由java语言编写的,当前的运行逻辑在Native中,需要进入FrameWork层,也就是java框架层。
3.3 FrameWork层发生的事情
Zygote成功进入Java框架层,换句话说就是Zygote开创了Java框架层。该main方法关键代码如下:
public static void main(String argv[]) {
try {
//创建一个Server端的socket,socketName为“zygote”
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进程
startSystemServer(abiList, socketName, zygoteServer);
}
Log.i(TAG, "Accepting command socket connections");
//等待AMS请求
zygoteServer.runSelectLoop(abiList);
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
第一段代码创建了一个Server端的socket,socketName为“zygote”,这个socket用于等待AMS请求Zygote来创建新的应用程序进程,然后预加载类和资源,之后启动SystemServer进程,这样系统的服务也会由SystemServe进程启动起来,最后调用zygoteServer的runSelectLoop方法来等待AMS,可以总结ZygoteInit的main方法主要做了四件事:
- 创建一个Server端的Socket
- 预加载类和资源
- 启动SystemServer进程
- 等待AMS请求创建新的应用程序进程
具体的这四个函数的详细细节,本处不在探讨,待下次再进行学习。这里只说一下SystemServer进程的工作:
- 启动Binder线程池,这样就可以与其他进程通信
- 创建SystemServiceManager,其用于对系统的服务进程创建、启动和生命周期管理
- 启动各种系统服务
四、总结
这一次,我们学习了从kernel到framework层的工作,大致是梳理了安卓手机从按下电源键到启动安卓系统的过程,不过大家肯定还有疑问,这里并没有显示桌面,并没有启动软件,这些问题,我准备在下一篇文章再和大家一起学习。