1.用户看到的 Android 系统的启动过程:
- 按下电源键
- 进入开机动画
- 经过漫长的等待(大概几分钟)
- 开机动画结束,正式开机
- 进入系统桌面(Launcher)
2.系统真正的开机过程
- 按下电源键---引导芯片代码开始从预定义的地方(固化在ROM中)开始执行。加载引导程序Bootloader到RAM,然后执行,初始化硬件参数等功能。
- 硬件参数初始化完成后,进入到kernel层,kernel层主要加载一些硬件设备驱动,初始化进程管理等操作,再kernerl中首先启动swapper进程(pid=0),用于初始化进程管理,内存管理,加载Driver等操作,再启动kthread进程(pid=2),这些linux系统的内核进程,kthread是所有内核进程的鼻祖。
- Kernel加载完毕后,硬件设备驱动与hal层交互,初始化进程管理等操作会启动init进程,这些在native中,init进程pid=1,第一个启动,启动后,会启动adbd,logd等用户守护进程,并且会启动servicemanager(binder服务管家)等重要服务,
- 同时孵化出zygote进程,c++ framework,zygote进程是有init进程解析init.rc文件后fork生成,他会加载虚拟机,启动system server,(zygote 孵化的第一个进程)
- System server负责启动和管理整个java framework,包含AMS、PMS、WMS等服务
- zygote同时会启动app进程,启动的第一个进程是Launcher,然后启动email,sms等进程,所有的app都是zygote fork生成。
总结:BootLoader > Kernel > Native > Framework > Application
3.启动过程
3.1init进程的启动
system/core/init/main.cpp
main函数的执行顺序:
- (1)ueventd_main: init进程创建子进程ueventd,创建设备节点文件的工作托付给ueventd,ueventd通过两种方式创建设备节点文件
- (2)FirstStageMain 启动第一阶段 创建文件并挂载
- (3)SetupSelinux 加载selinux规则,并设置selinux日志,完成SELinux相关工作
- (4)SecondStageMain 启动第二阶段
- 具体方法的调用均在system/core/init/路径下,这里不再贴代码。
int main(int argc, char** argv) { #if __has_feature(address_sanitizer) __asan_set_error_report_callback(AsanReportCallback); #endif if (!strcmp(basename(argv[0]), "ueventd")) { return ueventd_main(argc, argv); // ueventd.cpp } 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); //subcontext.cpp } if (!strcmp(argv[1], "selinux_setup")) { return SetupSelinux(argv); //selinux.cpp } if (!strcmp(argv[1], "second_stage")) { return SecondStageMain(argc, argv); //文件为 init.cpp } } return FirstStageMain(argc, argv); //文件为first_stage_init.cpp }
system\core\init\first_stage_init.cpp
int FirstStageMain(int argc, char** argv) { boot_clock::time_point start_time = boot_clock::now(); #define CHECKCALL(x) \ if (x != 0) errors.emplace_back(#x " failed", errno); // Clear the umask. umask(0); //初始化系统环境变量 CHECKCALL(clearenv()); CHECKCALL(setenv("PATH", _PATH_DEFPATH, 1)); // 挂载及创建基本的文件系统,并设置合适的访问权限 CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755")); CHECKCALL(mkdir("/dev/pts", 0755)); CHECKCALL(mkdir("/dev/socket", 0755)); CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL)); #define MAKE_STR(x) __STRING(x) CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC))); #undef MAKE_STR // 不要将原始命令行公开给非特权进程 CHECKCALL(chmod("/proc/cmdline", 0440)); gid_t groups[] = {AID_READPROC}; CHECKCALL(setgroups(arraysize(groups), groups)); CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL)); CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL)); CHECKCALL(mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11))); if constexpr (WORLD_WRITABLE_KMSG) { CHECKCALL(mknod("/dev/kmsg_debug", S_IFCHR | 0622, makedev(1, 11))); } //创建linux随机伪设备文件 CHECKCALL(mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8))); CHECKCALL(mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9))); //log wrapper所必须的,需要在ueventd运行之前被调用 CHECKCALL(mknod("/dev/ptmx", S_IFCHR | 0666, makedev(5, 2))); CHECKCALL(mknod("/dev/null", S_IFCHR | 0666, makedev(1, 3))); ... //将内核的stdin/stdout/stderr 全都重定向/dev/null,关闭默认控制台输出 SetStdioToDevNull(argv); // tmpfs已经挂载到/dev上,同时我们也挂载了/dev/kmsg,我们能够与外界开始沟通了 //初始化内核log InitKernelLogging(argv); //检测上面的操作是否发生了错误 if (!errors.empty()) { for (const auto& [error_string, error_errno] : errors) { LOG(ERROR) << error_string << " " << strerror(error_errno); } LOG(FATAL) << "Init encountered errors starting first stage, aborting"; } LOG(INFO) << "init first stage started!"; auto old_root_dir = std::unique_ptr<DIR, decltype(&closedir)>{opendir("/"), closedir}; if (!old_root_dir) { PLOG(ERROR) << "Could not opendir("/"), not freeing ramdisk"; } struct stat old_root_info; ... //挂载 system、cache、data 等系统分区 if (!DoFirstStageMount()) { LOG(FATAL) << "Failed to mount required partitions early ..."; } ... //进入下一步,SetupSelinux const char* path = "/system/bin/init"; const char* args[] = {path, "selinux_setup", nullptr}; execv(path, const_cast<char**>(args)); return 1; }
FirstStageMain到底做了哪些重要的事情:
- 挂载及创建基本的文件系统,并设置合适的访问权限
- 关闭默认控制台输出,并初始化内核级log。
- 挂载 system、cache、data 等系统分区
system\core\init\selinux.cpp
int SetupSelinux(char** argv) { SetStdioToDevNull(argv); InitKernelLogging(argv); if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); } boot_clock::time_point start_time = boot_clock::now(); MountMissingSystemPartitions(); SelinuxSetupKernelLogging(); LOG(INFO) << "Opening SELinux policy"; // Read the policy before potentially killing snapuserd. std::string policy; ReadPolicy(&policy); auto snapuserd_helper = SnapuserdSelinuxHelper::CreateIfNeeded(); if (snapuserd_helper) { // Kill the old snapused to avoid audit messages. After this we cannot // read from /system (or other dynamic partitions) until we call // FinishTransition(). snapuserd_helper->StartTransition(); } LoadSelinuxPolicy(policy); if (snapuserd_helper) { // Before enforcing, finish the pending snapuserd transition. snapuserd_helper->FinishTransition(); snapuserd_helper = nullptr; } SelinuxSetEnforcement(); // We're in the kernel domain and want to transition to the init domain. File systems that // store SELabels in their xattrs, such as ext4 do not need an explicit restorecon here, // but other file systems do. In particular, this is needed for ramdisks such as the // recovery image for A/B devices. if (selinux_android_restorecon("/system/bin/init", 0) == -1) { PLOG(FATAL) << "restorecon failed of /system/bin/init failed"; } setenv(kEnvSelinuxStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1); 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; }
SecondStageMain的关键代码为:
PropertyInit();对属性进行初始化 StartPropertyService(&property_fd);启动属性服务 LoadBootScripts(am, sm);解析init.rc init.rc的文件为 system/core/rootdir/init.zygote64.rc
总结一下,第二阶段做了以下这些比较重要的事情:
- 初始化属性的服务,并从指定文件读取属性
- 初始化epoll,并注册signalfd和property_set_fd,建立和init的子进程以及部分服务的通讯桥梁
- 初始化设备组合键,使系统能够对组合键信号做出响应
- 解析init.rc文件,并按rc里的定义去启动服务
- 开启死循环,用于接收epoll的事件
init.zygote64.rc的代码为:
其中service用于通知init进程创建名zygote的进程,这个zygote进程执行程序的路径为/system/bin/app_process64,后面的则是要传给app_process64的参数。
service zygote /system/bin/app_process64 -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 netd onrestart restart wificond writepid /dev/cpuset/foreground/tasks
system\core\rootdir\init.rc 启动zygote进程
on nonencrypted class_start main 启动zygote进程 class_start late_start
class_start是一个COMMAND,对应的函数为system\core\init\builtins.cpp下的do_class_start
static Result<void> do_class_start(const BuiltinArguments& args) { // Do not start a class if it has a property persist.dont_start_class.CLASS set to 1. if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false)) return {}; // Starting a class does not start services which are explicitly disabled. // They must be started individually. for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count(args[1])) { if (auto result = service->StartIfNotDisabled(); !result.ok()) { LOG(ERROR) << "Could not start service '" << service->name() << "' as part of class '" << args[1] << "': " << result.error(); } } } return {}; }
StartIfNotDisabled()方法位于system\core\init\service.cpp下
Result<void> Service::StartIfNotDisabled() {
if (!(flags_ & SVC_DISABLED)) {
return Start();
} else {
flags_ |= SVC_DISABLED_START;
}
return {};
}
Start方法的关键代码为:
if (flags_ & SVC_RUNNING) {//如果Service已经运行,则不启动 if ((flags_ & SVC_ONESHOT) && disabled) { flags_ |= SVC_RESTART; } // It is not an error to try to start a service that is already running. reboot_on_failure.Disable(); return {}; } //判断需要启动的Service的对应的执行文件是否存在,不存在则不启动该Service struct stat sb; if (stat(args_[0].c_str(), &sb) == -1) { flags_ |= SVC_DISABLED; return ErrnoError() << "Cannot find '" << args_[0] << "'"; } pid_t pid = -1; if (namespaces_.flags) { pid = clone(nullptr, nullptr, namespaces_.flags | SIGCHLD, nullptr); } else { pid = fork();/1.fork函数创建子进程 } if (pid == 0) {//运行在子进程中 umask(077); } ExpandArgsAndExecv(args_, sigstop_) //通过execve执行system/bin/app_process
这样就会进入framework/base/cmds/app_process/app_main.cpp的main函数
if (zygote) { runtime.start("com.android.internal.os.ZygoteInit", args, zygote); 启动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."); }
属性的初始化
文件位于 system\core\init\property_service.cpp
void PropertyInit() { selinux_callback cb; cb.func_audit = PropertyAuditCallback; selinux_set_callback(SELINUX_CB_AUDIT, cb); mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH); CreateSerializedPropertyInfo(); if (__system_property_area_init()) { LOG(FATAL) << "Failed to initialize property area"; } if (!property_info_area.LoadDefaultPath()) { LOG(FATAL) << "Failed to load serialized property info file"; } // If arguments are passed both on the command line and in DT, // properties set in DT always have priority over the command-line ones. ProcessKernelDt(); ProcessKernelCmdline(); // Propagate the kernel variables to internal variables // used by init as well as the current required properties. ExportKernelBootProps(); PropertyLoadBootDefaults(); }
启动属性服务
void StartPropertyService(int* epoll_socket) { InitPropertySet("ro.property_service.version", "2"); int sockets[2]; if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) { PLOG(FATAL) << "Failed to socketpair() between property_service and init"; } *epoll_socket = from_init_socket = sockets[0]; init_socket = sockets[1]; StartSendingMessages(); //创建非阻塞的socket if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,false, 0666, 0, 0, {}); result.ok()) { property_set_fd = *result; } else { LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); } //调用listen函数对property_set_fd进行监听,这样创建的socket就成为了server,也就是属性服务;listen函数的第二个参数设置8意味着属性服务最多可以同时为8个试图设置属性的用户提供服务 listen(property_set_fd, 8); //创建PropertyServiceThread auto new_thread = std::thread{PropertyServiceThread}; property_service_thread.swap(new_thread); }
PropertyServiceThread关键代码为:
property_set_fd放入了epoll句柄中,用epoll来监听property_set_fd:当property_set_fd中有数据到来时,init进程将用handle_property_set_fd函数进行处理。
在linux新的内核中,epoll用来替换select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为内核中的select实现是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。
if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result.ok()) { LOG(FATAL) << result.error(); }
handle_property_set_fd的关键代码为
case PROP_MSG_SETPROP: { char prop_name[PROP_NAME_MAX]; char prop_value[PROP_VALUE_MAX]; if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) || !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) { PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket"; return; } prop_name[PROP_NAME_MAX-1] = 0; prop_value[PROP_VALUE_MAX-1] = 0; std::string source_context; if (!socket.GetSourceContext(&source_context)) { PLOG(ERROR) << "Unable to set property '" << prop_name << "': getpeercon() failed"; return; } const auto& cr = socket.cred(); std::string error; //设置属性,会对权限进行判断 uint32_t result = HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error); if (result != PROP_SUCCESS) { LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; } break; }
HandlePropertySet 代码如下:
uint32_t HandlePropertySet(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr, SocketConnection* socket, std::string* error) { //检查权限 if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) { return ret; } if (StartsWith(name, "ctl.")) { return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error); } // sys.powerctl is a special property that is used to make the device reboot. We want to log // any process that sets this property to be able to accurately blame the cause of a shutdown. if (name == "sys.powerctl") { std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid); std::string process_cmdline; std::string process_log_string; if (ReadFileToString(cmdline_path, &process_cmdline)) { // Since cmdline is null deliminated, .c_str() conveniently gives us just the process // path. process_log_string = StringPrintf(" (%s)", process_cmdline.c_str()); } LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid << process_log_string; if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) { *error = "Userspace reboot is not supported by this device"; return PROP_ERROR_INVALID_VALUE; } } // If a process other than init is writing a non-empty value, it means that process is // requesting that init performs a restorecon operation on the path specified by 'value'. // We use a thread to do this restorecon operation to prevent holding up init, as it may take // a long time to complete. if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) { static AsyncRestorecon async_restorecon; async_restorecon.TriggerRestorecon(value); return PROP_SUCCESS; } //设置属性 return PropertySet(name, value, error); }
PropertySet关键代码为:
static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) { size_t valuelen = value.size(); if (!IsLegalPropertyName(name)) { *error = "Illegal property name"; return PROP_ERROR_INVALID_NAME; } if (auto result = IsLegalPropertyValue(name, value); !result.ok()) { *error = result.error().message(); return PROP_ERROR_INVALID_VALUE; } //从属性存储空间查找该属性 prop_info* pi = (prop_info*) __system_property_find(name.c_str()); //如果属性存在 if (pi != nullptr) { // ro.* properties are actually "write-once". //如果属性以"ro."开头,则表示是只读,不能修改,直接返回 if (StartsWith(name, "ro.")) { *error = "Read-only property was already set"; return PROP_ERROR_READ_ONLY_PROPERTY; } //更新属性值 __system_property_update(pi, value.c_str(), valuelen); } else { //如果属性不存在则添加该属性 int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen); if (rc < 0) { *error = "__system_property_add failed"; return PROP_ERROR_SET_FAILED; } } // Don't write properties to disk until after we have read all default // properties to prevent them from being overwritten by default values. if (persistent_properties_loaded && StartsWith(name, "persist.")) { WritePersistentProperty(name, value); } // If init hasn't started its main loop, then it won't be handling property changed messages // anyway, so there's no need to try to send them. auto lock = std::lock_guard{accept_messages_lock}; if (accept_messages) { PropertyChanged(name, value); } return PROP_SUCCESS; }
总结起来init进程主要做了三件事:
1.创建一些文件夹并挂载设备
2.初始化和启动属性服务
3.解析init.rc配置文件并启动zygote进程