您当前的位置:首页 > 电脑百科 > 程序开发 > 移动端 > Android

Android 9.0 init 启动流程

时间:2019-10-21 13:03:01  来源:  作者:

本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

一、启动流程概述

二、Android启动分析

三、init 进程启动分析

四、init 启动脚本分析

五、init 进程分析

六、init 脚本执行

七、init 进程守护

八、init rc 脚本启动Zygote

九、启动分析小结

一、 启动流程概述

Android启动流程跟 linux启动类似,大致分为如下五个阶段。

  • 1.开机上电,加载固化的ROM。
  • 2.加载BootLoader,拉起Android OS。
  • 3.加载Uboot,初始外设,引导Kernel启动等。
  • 4.启动Kernel,加载驱动,硬件。
  • 5.启动Android,挂载分区,加载驱动、服务,init进程等。

Android系统启动大致过程如下:

 

Android 9.0 init 启动流程

 

 

Android 启动过程

由于水平有限,无法深入了理解驱动层代码,本文主要对 Android上层启动流程进行分析。

二、Android启动分析

Uboot启动Kernel完成系统设置后,会首先在系统中寻找init.rc文件,并启动init进程。

 

Android 9.0 init 启动流程

 

 

Android 启动分析

三、init 进程启动分析

Init进程是Android启动的第一个进程,进程号为1,是Android的系统启动的核心进程,主要用来创建Zygote、属性服务等。 init.cpp 中的main 函数,是init进程的入口函数,源码主要存在systemcoreinit目录下。

常见init.xxx.rc 进程如下:

 

Android 9.0 init 启动流程

 

 

常见init.xxx.rc 进程

init 进程主要作用

 

Android 9.0 init 启动流程

 

 

init 进程主要作用

/system/core/init 部分内容如下:

 

Android 9.0 init 启动流程

 

 

/system/core/init 部分内容

main 函数主要做的事情

1.创建挂载启动所需的文件系统(tmpfs、 devpts、 proc、 sysfs、 selinuxfs等)。

2.初始化并启动属性服务

3.解析init.rc 脚本配置文件,并启动Zygote 进程。

init.cpp main 函数实现代码如下:

