概要
android启动过程包含从Linux内核加载到Home应用程序启动的整个过程。
Linux 内核
android是基于Linux内核的系统平台。启动的时候,首先通过bootloader(系统加载器),加载Linux内核。在Linux加载启动时,与普通的Linux启动过程相同,先初始化内核,然后调用init进程。
init进程
android的init进程对各种设备进行初始化,运行android framework所需要的各种daemon、context manager、media server、zygote等。以下是init进程执行的daemon进程:
- USB daemon(usbd):管理USB连接
- android debug bridge daemon(adbd):android debug bridge连接管理
- debugger daemon(debuggerd):启动debugger系统
- radio interface layer daemon(rild):管理无线通信连接
context manager
context manager是一个管理android系统服务的重要进程。系统服务是组成android framework的重要组件,提供从相机、音频、视频处理到各种应用程序制作所需要得到重要的API
context manager提供运行于android内的各种系统服务信息。应用程序或framework内部模块在调用系统服务时,需要先向服务器申请,而后通过binder IPC调用系统服务。
在系统启动的时候,android所有系统服务都要把各自的handle信息注册到context manager,此时,binder IPC用来进行进程间通信。
media server
media server用于运行基于C/C++的本地系统服务,如audio flinger(负责音频输出)、camera等。
zygote
zygote进程用于缩短android应用程序加载的时间。每当执行Java应用程序的时候,zygote就会派生出一个子进程来执行应用程序,该子进程就是用来执行Java应用程序的虚拟机。
system server
system server是android系统的一个核心进程,它是由zygote进程创建的,在android启动过程中位于zygote之后。在system server中可以看到它建立的android中的大部分服务,如activity manager service(管理应用程序的生命周期)、location manager service(提供终端的地理位置信息)等。
为了将运行在system server中Java系统服务提供给android应用程序或framework内部模块使用,需要将它们先注册到context manager中。
在通过binder IPC 将Java系统服务注册到基于C语言的服务管理器时,需要使用JNI本地编程接口。JNI允许Java与其他编程语言(如C、C++、汇编语言)编写的应用程序和库进行交互操作。
以上就是对android启动过程的简单介绍,这仅仅是android启动过程的一部分,当所有Java系统服务加载完毕后,activity manager service会运行HOME应用,启动过程继续进行。
init进程
众所周知,Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再依次启动系统运行所需要的其他进程。在系统启动完成后,init进程会作为守护进程监视所有其他进程。若某个监视中的进程一旦终结,进入僵死状态时,它就会释放进程所占用的系统资源。在android平台中也存在init进程,除了提供以上常见的功能外,还提供几种额外的功能。android的init进程主要做以下两件事:
- 解析配置文件init.rc,然后启动系统各种native进程,例如非常重要的zygote进程、surfaceFlinger进程和media进程,这个是它的主要工作之一,也是它最重要的工作,因为native进程靠它来启动。
- 维护一个属性服务property service,并且管理它。应用程序客户端可以通过set操作来设置属性,通过get操作来获取属性,常用的setProperty()方法和getProperty()方法就是通过框架层连接到这个属性服务的。当然,也可以使用abd shell 来获取属性和设置属性,如adb shell 通过getprop命令获取手机的所有系统属性。
init进程的源代码在system/core/init/目录下,主要文件是init.cpp,以下是这个文件的main函数。
int main(int argc, char** argv) {
}
从init.cpp的main函数中,可以看到其主要做了以下几件事
- klog_init()函数将log写到/dev/kmsg中,对应代码位于system/core/libcutils/klog.c中
void klog_init(void) {
|
|
}
之后,klog.c的klog_writev()的函数就会把log信息写在新创建的klog_fd文件描述符代表的文件当中。在init.cpp文件中有大量的ERROR()、NOTICE() 和 INFO(),这些函数都对应init_klog_write()函数,init_klog_write()函数调用init_klog_vwrite(),init_klog_vwrite()函数调用了klog_writev()函数来处理这个log。
process_kernel_cmdline()函数解析内核启动参数
static void process_kernel_cmdline() {
12345// 内核启动参数信息保存在/proc/cmdline里main,它是uboot启动时传给内核的信息chmod("/proc/cmdline", 0440);// 解析内核启动参数import_kernel_cmdline(false, import_kernel_nv);if (qemu[0]) import_kernel_cmdline(true, import_kernel_nv);}
signal_handler_init()函数设置信号处理函数
void signal_handler_init() {
123456789101112131415161718192021// 创建socketint s[2];if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {ERROR("socketpair failed: %s\n", strerror(errno));exit(1);}// signal_write_fd发送数据的文件描述符,signal_read_fd接收数据的文件描述符signal_write_fd = s[0];signal_read_fd = s[1];struct sigaction act;memset(&act, 0, sizeof(act));act.sa_handler = SIGCHLD_handler; // 发送数据的函数act.sa_flags = SA_NOCLDSTOP;sigaction(SIGCHLD, &act, 0);ServiceManager::GetInstance().ReapAnyOutstandingChildren();// handle_signal接收数据的函数register_epoll_handler(signal_read_fd, handle_signal);}
signal_handler_init函数初始化了发送数据的SIGCHLD_handler函数和接收数据的handle_signal函数
static void SIGCHLD_handler(int) {
123if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {ERROR("write(signal_write_fd) failed: %s\n", strerror(errno));}}
static void handle_signal() {
123char buf[32];read(signal_read_fd, buf, sizeof(buf));ServiceManager::GetInstance().ReapAnyOutstandingChildren();}
当子进程异常退出的时候,SIGCHLD_handler函数会被调用,然后往signal_write_fd中写入数据,让接收数据的函数handle_signal接收,handle_signal函数接收到数据后,会调用ReapAnyOutstandingChildren函数来进行下一步操作。
void ServiceManager::ReapAnyOutstandingChildren() {
12while (ReapOneProcess()) {}}
bool ServiceManager::ReapOneProcess() {
123456789101112131415161718192021222324252627282930313233343536373839int status;pid_t pid = TEMP_FAILURE_RETRY(waitpid(-1, &status, WNOHANG));if (pid == 0) {return false;} else if (pid == -1) {ERROR("waitpid failed: %s\n", strerror(errno));return false;}// 找到死掉的serviceService* svc = FindServiceByPid(pid);std::string name;if (svc) {name = android::base::StringPrintf("Service '%s' (pid %d)",svc->name().c_str(), pid);} else {name = android::base::StringPrintf("Untracked pid %d", pid);}if (WIFEXITED(status)) {NOTICE("%s exited with status %d\n", name.c_str(), WEXITSTATUS(status));} else if (WIFSIGNALED(status)) {NOTICE("%s killed by signal %d\n", name.c_str(), WTERMSIG(status));} else if (WIFSTOPPED(status)) {NOTICE("%s stopped by signal %d\n", name.c_str(), WSTOPSIG(status));} else {NOTICE("%s state changed", name.c_str());}if (!svc) {return true;}if (svc->Reap()) { // 杀死死掉service的所有子进程waiting_for_exec = false;RemoveService(*svc);}return true;}
ReapAnyOutstandingChildren简单调用了ReapOneProcess函数来进行下一步操作。ReapOneProcess会杀死死掉的service及其子进程。之后,守护进程init.cpp的main函数会调用死掉的service的onrestart方法重启系统服务。
property_load_boot_defaults()函数导入默认环境变量
void property_load_boot_defaults() {
12// 导入PROP_PATH_RAMDISK_DEFAULT文件的内容load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);}
property_init()函数初始化属性服务和start_property_service()函数启动属性服务
void property_init() {
1234if (__system_property_area_init()) {ERROR("Failed to initialize property area\n");exit(1);}}
void start_property_service() {
1234567891011// 创建socket服务,即属性服务,用于进程间通信property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,0666, 0, 0, NULL);if (property_set_fd == -1) {ERROR("start_property_service socket creation failed: %s\n", strerror(errno));exit(1);}// 监听property_set_fd文件描述符listen(property_set_fd, 8);// 当应用程序设置属性的时候,框架会通过socket连接过来,于是就会调用handle_property_set_fd函数register_epoll_handler(property_set_fd, handle_property_set_fd);}
static void handle_property_set_fd()
{1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283prop_msg msg;int s;int r;struct ucred cr;struct sockaddr_un addr;socklen_t addr_size = sizeof(addr);socklen_t cr_size = sizeof(cr);char * source_ctx = NULL;struct pollfd ufds[1];const int timeout_ms = 2 * 1000; /* Default 2 sec timeout for caller to send property. */int nr;// 接受连接if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {return;}/* Check socket options here */if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {close(s);ERROR("Unable to receive socket options\n");return;}ufds[0].fd = s;ufds[0].events = POLLIN;ufds[0].revents = 0;nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));if (nr == 0) {ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);close(s);return;} else if (nr < 0) {ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));close(s);return;}r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));if(r != sizeof(prop_msg)) {ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",r, sizeof(prop_msg), strerror(errno));close(s);return;}switch(msg.cmd) {case PROP_MSG_SETPROP:msg.name[PROP_NAME_MAX-1] = 0;msg.value[PROP_VALUE_MAX-1] = 0;if (!is_legal_property_name(msg.name, strlen(msg.name))) {ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);close(s);return;}getpeercon(s, &source_ctx);// 如果属性是以ctl.开头就是控制属性,控制属性用于执行命令if(memcmp(msg.name,"ctl.",4) == 0) {close(s);if (check_control_mac_perms(msg.value, source_ctx, &cr)) {handle_control_message((char*) msg.name + 4, (char*) msg.value);} else {ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);}} else {// 普通系统属性设置if (check_mac_perms(msg.name, source_ctx, &cr)) {property_set((char*) msg.name, (char*) msg.value);} else {ERROR("sys_prop: permission denied uid:%d name:%s\n",cr.uid, msg.name);}close(s);}freecon(source_ctx);break;default:close(s);break;}}
handle_property_set_fd函数的变量name用来表示系统属性的名称,而变量value用来表示系统属性的值。系统属性分为两种类型,一种是普通类型的系统属性,另一种是控制类型的系统属性,而控制属性的系统属性名称以ctl.开头。回到函数中,如果属性是普通类型的系统属性,就会调用check_mac_perms来检查相应的权限,然后调用property_set函数来设置系统属性的值,如果是控制类型的系统属性,就会调用handle_control_message函数来设置系统属性的值。
void handle_control_message(const std::string& msg, const std::string& name) {
123456789101112131415Service* svc = ServiceManager::GetInstance().FindServiceByName(name);if (svc == nullptr) {ERROR("no such service '%s'\n", name.c_str());return;}if (msg == "start") {svc->Start(); // 启动一个服务} else if (msg == "stop") {svc->Stop(); // 停止一个服务} else if (msg == "restart") {svc->Restart(); //重启一个服务} else {ERROR("unknown control msg '%s'\n", msg.c_str());}}
int property_set(const char name, const char value) {
12345int rc = property_set_impl(name, value);if (rc == -1) {ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);}return rc;}
property_set通过调用property_set_impl来实现属性设置
static int property_set_impl(const char name, const char value) {
1234567891011121314151617181920212223242526272829303132333435363738394041size_t namelen = strlen(name);size_t valuelen = strlen(value);if (!is_legal_property_name(name, namelen)) return -1;if (valuelen >= PROP_VALUE_MAX) return -1;if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {if (selinux_reload_policy() != 0) {ERROR("Failed to reload policy\n");}} else if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {if (restorecon_recursive(value) != 0) {ERROR("Failed to restorecon_recursive %s\n", value);}}// 从属性空间看是否已经存在该属性prop_info* pi = (prop_info*) __system_property_find(name);if(pi != 0) {// 如果属性是以ro.开头表示只读,不能设置,直接返回if(!strncmp(name, "ro.", 3)) return -1;__system_property_update(pi, value, valuelen);} else {int rc = __system_property_add(name, namelen, value, valuelen);if (rc < 0) {return rc;}}// 如果属性是以net.开头,主要与DNS有关if (strncmp("net.", name, strlen("net.")) == 0) {if (strcmp("net.change", name) == 0) {return 0;}property_set("net.change", name);} else if (persistent_properties_loaded &&strncmp("persist.", name, strlen("persist.")) == 0) {// persist.开头的属性,需要调用write_persistent_property设置value值write_persistent_property(name, value);}property_changed(name, value);return 0;}
parser.ParseConfig(“/init.rc”);函数解析配置文件和使用for循环调用execute_one_command()函数来启动子进程
init.rc文件是android中一个非常重要的配置文件,这个文件并不是普通的一般配置文件,而是被成为android init language(android初始化语言)。
import /init.environ.rc import /init.usb.rc import /init.${ro.hardware}.rc import /init.usb.configfs.rc import /init.${ro.zygote}.rc on early-init # 设置init和它的子进程的oom_adj值,用于内存管理 write /proc/1/oom_score_adj -1000 # Disable sysrq from keyboard write /proc/sys/kernel/sysrq 0 # Set the security context of /adb_keys if present. restorecon /adb_keys # Shouldn't be necessary, but sdcard won't start without it. http://b/22568628. mkdir /mnt 0775 root system # Set the security context of /postinstall if present. restorecon /postinstall #启动ueventd,ueventd是init进程 start ueventd on init ... on late-init ... on boot ... on nonencrypted ... ... ....... ... service ueventd /sbin/ueventd class core critical seclabel u:r:ueventd:s0 service healthd /sbin/healthd class core critical seclabel u:r:healthd:s0 group root system wakelock service console /system/bin/sh class core console disabled user shell group shell log readproc seclabel u:r:shell:s0 on property:ro.debuggable=1 # Give writes to anyone for the trace folder on debug builds. # The folder is used to store method traces. chmod 0773 /data/misc/trace start console service flash_recovery /system/bin/install-recovery.sh class main oneshot
通过KEYWORD定义知道,KEYWORD只有三种类型,分别是SECTION、OPTION、COMMAND
- SECTION:只包括import、on、service这三个关键字
- OPTION:包括user、socket等关键字
- COMMAND:包括class_start、start等关键字
bool Parser::ParseConfig(const std::string& path) {
|
|
}
bool Parser::ParseConfigDir(const std::string& path) {
|
|
}
bool Parser::ParseConfigFile(const std::string& path) {
|
|
}
启动service进程
解析分析完init.rc文件后,就会通过while循环中的am.ExecuteOneCommand()函数去执行相对应的命令,触发条件到boot阶段的时候,就启动那些core类型和main类型的service,而service的启动主要是通过Service::Start()函数
bool Service::Start() {
|
|
}
总结
至此,init.rc文件的解析和启动service就分析完成了。init.rc文件的解析主要就是对关键字的解析,而service的启动主要是通过调用Linux的fork()函数创建一个子进程,execve()函数执行可执行程序,最终把service启动起来并且进入它的main()函数。