首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

  • 24-12-05 23:45
  • 4104
  • 7714
juejin.cn

最近在学习Android Framework相关的东西,很多内容都与Android系统启动关系密切,因此需要特地记录。其中init进程是Andorid系统中用户空间的第一个进程,进程号为1,是Android系统启动流程中比较关键的步骤。

init进程由多个源文件共同组成,这个文件位于源码目录system/core/init中。

环境参数:

  • android-14.0.0_r27
  • Ubuntu 22.04.5 LTS

在线源码网址:xrefandroid

init进程的定位

了解init进程,就需要先了解Android系统启动的前几步,从而找到init进程在系统中的定位。

Android系统的启动主要分为5个步骤:

  • Loader → Kernel → Native → Framework → Application

上图是网上某大佬总结,借鉴重新绘制了下加深印象=。=

Loader

  • Boot ROM:当我们按下电源,引导芯片代码会从预定义的位置(固化在ROM中)开始执行,加载引导程序BootLoader到RAM中,然后执行。
  • Boot Loader:引导操作系统启动,把系统OS拉起来,是Android操作系统开始运行前的一个小程序,主要功能由检查RAM,初始化硬件外设参数等功能。

Kernel

Android内核层,系统的发起点。

  • swapper进程也称为交换(idle)进程由系统自动创建,运行在内核态,进程id为0,是系统创建的第一个进程,也是唯一一个没有通过fork或者kernel_thread产生的进程。用于初始化进程管理,内存管理,加载Camera,Binder,Display,Input等驱动工作。
  • kthreadd进程是idle通过kernel_thread创建,进程id为2,始终运行在内核空间,主要是负责内核线程的调度和管理。

Native

Native层,也就是Framework层中C++的那一部分,主要包括由init进程孵化出的用户进程,HAL层,Binder的管理者ServiceManager以及启动动画,Media Server等。

  • init进程是idle通过kernel_thread创建,在内核空间完成初始化,加载init进程,最后转变为用户空间的init进程,是其他所有用户进程的鼻祖。
  • HAL层是硬件和软件之间的桥梁。Android把对硬件的操作分成了两部分,HAL和内核驱动,HAL实现在用户空间,驱动在内核空间。Linux内核中的代码需要开源,用户空间不需要,因此这样可以保护厂家的利益。
  • Media Server由init进程fork而来,负责启动和管理AudioFlinger,MediaPlayerService等服务。

Framework

Framework层中纯Java的那一部分,通过JNI与Native层通信。

  • 启动Zygote进程,加载ZygoteInit类,注册Zygote Socket服务端套接字;加载虚拟机,加载类和系统资源 —— fork出来的进程天生就有自己的虚拟机和系统资源。
  • System Server由Zygote进程fork而来,System Server是Zygote孵化出来的第一个进程,负责启动和管理整个Java Framework,包括AMS,WMS,PMS等

Application

应用层。

  • Launcher是Zygote孵化的第一个App进程
  • 所有的App都是由Zygote孵化而来

从上面的步骤来看,当我们按下电源,系统启动会先加载引导程序,引导程序又去启动Linux内核,开天辟地产生第一个进程swapper,Linux内核加载完成后,首先就是启动init进程。

init进程的启动

init进程是由swapper进程启动的,而swapper进程位于kernel层,因此启动init进程的地方应该位于kernel层:

AOSP目录中没有找到bsp的代码,就找了个线上的:lxr.linux.no/#linux+v6.7…