int main(int argc, char** argv) {
 ... ...
 if (!strcmp(basename(argv[0]), "watchdogd")) {
 //启动看门狗函数
 return watchdogd_main(argc, argv);
 }
 ... ...
 //启动第一阶段
 if (is_first_stage) {
 boot_clock::time_point start_time = boot_clock::now();
 // 清理 umask.
 umask(0);
 clearenv();
 setenv("PATH", _PATH_DEFPATH, 1);
 // 在RAM内存上获取基本的文件系统,剩余的被 rc 文件所用
 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));
 // 非特权应用不能使用 Android 命令行
 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));
 if constexpr (WORLD_WRITABLE_KMSG) {
 mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11));
 }
 mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
 mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
 // Mount staging areas for devices managed by vold
 // See storage config details at http://source.android.com/devices/storage/
 mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV,
 "mode=0755,uid=0,gid=1000");
 //创建可供读写的 vendor目录
 mkdir("/mnt/vendor", 0755);
 // 在/dev目录下挂载好 tmpfs 以及 kmsg 
 // 这样就可以初始化 /kernel Log 系统,供用户打印log
 InitKernelLogging(argv);
 LOG(INFO) << "init first stage started!";
 if (!DoFirstStageMount()) {
 LOG(FATAL) << "Failed to mount required partitions early ...";
 }
 SetInitAvbVersionInRecovery();
 // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote).
 global_seccomp();
 // 优先加载selinux log系统, 紧接着初始化selinux
 SelinuxSetupKernelLogging();
 SelinuxInitialize();
 // 添加 selinux 是否启动成功的log
 if (selinux_android_restorecon("/init", 0) == -1) {
 PLOG(FATAL) << "restorecon failed of /init failed";
 }
 setenv("INIT_SECOND_STAGE", "true", 1);
 static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
 uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
 setenv("INIT_STARTED_AT", std::to_string(start_ms).c_str(), 1);
 char* path = argv[0];
 char* args[] = { path, nullptr };
 execv(path, args);
 // execv() only returns if an error hAppened, in which case we
 // panic and never fall through this conditional.
 PLOG(FATAL) << "execv("" << path << "") failed";
 }
 //启动第二阶段
 InitKernelLogging(argv);
 LOG(INFO) << "init second stage started!";
 // Set up a session keyring that all processes will have access to. It
 // will hold things like FBE encryption keys. No process should override
 // its session keyring.
 keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);
 // Indicate that booting is in progress to background fw loaders, etc.
 close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
 //初始化属性
 property_init();
 // If arguments are passed both on the command line and in DT,
 // properties set in DT always have priority over the command-line ones.
 process_kernel_dt();
 process_kernel_cmdline();
 // Propagate the kernel variables to internal variables
 // used by init as well as the current required properties.
 export_kernel_boot_props();
 // Make the time that init started available for bootstat to log.
 property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
 property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
 // Set libavb version for Framework-only OTA match in Treble build.
 const char* avb_version = getenv("INIT_AVB_VERSION");
 if (avb_version) property_set("ro.boot.avb_version", avb_version);
 // 清空设置的环境变量
 unsetenv("INIT_SECOND_STAGE");
 unsetenv("INIT_STARTED_AT");
 unsetenv("INIT_SELINUX_TOOK");
 unsetenv("INIT_AVB_VERSION");
 // 设置第二阶段的selinux
 SelinuxSetupKernelLogging();
 SelabelInitialize();
 SelinuxRestoreContext();
 //创建 epoll 句柄
 epoll_fd = epoll_create1(EPOLL_CLOEXEC);
 if (epoll_fd == -1) {
 PLOG(FATAL) << "epoll_create1 failed";
 }
 //设置 子进程处理函数
 sigchld_handler_init();
 if (!IsRebootCapable()) {
 // If init does not have the CAP_SYS_BOOT capability, it is running in a container.
 // In that case, receiving SIGTERM will cause the system to shut down.
 InstallSigtermHandler();
 }
 LoadRscRoProps();
 property_load_boot_defaults();
 export_oem_lock_status();
 //启动属性服务
 start_property_service();
 //为USB存储设置udc Contorller, sys/class/udc
 set_usb_controller();
 const BuiltinFunctionMap function_map;
 Action::set_function_map(&function_map);
 subcontexts = InitializeSubcontexts();
 ActionManager& am = ActionManager::GetInstance();
 ServiceList& sm = ServiceList::GetInstance();
 LoadBootScripts(am, sm);
 // Turning this on and letting the INFO logging be discarded adds 0.2s to
 // Nexus 9 boot time, so it's disabled by default.
 if (false) DumpState();
 am.QueueEventTrigger("early-init");
 // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
 am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
 // ... so that we can start queuing up actions that require stuff from /dev.
 am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
 am.QueueBuiltinAction(SetMmapRndBitsAction, "SetMmapRndBits");
 am.QueueBuiltinAction(SetKptrRestrictAction, "SetKptrRestrict");
 am.QueueBuiltinAction(keychord_init_action, "keychord_init");
 am.QueueBuiltinAction(console_init_action, "console_init");
 // Trigger all the boot actions to get us started.
 am.QueueEventTrigger("init");
 // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
 // wasn't ready immediately after wait_for_coldboot_done
 am.QueueBuiltinAction(MixHwrngIntoLinuxRngAction, "MixHwrngIntoLinuxRng");
 // Don't mount filesystems or start core system services in charger mode.
 std::string bootmode = GetProperty("ro.bootmode", "");
 if (bootmode == "charger") {
 am.QueueEventTrigger("charger");
 } else {
 am.QueueEventTrigger("late-init");
 }
 // Run all property triggers based on current state of the properties.
 am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
 while (true) {
 // By default, sleep until something happens.
 int epoll_timeout_ms = -1;
 if (do_shutdown && !shutting_down) {
 do_shutdown = false;
 if (HandlePowerctlMessage(shutdown_command)) {
 shutting_down = true;
 }
 }
 if (!(waiting_for_prop || Service::is_exec_service_running())) {
 am.ExecuteOneCommand();
 }
 if (!(waiting_for_prop || Service::is_exec_service_running())) {
 if (!shutting_down) {
 auto next_process_restart_time = RestartProcesses();
 // If there's a process that needs restarting, wake up in time for that.
 if (next_process_restart_time) {
 epoll_timeout_ms = std::chrono::ceil<std::chrono::milliseconds>(
 *next_process_restart_time - boot_clock::now())
 .count();
 if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
 }
 }
 // If there's more work to do, wake up again immediately.
 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;
}

基于MTK 平台 init.cpp 源码分析

 

Android 9.0 init 启动流程

 

 

基于MTK 平台 init.cpp 主要作用

四、 init 启动脚本分析

init.rc 路径 一般在system/core/rootdir下,init脚本是有Android 初始化语言编写。

Android Init Language 语句类型:

  • 1.Action
  • 2.Command
  • 3.Service
  • 4.Option
  • 5.Import

 

Android 9.0 init 启动流程

 

 

init 进程分析

Android 9.0 init 启动流程

 

 

init.rc on

Android 9.0 init 启动流程

 

 

init.rc services

Android 9.0 init 启动流程

 

 

init.rc import

五、init 进程分析

 

Android 9.0 init 启动流程

 

 

init 进程分析

Android 9.0 init 启动流程

 

 

init 解析脚本分析

Android 9.0 init 启动流程

 

 

init 事件列表

Android 9.0 init 启动流程

 

 

init 事件结构

六 、init 脚本执行

 

Android 9.0 init 启动流程

 

 

init 进程解析和执行

Android 9.0 init 启动流程

 

 

整理事件列表

Android 9.0 init 启动流程

 

 

init 构建事件

Android 9.0 init 启动流程

 

 

Service 事件分类

Android 9.0 init 启动流程

 

 

init 进程执行命令和启动服务

七、init 进程守护

init进程处理消息事件

  1. 根据Shell或者系统中消息设置系统prop
  •  
  1. 守护系统服务,如果服务退出,重启退出的服务。

 

Android 9.0 init 启动流程

 

 

init守护进程

Android 9.0 init 启动流程

 

 

init 处理 prop 消息分析

Android 9.0 init 启动流程

 

 

init 守护服务分析

八、init rc 脚本启动Zygote

Zygote 的 classname 为main.

init.rc文件配置代码如下:

... ... 
on nonencrypted
 class_start main
 class_start late_start
on property:sys.init_log_level=*
 loglevel ${sys.init_log_level}
... ...

九、启动分析小结

 

Android 9.0 init 启动流程

 

 

启动分析小结



Tags:Android   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
今天面试遇到同学说做过内存优化,于是我一般都会问那 Bitmap 的像素内存存在哪?大多数同学都回答在 java heap 里面,就比较尴尬,理论上你做内存优化,如果连图片这个内存大户内存...【详细内容】
2021-12-23  Tags: Android  点击:(8)  评论:(0)  加入收藏
Android logcat日志封装logcat痛点在Android开发中使用logcat非常频繁,logcat能帮我们定位问题,但是在日常使用中发现每次使用都需要传递tag,并且会遇到输出频率很高的log,在多...【详细内容】
2021-12-22  Tags: Android  点击:(8)  评论:(0)  加入收藏
对项目的基本介绍 1.整个框架主要是给MVVM框架使用的,自己写完interface接口后,通过自定义的注解就能自动生成接口方法 2.用Kotlin的Flow去代替Rxjava,因为我发现RxJava功能很...【详细内容】
2021-12-08  Tags: Android  点击:(17)  评论:(0)  加入收藏
前言在Android开发过程中,有些时候会根据需要引用别的项目到当前项目里面,而且以Module形式引用。所以本篇博文就来分享一下怎么以Module形式引用别的项目到当前项目中,方便开...【详细内容】
2021-12-07  Tags: Android  点击:(22)  评论:(0)  加入收藏
新型Android恶意木马程序伪装成数十款街机、射击和策略游戏,通过华为应用市场AppGallery进行分发,从而窃取设备信息和用户的手机号码,全球目前至少有930万台Android设备被该恶...【详细内容】
2021-12-01  Tags: Android  点击:(24)  评论:(0)  加入收藏
作者:fundroid这篇文章偏阅读一些,大家可以了解下 Android 的一些最新动向。每年9/10月份 Google 都会举行约为期2天的 Android Dev Summit,在活动上 Google 的技术专家们会分...【详细内容】
2021-11-30  Tags: Android  点击:(15)  评论:(0)  加入收藏
一、 准备工作1、安装JDK,下载地址(可能需要一个oracle账号,大家百度一下或者自行注册一个就行。尽可能选择8或者11,这两个是长期版本)Java SE | Oracle Technology Network | Or...【详细内容】
2021-11-23  Tags: Android  点击:(28)  评论:(0)  加入收藏
如果你是一名忠实的Android玩家,那么可能会知道,今年的Android 12系统在版本规划上与“往届”相比可以说是很有些特殊。具体来说,除了前段时间刚刚推出正式版的Android 12外,谷...【详细内容】
2021-11-10  Tags: Android  点击:(24)  评论:(0)  加入收藏
使用Maven Publish Plugin插件。(官方支持)一、在Library的build.gradle中配置plugins { id &#39;com.android.library&#39; id &#39;kotlin-android&#39; id &#39;k...【详细内容】
2021-11-05  Tags: Android  点击:(37)  评论:(0)  加入收藏
今年5月,谷歌推出了Android 12,这是原生安卓系统史上最大的设计变化,10月4日,谷歌推出全新的Android12正式版本,并且宣布会在今年晚些时候应用于安卓设备,对比Android11的挤牙膏式...【详细内容】
2021-10-29  Tags: Android  点击:(125)  评论:(0)  加入收藏
▌简易百科推荐
今天面试遇到同学说做过内存优化,于是我一般都会问那 Bitmap 的像素内存存在哪?大多数同学都回答在 java heap 里面,就比较尴尬,理论上你做内存优化,如果连图片这个内存大户内存...【详细内容】
2021-12-23  像程序那样思考    Tags:Android开发   点击:(8)  评论:(0)  加入收藏
Android logcat日志封装logcat痛点在Android开发中使用logcat非常频繁,logcat能帮我们定位问题,但是在日常使用中发现每次使用都需要传递tag,并且会遇到输出频率很高的log,在多...【详细内容】
2021-12-22  YuCoding    Tags:Android   点击:(8)  评论:(0)  加入收藏
对项目的基本介绍 1.整个框架主要是给MVVM框架使用的,自己写完interface接口后,通过自定义的注解就能自动生成接口方法 2.用Kotlin的Flow去代替Rxjava,因为我发现RxJava功能很...【详细内容】
2021-12-08  网易Leo    Tags:Android开发   点击:(17)  评论:(0)  加入收藏
前言在Android开发过程中,有些时候会根据需要引用别的项目到当前项目里面,而且以Module形式引用。所以本篇博文就来分享一下怎么以Module形式引用别的项目到当前项目中,方便开...【详细内容】
2021-12-07  网易Leo    Tags:Android开发   点击:(22)  评论:(0)  加入收藏
作者:fundroid这篇文章偏阅读一些,大家可以了解下 Android 的一些最新动向。每年9/10月份 Google 都会举行约为期2天的 Android Dev Summit,在活动上 Google 的技术专家们会分...【详细内容】
2021-11-30  像程序那样思考    Tags:Android开发   点击:(15)  评论:(0)  加入收藏
一、 准备工作1、安装JDK,下载地址(可能需要一个oracle账号,大家百度一下或者自行注册一个就行。尽可能选择8或者11,这两个是长期版本)Java SE | Oracle Technology Network | Or...【详细内容】
2021-11-23  永沧    Tags:Android   点击:(28)  评论:(0)  加入收藏
使用Maven Publish Plugin插件。(官方支持)一、在Library的build.gradle中配置plugins { id &#39;com.android.library&#39; id &#39;kotlin-android&#39; id &#39;k...【详细内容】
2021-11-05  羊城小阳    Tags:Android   点击:(37)  评论:(0)  加入收藏
谷歌离推出Play Store应用程序的新数据隐私部分又近了一步。应用程序开发人员现在可以通过谷歌在Play控制台的新 "数据安全表 "填写相关细节。该公司表示,所需信息将从2022年...【详细内容】
2021-10-20    中关村在线  Tags:安卓   点击:(58)  评论:(0)  加入收藏
架构究竟是什么?如何更好的理解架构?我们知道一个APP通常是由class组成,而这些class之间如何组合,相互之间又如何产生作用,就是影响这个APP的关键点。细分的话我们可以将其分为类...【详细内容】
2021-09-17  像程序那样思考    Tags:Android架构   点击:(52)  评论:(0)  加入收藏
概述当Android应用程序需要访问设备上的敏感资源时,应用程序开发人员会使用权限模型。虽然该模型使用起来非常简单,但开发人员在使用权限时容易出错,从而导致安全漏洞。本文中,...【详细内容】
2021-09-07  SecTr安全团队    Tags:Android开发   点击:(66)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条