在阅读源码之前,我们应要熟悉整个Android的系统架构,在针对某一层进行深入理解,否则东看西看没有方向没有目标会导致思绪紊乱,这样读源码的效果不佳

这篇文章主要参考gityuan阅读Android 7.0的源码,顺着他的思路我理了一遍Android 9.0的代码,如果有地方理解错了,谢谢指出!!

Android整体系统框架

Linux 内核

Android 平台的基础是 Linux 内核。这一层包含Linux内核和一些驱动模块(比如USB驱动、Camera驱动等)

硬件抽象层 (HAL)

硬件抽象层 (HAL) 提供标准界面,向更高级别的 Java API 框架显示设备硬件功能。HAL 包含多个库模块,其中每个模块都为特定类型的硬件组件实现一个界面,例如相机或蓝牙模块。当框架 API 要求访问设备硬件时,Android 系统将为该硬件组件加载库模块。

Android Runtime

对于运行 Android 5.0(API 级别 21)或更高版本的设备,每个应用都在其自己的进程中运行,并且有其自己的 Android Runtime (ART) 实例。ART 编写为通过执行 DEX 文件在低内存设备上运行多个虚拟机,DEX 文件是一种专为 Android 设计的字节码格式,经过优化,使用的内存很少。编译工具链(例如 Jack)将 Java 源代码编译为 DEX 字节码,使其可在 Android 平台上运行。

ART 的部分主要功能包括:

预先 (AOT) 和即时 (JIT) 编译
优化的垃圾回收 (GC)
更好的调试支持,包括专用采样分析器、详细的诊断异常和崩溃报告,并且能够设置监视点以监控特定字段

在 Android 版本 5.0(API 级别 21)之前,Dalvik 是 Android Runtime。如果您的应用在 ART 上运行效果很好,那么它应该也可在 Dalvik 上运行,但反过来不一定。

原生 C/C++ 库

许多核心 Android 系统组件和服务(例如 ART 和 HAL)构建自原生代码,需要以 C 和 C++ 编写的原生库。Android 平台提供 Java 框架 API 以向应用显示其中部分原生库的功能。例如,您可以通过 Android 框架的 Java OpenGL API 访问 OpenGL ES,以支持在应用中绘制和操作 2D 和 3D 图形。

Java API 框架

您可通过以 Java 语言编写的 API 使用 Android OS 的整个功能集。这些 API 形成创建 Android 应用所需的构建块,它们可简化核心模块化系统组件和服务的重复使用,这一点也是我们常用到的一块地方

系统应用

Android 随附一套用于电子邮件、短信、日历、互联网浏览和联系人等的核心应用。平台随附的应用与用户可以选择安装的应用一样,没有特殊状态。因此第三方应用可成为用户的默认网络浏览器、短信 Messenger 甚至默认键盘(有一些例外,例如系统的“设置”应用)。

**所以我们这次就先从Native C/C++这一边开始看,这里面有许多核心的Android系统组件和服务,接下来我们先下载源码 platform-system-core-pie-release,从这边开始就进入Native源码的世界了**
 
这个源码里的官方提供的文档有这么一句话:

/init.rc is the primary .rc file and is loaded by the init executable at the beginning of its execution.  It is responsible for the initial set up of the system.

init这个函数负责系统的初始化,所以接下来也会从这个点切入。

1.init概述

init是Android系统中用户空间的第一个进程,它的进程号是1。我们肯能经常听到过zygote,那么这个zygote是如何被创建的呢,init的属性服务又是如何提供的。

2.init分析

以下代码很长,请保持耐心!
在下面代码我会将一些函数标记为log n ,大家可以通过log1等去快速查找相应函数所代表的含义

2.1main函数

首先看入口函数main的代码