scss
代码解读
复制代码
@init/main.c asmlinkage __visible void __init start_kernel(void) { char *command_line; char *after_dashes; set_task_stack_end_magic(&init_task); smp_setup_processor_id();//打印了驱动加载的第一行log ... //初始化一系列系统底层机制 pr_notice("%s", linux_banner);//打印内核版本信息 ... pr_notice("Kernel command line: %s\n", saved_command_line);//打印从uboot传递过来的command_line字符串 ... /* Do the rest non-__init'ed, we're now alive */ arch_call_rest_init();//创建init进程、kthread进程、idle进程 prevent_tail_call_optimization(); }

arch_call_rest_init方法继续往下走:

scss
代码解读
复制代码
@init/main.c void __init __weak arch_call_rest_init(void) { rest_init(); } noinline void __ref rest_init(void) { ... pid = kernel_thread(kernel_init, NULL, CLONE_FS);//创建init进程 ... pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);//创建kthreadd进程 ... /* Call into cpu_idle with preempt disabled */ cpu_startup_entry(CPUHP_ONLINE);//设置当前进程为idle进程 }

通过kernel_thread创建了init进程,init进程入口函数:system/core/init/main.cpp

arduino
代码解读
复制代码
@system/core/init/main.cpp int main(int argc, char** argv) { ... 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); } if (!strcmp(argv[1], "selinux_setup")) { return SetupSelinux(argv); } if (!strcmp(argv[1], "second_stage")) { return SecondStageMain(argc, argv); } } return FirstStageMain(argc, argv); }

程序根据传递的参数执行对应的方法,根据方法名,首先查看FirstStageMain()的操作:

less
代码解读
复制代码
@system/core/init/first_stage_init.cpp#FirstStageMain int FirstStageMain(int argc, char** argv) { ... // Clear the umask. umask(0); //创建和挂载启动所需要的文件目录 CHECKCALL(mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755")); CHECKCALL(mkdir("/dev/pts", 0755)); CHECKCALL(mkdir("/dev/socket", 0755)); CHECKCALL(mkdir("/dev/dm-user", 0755)); CHECKCALL(mount("devpts", "/dev/pts", "devpts", 0, NULL)); CHECKCALL(mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC))); CHECKCALL(setgroups(arraysize(groups), groups)); CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL)); CHECKCALL(mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL)); ... CHECKCALL(mount("tmpfs", "/mnt", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=1000")); ... //初始化Kernel的Log,这样外界可以获取Kernel的日志 InitKernelLogging(argv); }

这在第一步中,创建和挂载启动需要的文件目录,其中挂载了tmpfs,devpts,proc,sysfs和selinuxfs五种文件系统,这些都是系统运行时候才有的目录,也就是说如果系统没有运行,则不会有这些目录。

再来看SecondStageMain()方法:

scss
代码解读
复制代码
@system/core/init/init.cpp#SecondStageMain int SecondStageMain(int argc, char** argv) { ... //1.初始化属性服务 PropertyInit(); ... //2.初始化子进程终止信号处理函数 Epoll epoll; if (auto result = epoll.Open(); !result.ok()) { PLOG(FATAL) << result.error(); } InstallSignalFdHandler(&epoll); InstallInitNotifier(&epoll); //3.设置其他系统属性并开启系统属性服务 StartPropertyService(&property_fd); ... ActionManager& am = ActionManager::GetInstance(); //单例类ServiceList ServiceList& sm = ServiceList::GetInstance(); //4.解析init.rc等文件,建立rc文件的action 、service LoadBootScripts(am, sm); while (true) { ... if (!IsShuttingDown()) { //注意此处,后续包有用的 HandleControlMessages(); SetUsbController(); } } return 0; }

注释已经比较清楚了:

  • 第一步是初始化属性服务;
  • 第二步主要是为了防止init进程的子进程成为僵尸进程,系统会在子进程暂停和终止的时候发出SIGCHLD信号,而InstallSignalFdHandler函数就是用来接收SIGCHLD信号的。

    比如init进程的子进程Zygote进程终止了,InstallSignalFdHandler函数内部会调用HandleSignalFd函数,经过一系列的调用和处理,最终会找到Zygote进程并且移除所有Zygote进程的信息,再重启Zygote服务的启动脚本(init.Zygote64.rc)中带有onrestart选项的服务。

  • 第三步启动属性服务,监听属性变化,与第一步呼应
  • 第四步解析init.rc文件

