最近在学习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:
查看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进程
评论记录:
回复评论: