Android 12 init start&stop命令流程分析
Posted pecuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 12 init start&stop命令流程分析相关的知识,希望对你有一定的参考价值。
文章托管在gitee上 Android Notes , 同步csdn
本文基于android12 分析
概述
通常,在开发过程中,需要push一些修改到系统分区,之后需要重启系统使修改生效。如果修改的是系统框架相关的,通常可以只重启系统框架,一般在shell下面执行如下命令即可:
pecuyu-PC:~$ adb shell
emulator64_x86_64_arm64:/ $ stop
Must be root
emulator64_x86_64_arm64:/ $ su
emulator64_x86_64_arm64:/ # stop
emulator64_x86_64_arm64:/ # start
不过,执行stop、start命令需要root权限,这点需要注意。接下来分析这两个命令的执行流程。
stop、start程序的实现
在shell里面查看两个命令,发现它们都是软连接,指向的都是 toolbox
$ ls -l /system/bin/stop
lrwxr-xr-x 1 root shell 7 2021-12-20 15:52 /system/bin/stop -> toolbox
$ ls -l /system/bin/start
lrwxr-xr-x 1 root shell 7 2021-12-20 15:52 /system/bin/start -> toolbox
$ ls -lZ /system/bin/toolbox
-rwxr-xr-x 1 root shell u:object_r:toolbox_exec:s0 128984 2021-12-20 15:30 /system/bin/toolbox
toolbox 实现
toolbox是一个可执行程序,它的实现在 system/core/toolbox/
// 声明一系列函数
// 定义TOOL, 在tools.h使用此宏,声明所有工具函数
#define TOOL(name) int name##_main(int, char**); // 如 name##_main -> start_main
#include "tools.h"
#undef TOOL
static struct
const char* name; // 函数名与函数指针
int (*func)(int, char**);
tools[] = // 定义工具列表
#define TOOL(name) #name, name##_main , // 初始化一个结构体, 如 start,start_main ,
#include "tools.h" // 展开并初始化结构体数组
#undef TOOL
0, 0 ,
;
上面导入tools.h头文件,其中调用TOOL来实现功能,可以知道定义了如下工具
/// @system/core/toolbox/tools.h
TOOL(getevent)
TOOL(getprop)
TOOL(modprobe)
TOOL(setprop)
TOOL(start)
TOOL(stop)
TOOL(toolbox)
在shell中执行toolbox,就可以知道有哪些命令,即是上面声明的命令。
$ toolbox
getprop modprobe setprop start stop toolbox
直接执行toolbox调用的是toolbox_main函数
int toolbox_main(int argc, char** argv)
// "toolbox foo ..." is equivalent to "foo ..."
if (argc > 1) // 如果指定参数,调用main继续处理命令
return main(argc - 1, argv + 1);
// Plain "toolbox" lists the tools.
for (size_t i = 1; tools[i].name; i++) // 打印所有命令名
printf("%s%c", tools[i].name, tools[i+1].name ? ' ' : '\\n');
return 0;
toolbox#main
看看toolbox的main函数实现,toolbox_main函数实际上也是从这里进入的。执行 stop/start命令也是从这个main进入,argv[0] 对应是stop/start,根据函数名调用具体的实现函数(stop_main/start_main)。
/// @system/core/toolbox/toolbox.c
int main(int argc, char** argv)
// Let's assume that none of this code handles broken pipes. At least ls,
// ps, and top were broken (though I'd previously added this fix locally
// to top). We exit rather than use SIG_IGN because tools like top will
// just keep on writing to nowhere forever if we don't stop them.
signal(SIGPIPE, SIGPIPE_handler); // 处理SIGPIPE,默认动作exit
char* cmd = strrchr(argv[0], '/'); // 寻找最后一个 /
char* name = cmd ? (cmd + 1) : argv[0]; // 如果存在/ ,则后面是函数名, 否则整体是函数名
for (size_t i = 0; tools[i].name; i++) // 遍历所有的tool,查找名字匹配的
if (!strcmp(tools[i].name, name))
return tools[i].func(argc, argv); // 当name是 start,则调用 start_main
printf("%s: no such tool\\n", argv[0]);
return 127;
stop_main/start_main 实现
从上面
/// @system/core/toolbox/start.cpp
extern "C" int start_main(int argc, char** argv)
return StartStop(argc, argv, true);
extern "C" int stop_main(int argc, char** argv)
return StartStop(argc, argv, false);
StartStop
- 必须在root下执行
- 没有参数, 则去执行 stop、start 所有默认服务,即"netd"、“surfaceflinger”、“audioserver”、“zygote”,
- 指定一个参数为–help,则打印帮助,如 start --help
- 指定了一些服务,则去启动相关服务,比如 start zygote
static int StartStop(int argc, char** argv, bool start)
if (getuid()) // uid 为0 即 root 才能执行
std::cerr << "Must be root" << std::endl;
return EXIT_FAILURE;
if (argc == 1) // 没有参数, 则去执行 stop、start
ControlDefaultServices(start);
if (argc == 2 && argv[1] == "--help"s) // 打印help,如 start --help
std::cout << "usage: " << (start ? "start" : "stop")
<< " [SERVICE...]\\n"
"\\n"
<< (start ? "Starts" : "Stops")
<< " the given system service, or netd/surfaceflinger/zygotes." << std::endl;
return EXIT_SUCCESS;
for (int i = 1; i < argc; ++i) // 指定了某个服务名
ControlService(start, argv[i]);
return EXIT_SUCCESS;
ControlDefaultServices
static void ControlDefaultServices(bool start)
std::vector<std::string> services = // 默认 停止、启动 的服务
"netd",
"surfaceflinger",
"audioserver",
"zygote",
;
// Only start zygote_secondary if not single arch.
std::string zygote_configuration = GetProperty("ro.zygote", ""); // 读取zygote配置
if (zygote_configuration != "zygote32" && zygote_configuration != "zygote64") // 没有指定zygote32或zygote64
services.emplace_back("zygote_secondary");
if (start) // 启动默认服务
for (const auto& service : services)
ControlService(true, service);
else // 停止默认服务
for (auto it = services.crbegin(); it != services.crend(); ++it)
ControlService(false, *it);
ControlService
通过设置控制属性 ctl.start、ctl.stop 来启动、停止服务
static void ControlService(bool start, const std::string& service)
if (!android::base::SetProperty(start ? "ctl.start" : "ctl.stop", service))
std::cerr << "Unable to " << (start ? "start" : "stop") << " service '" << service
<< "'\\nSee dmesg for error reason." << std::endl;
exit(EXIT_FAILURE);
通过init(3) 属性服务 分析可知, init的属性服务将处理该请求。
init 处理属性设置请求
在init的属性服务中处理设置属性请求,该实现在HandlePropertySet函数处理。
/// @system/core/init/property_service.cpp
// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
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.")) // 处理控制属性
// +4 跳过 ctl. , value 表示服务名
return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
...
SendControlMessage
/// @system/core/init/property_service.cpp
static uint32_t SendControlMessage(const std::string& msg, const std::string& name, pid_t pid,
SocketConnection* socket, std::string* error)
auto lock = std::lock_guardaccept_messages_lock;
if (!accept_messages) // 关机过程不再处理
*error = "Received control message after shutdown, ignoring";
return PROP_ERROR_HANDLE_CONTROL_MESSAGE;
// We must release the fd before sending it to init, otherwise there will be a race with init.
// If init calls close() before Release(), then fdsan will see the wrong tag and abort().
int fd = -1;
if (socket != nullptr && SelinuxGetVendorAndroidVersion() > __ANDROID_API_Q__)
fd = socket->Release();
bool queue_success = QueueControlMessage(msg, name, pid, fd); // 控制消息入队等待处理
if (!queue_success && fd != -1) // 回写错误信息
uint32_t response = PROP_ERROR_HANDLE_CONTROL_MESSAGE;
TEMP_FAILURE_RETRY(send(fd, &response, sizeof(response), 0));
close(fd);
return PROP_SUCCESS;
QueueControlMessage
/// @system/core/init/init.cpp
bool QueueControlMessage(const std::string& message, const std::string& name, pid_t pid, int fd)
auto lock = std::lock_guardpending_control_messages_lock;
if (pending_control_messages.size() > 100) // 队列待处理任务大于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;
SecondStageMain 循环处理控制事件
如下是 init 主循环,负责处理相关事件。
/// @system/core/init/main.cpp
int SecondStageMain(int argc, char** argv)
...
while (true)
// By default, sleep until something happens. 计算epool超时
auto epoll_timeout = std::optional<std::chrono::milliseconds>;
...
auto pending_functions = epoll.Wait(epoll_timeout); // WakeMainInitThread导致Wait收到新事件返回
...
if (!IsShuttingDown()) // 不是正在关机,
HandleControlMessages(); // 处理控制消息
SetUsbController();
...
return 0;
HandleControlMessages
处理控制消息。 一次只处理一个事件,防止占用过多时间,导致其他事件得不得处理
static void HandleControlMessages()
auto lock = std::unique_lockpending_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();
HandleControlMessage
处理一条控制消息
/// @system/core/init/init.cpp
static bool HandleControlMessage(std::string_view message, const std::string& name,
pid_t from_pid)
// 获取发起进程的cmdline
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";
Service* service = nullptr;
auto action = message; // action 是 ctl. 后面的部分,比如 ctl.start 则 action 是 start
if (ConsumePrefix(&action, "interface_")) // 比如interface_start、interface_stop 启动aidl型服务
service = ServiceList::GetInstance().FindInterface(name);
else // 启动某个native服务,比如 surfaceflinger
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); // 寻找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()) // 调用对应的函数,start 对应的函数是 do_start
LOG(ERROR) << "Control message: Could not ctl." << message << " for '" << name
<< "' from pid: " << from_pid << " (" << process_cmdline
<< "): " << result.error();
return false;
LOG(INFO以上是关于Android 12 init start&stop命令流程分析的主要内容,如果未能解决你的问题,请参考以下文章
android init.rc中service console option的含义作用
Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, int