总结:init进程的启动源于Kernel,作为第一个用户进程,在入口函数中主要创建和挂载文件目录,初始化和启动了属性服务,解析init.rc文件等。

解析init.rc

init.rc是非常重要的配置文件,文件位于system/core/rootdir/init.rc,它是由Android初始化语言编写的脚本,这种语言包含5种类型语句:Action、Command、Service、Option和Import。

粗略看下init.rc文件:

bash
代码解读
复制代码
@system/core/rootdir/init.rc on init sysclktz 0 # Mix device-specific information into the entropy pool copy /proc/cmdline /dev/urandom copy /system/etc/prop.default /dev/urandom ... on boot # basic network init ifup lo hostname localhost domainname localdomain # Start standard binderized HAL daemons class_start hal class_start core ... on nonencrypted class_start main class_start late_start

其中on init, on boot, on nonencrypted属于Action类型的语句,表示触发时机;下面的class_start main类型的语句属于Command,表示动作触发之后要执行的命令。

需要注意的是从Android8.0开始对init.rc做了拆分,每个服务对应一个rc文件。Zygote启动脚本在init.zygoteXX.rc中定义,其中XX表示为处理器位数,一般我们用init.zygote64.rc:

perl
代码解读
复制代码
@system/core/rootdir/init.zygote64.rc //1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote 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 # NOTE: If the wakelock name here is changed, then also # update it in SystemSuspend.cpp onrestart write /sys/power/wake_lock zygote_kwl onrestart restart audioserver onrestart restart cameraserver onrestart restart media onrestart restart media.tuner onrestart restart netd onrestart restart wificond task_profiles ProcessCapacityHigh MaxPerformance critical window=${zygote.critical_window.minute:-off} target=zygote-fatal

其中注释1这一行,service表示这语句为Service类型, zygote表示service的名字为zygote,/system/bin/app_process64表示进程的程序路径,这一行后面代码都是要传递给app_process64的参数。 下面的参数为Option类型语句,其中class mian表示Zygote此服务的服务类型为main(此点后面会用到)

解析Service类型语句

Service类型语句由ServiceParser来解析,解析实现代码在system/core/init/service_parser.cpp中:

c
代码解读
复制代码
@system/core/init/service_parser.cpp#ParseSection //ParseSection主要用来搭建Service的架子 Result<void> ServiceParser::ParseSection(std::vector<std::string>&& args, const std::string& filename, int line) { if (args.size() < 3) { return Error() << "services must have a name and a program"; } const std::string& name = args[1]; if (!IsValidName(name)) { return Error() << "invalid service name '" << name << "'"; } filename_ = filename; Subcontext* restart_action_subcontext = nullptr; if (subcontext_ && subcontext_->PathMatchesSubcontext(filename)) { restart_action_subcontext = subcontext_; } std::vector<std::string> str_args(args.begin() + 2, args.end()); if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_P__) { if (str_args[0] == "/sbin/watchdogd") { str_args[0] = "/system/bin/watchdogd"; } } if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_Q__) { if (str_args[0] == "/charger") { str_args[0] = "/system/bin/charger"; } } //构建了一个service对象 service_ = std::make_unique(name, restart_action_subcontext, filename, str_args); return {}; } @system/core/init/service_parser.cpp#ParseLineSection //ParseLineSection主要是用来解析子项的 Result<void> ServiceParser::ParseLineSection(std::vector<std::string>&& args, int line) { if (!service_) { return {}; } auto parser = GetParserMap().Find(args); if (!parser.ok()) return parser.error(); return std::invoke(*parser, this, std::move(args)); }

在ParseSection创建service对象,在ParseLineSection解析完所有数据后,就会调用EndSection方法:

