Android 12 init(5) start&stop命令流程分析

12 篇文章 7 订阅
6 篇文章 3 订阅

文章托管在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_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;
}

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_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;
}

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_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();
    }
}

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) << "Control message: Processed ctl." << message << " for '" << name
              << "' from pid: " << from_pid << " (" << process_cmdline << ")";
    return true;
}

从上面的分析可知,设置 ctl.start 会调用 do_start 去启动服务,设置 ctl.start 则会调用 do_stop 去停止服务。

do_start

/// @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) 子进程回收与服务重启分析 已分析过,此处不再赘述。

do_stop

/// @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
}

Service::StopOrReset

停止服务逻辑,注意传入的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命令的实现大致分为如下几步:

  • 执行start/stop程序,它的本体实际上是toolbox。执行命令可以指定特定服务,表示要启动、停止对应服务
  • start/stop通过设置控制属性 ctl.start、ctl.stop 来启动、停止服务
  • init 处理 ctl.start、ctl.stop属性事件,执行启动、停止服务的操作
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值