int main(int argc, char** argv) {...(将文件属性设置为077权限)// 第一阶段bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);if (is_first_stage) { boot_clock::time_point start_time = boot_clock::now();// Clear the umask. umask(0); //umask()函数:设置建立新文件时的权限遮罩clearenv();  //清除所有的环境变量setenv("PATH", _PATH_DEFPATH, 1); //设置环境变量// 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.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));// Don't expose the raw commandline to unprivileged processes.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");// /mnt/vendor is used to mount vendor-specific partitions that can not be// part of the vendor partition, e.g. because they are mounted read-write.mkdir("/mnt/vendor", 0755);// Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually// talk to the outside world...InitKernelLogging(argv); // log2//以上挂载一些文件(挂载:它指将一个设备(通常是存储设备)挂接到一个已存在的目录上。)LOG(INFO) << "init first stage started!";//log2if (!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();// Set up SELinux, loading the SELinux policy.// 安装SELinuxSelinuxSetupKernelLogging();SelinuxInitialize();// We're in the kernel domain, so re-exec init to transition to the init domain now// that the SELinux policy has been loaded.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";}//此时我们处于init的第二阶段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.//设置所有进程都可以访问的会话密匙环。它将保存FBE加密密钥之类的东西。任何进程都不应覆盖其会话密钥环。keyctl_get_keyring_ID(KEY_SPEC_SESSION_KEYRING, 1);// Indicate that booting is in progress to background fw loaders, etc.//指示正在引导到后台fw加载器,等等。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.如果参数同时在命令行和DT中传递,// DT中设置的属性总是优先于命令行属性。process_kernel_dt();process_kernel_cmdline();// Propagate the kernel variables to internal variables// used by init as well as the current required properties.//将内核变量传播到内部变量//用于init以及当前所需的属性。export_kernel_boot_props();// Make the time that init started available for bootstat to log.//让init启动的时间可供bootstat进行日志记录。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);// Clean up our environment.//将libavb版本设置为只有框架的OTA匹配。unsetenv("INIT_SECOND_STAGE");unsetenv("INIT_STARTED_AT");unsetenv("INIT_SELINUX_TOOK");unsetenv("INIT_AVB_VERSION");// Now set up SELinux for second stage.//现在为第二阶段设置SELinux。SelinuxSetupKernelLogging();SelabelInitialize();SelinuxRestoreContext();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.//如果init没有CAP_SYS_BOOT功能,它将在容器中运行。
//在这种情况下,接收SIGTERM将导致系统关闭。InstallSigtermHandler();}property_load_boot_defaults();export_oem_lock_status();start_property_service();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...//队列一个等待冷启动完成的动作,这样我们就知道ueventd已经设置了所有/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./// /……这样我们就可以开始对需要/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");//log3// 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_doneam.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)();}}

2.2 log2: InitKernelLogging(argv) Log() log系统

includer log.h

#define KLOG_ERROR_LEVEL   3
#define KLOG_WARNING_LEVEL 4
#define KLOG_NOTICE_LEVEL  5
#define KLOG_INFO_LEVEL    6
#define KLOG_DEBUG_LEVEL   7

2.3 log3:QueueBuiltinAction  对内容的一系列操作

 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");

3 init重点分析

接下来,解读init的main方法中的4大块核心知识点:信号处理、rc文件语法、启动服务以及属性服务

3.1信号处理

  sigchld_handler_init();

首先看下这个函数做了什么事
  
  [-> sigchld_handler.cpp]

void sigchld_handler_init() {// 为SIGCHLD创建一个信令机制。int s[2];if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, s) == -1) {PLOG(FATAL) << "socketpair failed in sigchld_handler_init";}signal_write_fd = s[0];signal_read_fd = s[1];// 如果我们捕获了SIGCHLD,则写入signal_write_fd。struct sigaction act;memset(&act, 0, sizeof(act));act.sa_handler = SIGCHLD_handler;// SA_NOCLDSTOP使init进程只有在其子进程终止时才会受到SIGCHLD信号act.sa_flags = SA_NOCLDSTOP;sigaction(SIGCHLD, &act, 0);//进入waitpid来处理子进程是否退出的情况ReapAnyOutstandingChildren();//register_epoll_handler(signal_read_fd, handle_signal);
}

每个进程在处理其他进程发送的signal信号时都需要先注册,当进程的运行状态改变或终止时会产生某种signal信号,init进程是所有用户空间进程的父进程,当其子进程终止时产生sigchld信号,传递参数给sigaction结构体,便完成信号处理的过程。
  这里看下2个重要函数:

//写入数据static void SIGCHLD_handler(int) {if (TEMP_FAILURE_RETRY(write(signal_write_fd, "1", 1)) == -1) {PLOG(ERROR) << "write(signal_write_fd) failed";}
}//读取数据
static void handle_signal() {// Clear outstanding requests.char buf[32];//读取signal_read_fd中的数据,并放入bufread(signal_read_fd, buf, sizeof(buf));ReapAnyOutstandingChildren();
}

我们继续看下 ReapAnyOutstandingChildren()函数,里面的ReapOneProcess()又是一个很长的函数

void ReapAnyOutstandingChildren() {while (ReapOneProcess()) {}
}static bool ReapOneProcess() {siginfo_t siginfo = {};// This returns a zombie pid or informs us that there are no zombies left to be reaped.// It does NOT reap the pid; that is done below.if (TEMP_FAILURE_RETRY(waitid(P_ALL, 0, &siginfo, WEXITED | WNOHANG | WNOWAIT)) != 0) {PLOG(ERROR) << "waitid failed";return false;}auto pid = siginfo.si_pid;if (pid == 0) return false;// At this point we know we have a zombie pid, so we use this scopeguard to reap the pid// whenever the function returns from this point forward.// We do NOT want to reap the zombie earlier as in Service::Reap(), we kill(-pid, ...) and we// want the pid to remain valid throughout that (and potentially future) usages.auto reaper = make_scope_guard([pid] { TEMP_FAILURE_RETRY(waitpid(pid, nullptr, WNOHANG)); });std::string name;std::string wait_string;Service* service = nullptr;if (PropertyChildReap(pid)) {name = "Async property child";} else if (SubcontextChildReap(pid)) {name = "Subcontext";} else {service = ServiceList::GetInstance().FindService(pid, &Service::pid);if (service) {name = StringPrintf("Service '%s' (pid %d)", service->name().c_str(), pid);if (service->flags() & SVC_EXEC) {auto exec_duration = boot_clock::now() - service->time_started();auto exec_duration_ms =std::chrono::duration_cast<std::chrono::milliseconds>(exec_duration).count();wait_string = StringPrintf(" waiting took %f seconds", exec_duration_ms / 1000.0f);}} else {name = StringPrintf("Untracked pid %d", pid);}}if (siginfo.si_code == CLD_EXITED) {LOG(INFO) << name << " exited with status " << siginfo.si_status << wait_string;} else {LOG(INFO) << name << " received signal " << siginfo.si_status << wait_string;}if (!service) return true;service->Reap(siginfo);if (service->flags() & SVC_TEMPORARY) {ServiceList::GetInstance().RemoveService(*service);}return true;
}