scss
代码解读
复制代码
@system/core/init/service_parser.cpp#EndSection Result ServiceParser::EndSection() { if (!service_) { return {}; } if (interface_inheritance_hierarchy_) { if (const auto& check_hierarchy_result = CheckInterfaceInheritanceHierarchy( service_->interfaces(), *interface_inheritance_hierarchy_); !check_hierarchy_result.ok()) { return Error() << check_hierarchy_result.error(); } } if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__) { if ((service_->flags() & SVC_CRITICAL) != 0 && (service_->flags() & SVC_ONESHOT) != 0) { return Error() << "service '" << service_->name() << "' can't be both critical and oneshot"; } } Service* old_service = service_list_->FindService(service_->name()); if (old_service) { if (!service_->is_override()) { return Error() << "ignored duplicate definition of service '" << service_->name() << "'"; } if (StartsWith(filename_, "/apex/") && !old_service->is_updatable()) { return Error() << "cannot update a non-updatable service '" << service_->name() << "' with a config in APEX"; } std::string context = service_->subcontext() ? service_->subcontext()->context() : ""; std::string old_context = old_service->subcontext() ? old_service->subcontext()->context() : ""; if (context != old_context) { return Error() << "service '" << service_->name() << "' overrides another service " << "across the treble boundary."; } service_list_->RemoveService(*old_service); old_service = nullptr; } //1 service_list_->AddService(std::move(service_)); return {}; }

其中注释1处的service_list_->RemoveService(*old_service)会走到单例类ServiceList中去,最终将service_对象添加到vector类型的Service链表中去,位于system/core/init/service_list.cpp

c
代码解读
复制代码
@system/core/init/service_list.h //vector类型的链表 private: std::vector<std::unique_ptr> services_; @system/core/init/service_list.cpp#AddService void ServiceList::AddService(std::unique_ptr service) { services_.emplace_back(std::move(service)); }

总结:其实解析Service语句就是根据参数创建Serice对象,根据选项区域的内容填充Service对象,最后将Service对象加入到vector类型的Service链表中去。

如何启动Service

解析完Service,那如何启动Service呢?在init.rc中有如下配置:

csharp
代码解读
复制代码
@system/core/rootdir/init.rc on boot # basic network init ifup lo hostname localhost domainname localdomain # Start standard binderized HAL daemons class_start hal class_start core on nonencrypted class_start main class_start late_start

其中class_start是一个Command,对应函数为do_class_start。class_start main表示启动那些服务类型为main的Service,class_start core表示启动那些服务类型为core的Service:

比如:

在Zygote进程对应的rc文件中:

perl
代码解读
复制代码
@system/core/rootdir/init.zygote64.rc service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote class main ...

Zygot被定义为main类服务,因此class_start main就是用来启动Zygote的。

在bootanim进程对应的rc文件中:

kotlin
代码解读
复制代码
@frameworks/base/cmds/bootanimation/bootanim.rc service bootanim /system/bin/bootanimation class core animation user graphics group graphics audio //注意 disabled oneshot ioprio rt 0 task_profiles MaxPerformance

bootanim被定义为core类服务,animation表示用途,因此class_start core就是用来启动bootanim的。

do_class_start函数在builtins.cpp中定义:

rust
代码解读
复制代码
@system/core/init/builtins.cpp#do_class_start static Result 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 {}; }

遍历ServiceList,找到classname为main的Zygote执行StartIfNotDisabled方法:

kotlin
代码解读
复制代码
@system/core/init/service.cpp#StartIfNotDisabled Result Service::StartIfNotDisabled() { if (!(flags_ & SVC_DISABLED)) {//注意 return Start(); } else { flags_ |= SVC_DISABLED_START; } return {}; }

其中SVC_DISABLED表示Service没有在其对应的rc文件中设置disable选项,如果没有设置,则会调用Start函数启动该Service,否则就不启动。

bootanim对应的rc文件bootanim.rc中设置有disabled,因此不会直接被启动。 Zygote对应的init.zygote64.rc中并没有设置disable选项,因此可以直接调用Start函数启动。

