赞
踩
文章托管在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权限,这点需要注意。接下来分析这两个命令的执行流程。
在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是一个可执行程序,它的实现在 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函数实际上也是从这里进入的。执行 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; }
从上面
/// @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);
}
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; }
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); } } }
通过设置控制属性 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的属性服务中处理设置属性请求,该实现在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);
}
...
}
/// @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_guard{accept_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; }
/// @system/core/init/init.cpp
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) { // 队列待处理任务大于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;
}
如下是 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; }
处理控制消息。 一次只处理一个事件,防止占用过多时间,导致其他事件得不得处理
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(); } }
处理一条控制消息
/// @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) << "Control message: Processed ctl." << message << " for '" << name << "' from pid: " << from_pid << " (" << process_cmdline << ")"; return true; }
从上面的分析可知,设置 ctl.start 会调用 do_start 去启动服务,设置 ctl.start 则会调用 do_stop 去停止服务。
/// @system/core/init/builtins.cpp
static Result<void> do_start(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]); // 寻找指定名字的服务
if (!svc) return Error() << "service " << args[1] << " not found";
if (auto result = svc->Start(); !result.ok()) { // 调用Service的Start函数启动服务
return ErrorIgnoreEnoent() << "Could not start service: " << result.error();
}
return {};
}
Service::Start 方法在 init(4) 子进程回收与服务重启分析 已分析过,此处不再赘述。
/// @system/core/init/builtins.cpp
static Result<void> do_stop(const BuiltinArguments& args) {
Service* svc = ServiceList::GetInstance().FindService(args[1]);
if (!svc) return Error() << "service " << args[1] << " not found";
svc->Stop(); // 调用 Service::Stop 函数
return {};
}
/// @system/core/init/service.cpp
void Service::Stop() {
StopOrReset(SVC_DISABLED); // 继续调用StopOrReset,注意传入的how值是 SVC_DISABLED
}
停止服务逻辑,注意传入的how值是 SVC_DISABLED
// The how field should be either SVC_DISABLED, SVC_RESET, or SVC_RESTART. void Service::StopOrReset(int how) { // The service is still SVC_RUNNING until its process exits, but if it has // already exited it shoudn't attempt a restart yet. flags_ &= ~(SVC_RESTARTING | SVC_DISABLED_START); // 先移除需要启动标记 if ((how != SVC_DISABLED) && (how != SVC_RESET) && (how != SVC_RESTART)) {// 不是这三个则设置为SVC_DISABLED // An illegal flag: default to SVC_DISABLED. how = SVC_DISABLED; } // If the service has not yet started, prevent it from auto-starting with its class. if (how == SVC_RESET) { flags_ |= (flags_ & SVC_RC_DISABLED) ? SVC_DISABLED : SVC_RESET; } else { flags_ |= how; // 此情景走此逻辑,添加了SVC_DISABLED 到flag } // Make sure it's in right status when a restart immediately follow a // stop/reset or vice versa. if (how == SVC_RESTART) { flags_ &= (~(SVC_DISABLED | SVC_RESET)); } else { flags_ &= (~SVC_RESTART); // 此情景走此逻辑 } if (pid_) { // 杀死进程组 KillProcessGroup(SIGKILL); NotifyStateChange("stopping"); } else { NotifyStateChange("stopped"); } }
从上面的分析看,指定了SVC_DISABLED 则会移除 SVC_RESTART, 当进程被杀死init进行进程回收时,调用Service::Reap函数则不会再重新启动服务了(关于服务重启参考 init(4) 子进程回收与服务重启分析 。),和服务异常退出会重启不同,我们简单看一下代码:
void Service::Reap(const siginfo_t& siginfo) { ... pid_ = 0; flags_ &= (~SVC_RUNNING); start_order_ = 0; ... // Disabled and reset processes do not get restarted automatically. if (flags_ & (SVC_DISABLED | SVC_RESET)) { // 当flag包含SVC_DISABLED,则不会往下走了,也就不会重启了。 NotifyStateChange("stopped"); return; } ... flags_ &= (~SVC_RESTART); flags_ |= SVC_RESTARTING; // 此处标记才会去重启服务 // Execute all onrestart commands for this service. onrestart_.ExecuteAllCommands(); NotifyStateChange("restarting"); return; }
start/stop命令的实现大致分为如下几步:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。