这篇还未完成,等之后在完善下,给各位带来不便。

Android Pie源码阅读 -----深入理解init(一)相关推荐

  1. 【Android 10 源码】深入理解 software Codec2 服务启动

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  2. 【Android 10 源码】深入理解 MediaCodec 组件分配

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  3. Android Framework源码阅读计划(2)——LocationManagerService.java

    Android Framework源码阅读计划 Android Framework源码阅读计划(1)--LocationManager.java Android Framework源码阅读计划(2)- ...

  4. 【Android 10 源码】深入理解 Omx 初始化

    MediaCodec 系列文章: [Android 10 源码]深入理解 MediaCodec 硬解码初始化 [Android 10 源码]深入理解 Omx 初始化 [Android 10 源码]深入 ...

  5. Android aosp源码阅读

    前言 最近因为找工作,需要频繁查阅Android源码.因此,打算在本地硬盘上下载Android源码,通过Android Studio来阅读. Android 源码构建:https://source.a ...

  6. android sensor源码,阅读android有关sensor的源码总结 - JerryMo06的专栏 - CSDN博客

    虽然这篇文章写得很差,因为赶时间,所以就匆匆忙忙地写出来自己作一个笔记.但是我想对大家应该有一点帮助. 1.有关sensor在Java应用程序的编程(以注册多个传感器为例,这程序是我临时弄出来的,可能 ...

  7. android toolbar源码解析,深入理解Android 5.0中的Toolbar

    环境说明: Android Studio 2.0 V7包版本:com.android.support:appcompat-v7:23.4.0 compileSdkVersion 23 buildToo ...

  8. Android Linkage-RecyclerView源码阅读

    当前版本 1.9.2 项目地址 概述 自定义LinkageRecyclerView控件,该控件布局中含有两个RecyclerView控件,左边为主Rv,右边为次Rv. 次Rv顶部有一个悬挂头View, ...

  9. Android源码阅读---init进程

    Android源码阅读-init进程 文章目录 Android源码阅读---init进程 1. 编译命令和进程入口 1. init 进程编译命令 2. main函数流程 2. 主函数处理流程 1. 创 ...

最新文章

  1. String类的学习
  2. Python学习总结(一)
  3. Python基础 - 第九天 - paramiko模块、进程、线程
  4. 【解决方案】Monkey-patching ssl after ssl has already been imported may lead to errors
  5. Linux 查看进程和删除进程
  6. 环形队列出队的元素怎么输出出来_队列的知识讲解与基本实现(数据结构)
  7. jackson 的注解:@JsonProperty、@JsonIgnore、@JsonFormat 用法说明
  8. linux定时任务执行url,科技常识:linux定时任务访问url实例
  9. C#程序打包安装部署之创建快捷方式
  10. Java、JSP药品库房管理系统
  11. 室内设计数据手册pdf_室内设计数据手册:施工与安装尺寸
  12. Python 可轻松生成图文并茂的PDF报告!
  13. Python通过MQTT协议上传物联网数据给ThingsBoard
  14. 机器学习(一)——基础概念
  15. c语言编程序按下列公式计算e的值,编写程序,利用公式 ,求出e的近似值
  16. Linux--系统安全及应用(一)(账号安全控制)
  17. 转:敏感性分析(Sensitivity Analysis) 和龙卷风图(tornado diagra
  18. 超参数及其优化办法:验证集
  19. CMake - 生成器(Generators)
  20. java messagedigest_Java 自带的加密类MessageDigest类(加密MD5和SHA)

热门文章

  1. 程序员找不到对象是伪命题?他用大数据找对象,现在婚都结了
  2. 计算机菜单命令,什么是电脑的菜单操作命令
  3. 一文看懂SMT车间生产环境要求及管理规范
  4. 小程序高级电商前端第1周走进Web全栈工程师一----小程序注册、开发工具推荐、《风袖》首页布局详尽分析、Webstorm开发小程序必配配置、mock数据...
  5. 硬盘克隆大师从入门到精通
  6. 今天用Java开发主机IP扫描神器,零基础Socket编程详细
  7. 现代控制理论(机器人或人工智能方向)补充资料:Python Control Systems Library + Modern Robotics
  8. 华中科技大学和华为云瑶光造就中国团队全球首冠
  9. ISO/IEC 14443、射频、PICC
  10. 超兔指纹浏览器(TO12345)是什么?