scss
代码解读
复制代码
@system/core/init/service.cpp#Start Result Service::Start() { ... //如果service已经在运行了,就不启动了 if (flags_ & SVC_RUNNING) { if ((flags_ & SVC_ONESHOT) && disabled) { flags_ |= SVC_RESTART; } LOG(INFO) << "service '" << name_ << "' requested start, but it is already running (flags: " << flags_ << ")"; // It is not an error to try to start a service that is already running. reboot_on_failure.Disable(); return {}; } ... //判断需要启动的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(); } //当前代码逻辑在子进程中运行 if (pid == 0) { umask(077); cgroups_activated.CloseWriteFd(); setsid_finished.CloseReadFd(); //最终执行execv函数,Service子进程被启动 RunService(descriptors, std::move(cgroups_activated), std::move(setsid_finished)); _exit(127); } else { cgroups_activated.CloseReadFd(); setsid_finished.CloseWriteFd(); } if (pid < 0) { pid_ = 0; return ErrnoError() << "Failed to fork"; } ... return {}; }

RunService最终执行到ExpandArgsAndExecv函数:

c
代码解读
复制代码
static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigstop) { std::vector<std::string> expanded_args; std::vector<char*> c_strings; expanded_args.resize(args.size()); c_strings.push_back(const_cast<char*>(args[0].data())); for (std::size_t i = 1; i < args.size(); ++i) { auto expanded_arg = ExpandProps(args[i]); if (!expanded_arg.ok()) { LOG(FATAL) << args[0] << ": cannot expand arguments': " << expanded_arg.error(); } expanded_args[i] = *expanded_arg; c_strings.push_back(expanded_args[i].data()); } c_strings.push_back(nullptr); if (sigstop) { kill(getpid(), SIGSTOP); } return execv(c_strings[0], c_strings.data()) == 0; }

如果当前需要启动的Service是Zygote,进程被启动后,就会进入该Service的main函数中,由Zygote对应的rc文件init.zygote64.rc可知,Zygote执行程序路径为/system/bin/app_process64,对应的文件为app_main.cpp,这样就会进入到app_main.cpp的main函数中:

c
代码解读
复制代码
@frameworks/base/cmds/app_process/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.isEmpty()) { 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。

总结:系统根据rc文件中定义的action,在不同的阶段触发不同的Command,通过class_start xx去启动某一类服务。

为什么执行程序/system/bin/app_process64对应的执行文件是app_main.cpp?

frameworks目录搜索可执行程序名称app_process:

图片.png

查看frameworks/base/cmds/app_process/Android.bp文件

css
代码解读
复制代码
cc_binary { name: "app_process", srcs: ["app_main.cpp"], multilib: { lib32: { suffix: "32", }, lib64: { suffix: "64", }, }, ... }

定义了一个可执行文件app_process,根据不同处理器位数添加不同的后缀,其入口文件为app_main.cpp。

属性服务

init进程启动的时候就会去启动属性服务,并且会为其分配内存,用来存储这些属性,如果需要直接读取就可以了。init.cpp中关于属性服务的入口代码:

scss
代码解读
复制代码
@system/core/init/init.cpp#SecondStageMain PropertyInit(); StartPropertyService(&property_fd);

这两行代码分别是用来初始化属性服务和启动属性服务的。先来看PropertyInit函数

scss
代码解读
复制代码
@system/core/init/property_service.cpp#PropertyInit 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(); ProcessBootconfig(); // Propagate the kernel variables to internal variables // used by init as well as the current required properties. ExportKernelBootProps(); PropertyLoadBootDefaults(); }

PropertyInit函数主要就是用来初始化属性内存区域的。那如何启动属性服务的呢

ini
代码解读
复制代码
@system/core/init/property_service.cpp#StartPropertyService void StartPropertyService(int* epoll_socket) { InitPropertySet("ro.property_service.version", "2");//设置属性服务的版本为2 int sockets[2]; //创建一对套接字用于属性服务和init进程之间通信 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, /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0, /*gid=*/0, /*socketcon=*/{}); result.ok()) { property_set_fd = *result; } else { LOG(FATAL) << "start_property_service socket creation failed: " << result.error(); } //监听property_set_fd,最大连接数为8 listen(property_set_fd, 8); //创建线程执行,执行函数为PropertyServiceThread auto new_thread = std::thread{PropertyServiceThread}; property_service_thread.swap(new_thread); ... }

PropertyServiceThread函数执行逻辑:

scss
代码解读
复制代码
@system/core/init/property_service.cpp#PropertyServiceThread static void PropertyServiceThread() { Epoll epoll; if (auto result = epoll.Open(); !result.ok()) { LOG(FATAL) << result.error(); } //1 if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd); !result.ok()) { LOG(FATAL) << result.error(); } if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) { LOG(FATAL) << result.error(); } while (true) { auto epoll_result = epoll.Wait(std::nullopt); if (!epoll_result.ok()) { LOG(ERROR) << epoll_result.error(); } } }

在注释1处,将property_set_fd放入epoll中,用epoll监听property_set_fd,当property_set_fd有数据来到时,init进程将调用handle_property_set_fd函数来进行处理。handle_property_set_fd函数最终会执行到HandlePropertySet函数:

c
代码解读
复制代码
std::optional<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}; } //如果是ctl开头,则发送控制信息 if (StartsWith(name, "ctl.")) { return {SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error)}; } 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)) { 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 (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) { static AsyncRestorecon async_restorecon; async_restorecon.TriggerRestorecon(value); return {PROP_SUCCESS}; } return PropertySet(name, value, socket, error); }

ctl开头的属于控制属性需要特殊处理,属性sys.powerctl跟重启关机相关,需要记录谁来设置的。其他属性则调用PropertySet来设置。

普通属性时,则调用PropertySet方法来设置

scss
代码解读
复制代码
@system/core/init/property_service.cpp?#PropertySet static std::optional PropertySet(const std::string& name, const std::string& value, SocketConnection* socket, 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". 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. //特殊处理名称开头为persist.的属性 if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { if (persist_write_thread) { persist_write_thread->Write(name, value, std::move(*socket)); return {}; } WritePersistentProperty(name, value); } NotifyPropertyChange(name, value); return {PROP_SUCCESS}; }

如果是控制属性,则会调用SendControlMessage方法,最终会走到QueueControlMessage方法:

c
代码解读
复制代码
@system/core/init/init.cpp#QueueControlMessage static std::queue pending_control_messages; bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd) { auto lock = std::lock_guard{pending_control_messages_lock}; if (pending_control_messages.size() > 100) { LOG(ERROR) << "Too many pending control messages, dropped '" << message << "' for '" << name << "' from pid: " << pid; return false; } pending_control_messages.push({message, name, pid, fd}); WakeMainInitThread(); return true; }

在QueueControlMessage方法中,会将控制属性放入pending_control_messages中,pending_control_messages为一个队列。

在上面init进程入口函数SecondStageMain()中,有一个while循环,里面会不断执行HandleControlMessages方法:

scss
代码解读
复制代码
@system/core/init/init.cpp#HandleControlMessages static void HandleControlMessages() { auto lock = std::unique_lock{pending_control_messages_lock}; // Init historically would only execute handle one property message, including control messages // in each iteration of its main loop. We retain this behavior here to prevent starvation of // other actions in the main loop. if (!pending_control_messages.empty()) { //消费 auto control_message = pending_control_messages.front(); pending_control_messages.pop(); lock.unlock(); bool success = HandleControlMessage(control_message.message, control_message.name, control_message.pid); uint32_t response = success ? PROP_SUCCESS : PROP_ERROR_HANDLE_CONTROL_MESSAGE; if (control_message.fd != -1) { TEMP_FAILURE_RETRY(send(control_message.fd, &response, sizeof(response), 0)); close(control_message.fd); } lock.lock(); } // If we still have items to process, make sure we wake back up to do so. if (!pending_control_messages.empty()) { WakeMainInitThread(); } }

在此函数中,恰好会对队列pending_control_messages执行pop操作,然后通过HandleControlMessage(control_message.message, control_message.name,control_message.pid)函数进行消费:

c
代码解读
复制代码
@system/core/init/init.cpp#HandleControlMessage static bool HandleControlMessage(std::string_view message, const std::string& name, pid_t from_pid) { std::string cmdline_path = StringPrintf("proc/%d/cmdline", from_pid); std::string process_cmdline; if (ReadFileToString(cmdline_path, &process_cmdline)) { std::replace(process_cmdline.begin(), process_cmdline.end(), '\0', ' '); process_cmdline = Trim(process_cmdline); } else { process_cmdline = "unknown process"; } auto action = message; if (ConsumePrefix(&action, "apex_")) { if (auto result = HandleApexControlMessage(action, name, message); !result.ok()) { LOG(ERROR) << "Control message: Could not ctl." << message << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << "): " << result.error(); return false; } LOG(INFO) << "Control message: Processed ctl." << message << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << ")"; return true; } //1 Service* service = nullptr; if (ConsumePrefix(&action, "interface_")) { service = ServiceList::GetInstance().FindInterface(name); } else { service = ServiceList::GetInstance().FindService(name); } if (service == nullptr) { LOG(ERROR) << "Control message: Could not find '" << name << "' for ctl." << message << " from pid: " << from_pid << " (" << process_cmdline << ")"; return false; } const auto& map = GetControlMessageMap(); const auto it = map.find(action); if (it == map.end()) { LOG(ERROR) << "Unknown control msg '" << message << "'"; return false; } const auto& function = it->second; if (auto result = function(service); !result.ok()) { LOG(ERROR) << "Control message: Could not ctl." << message << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << "): " << result.error(); return false; } LOG(INFO) << "Control message: Processed ctl." << message << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << ")"; return true; }

在注释1处,通过name在单例ServiceList中寻找对应service,然后在GetControlMessageMap方法返回 数据中查找对应的操作,执行对应的方法。

c
代码解读
复制代码
@system/core/init/init.cpp#GetControlMessageMap static const std::map<std::string, ControlMessageFunction, std::less<>>& GetControlMessageMap() { // clang-format off static const std::map<std::string, ControlMessageFunction, std::less<>> control_message_functions = { {"sigstop_on", [](auto* service) { service->set_sigstop(true); return Result<void>{}; }}, {"sigstop_off", [](auto* service) { service->set_sigstop(false); return Result<void>{}; }}, {"oneshot_on", [](auto* service) { service->set_oneshot(true); return Result<void>{}; }}, {"oneshot_off", [](auto* service) { service->set_oneshot(false); return Result<void>{}; }}, {"start", DoControlStart}, {"stop", DoControlStop}, {"restart", DoControlRestart}, }; // clang-format on return control_message_functions; }

比如:

关于开机动画的一个例子,修改了系统属性就能通知init进程去启动bootanim

当系统需要显示开机动画时,surfaceflinger进程会修改系统属性来启动bootanim:

java
代码解读
复制代码
@frameworks/native/services/surfaceflinger/StartPropertySetThread.cpp#threadLoop property_set("ctl.start", "bootanim");

init进程启动的属性服务会收到ctl.start控制属性的变化,最终会将此属性放入pending_control_messages队列中;而init进程会不断执行HandleControlMessages方法去消费pending_control_messages队列中的数据,先在ServiceList中找到对应的服务,ctl.start控制属性通过GetControlMessageMap方法的对照,可知最后执行的function(service)为DoControlStart(bootanim)

csharp
代码解读
复制代码
@system/core/init/init.cpp#DoControlStart static Result<void> DoControlStart(Service* service) { return service->Start(); }

调用service的start方法,bootanim服务启动。

总结

init进程启动做了很多工作,主要3件事:

  • 创建和挂载启动需要的文件目录
  • 初始化并启动属性服务
  • 解析init.rc配置文件并且启动Zygote进程
注:本文转载自juejin.cn的抛空的文章"https://juejin.cn/post/7444467898390003766"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

140
Android
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top