浅谈OpenHarmony之appspawn应用孵化器组件

前言

在往期笔记中,通过小型系统启动日志梳理了 OHOS 的启动流程,并认识到可以从 init 进程拉起的相关服务进程进一步探究 OHOS 世界。本篇笔记则是对 appspawn 进程的初步探究

其官方仓为 https://gitee.com/openharmony/startup_appspawn_lite/tree/master

源码分析

从参考资料可以知道,appspawn 应用孵化器组件其功能如其名,就是用来启动 OHOS app 的。appspawn 的源码其实很少,因此本篇笔记不会很长。具体地,需要对 samgr 系统服务框架有所了解,因为 appspawn 启动后,是作为 appspawn service 对外提供服务的。在往期博文中,笔者对 samgr 相关内容也做了简单梳理。

代码目录

浅谈OpenHarmony之appspawn应用孵化器组件_第1张图片

appspawn 入口函数

appspawn 的入口函数 main 很简单,主要执行了一些初始化,初始化完成后进入死循环

int main(int argc, char * const argv[])
{
    sleep(1);
    HILOG_INFO(HILOG_MODULE_HIVIEW, "[appspawn] main, enter.");

    // 1. ipc module init
    HOS_SystemInit();

    // 2. register signal for SIGCHLD
    SignalRegist();

    // 3. keep process alive
    HILOG_INFO(HILOG_MODULE_HIVIEW, "[appspawn] main, entering wait.");
    while (1) {
        // pause only returns when a signal was caught and the signal-catching function returned.
        // pause only returns -1, no need to process the return value.
        (void)pause();
    }
}

了解 sagmr 服务注册方法可以知道,通过 SYSEX_SERVICE_INIT 可以将服务注册过程置于 main 函数前执行。因此探究 appspawn 执行过程应该从 appspawn_service.c 开始

appspawn 服务注册

AppSpawnInit 完成了 appspawn 服务注册。注册方法都是一样的,只需继承 service 接口,并定义一个 AppSpawnService 类即可,再将其通过 RegisterService 注册到 samgr 中。需要关注的是 service 每个类成员函数的具体实现

startup_appspawn_lite-master\services\src\appspawn_service.c

static AppSpawnService g_appSpawnService = {
    .GetName = GetName,
    .Initialize = Initialize,
    .MessageHandle = MessageHandle,
    .GetTaskConfig = GetTaskConfig,
    SERVER_IPROXY_IMPL_BEGIN,
    .Invoke = Invoke,
    IPROXY_END,
};

void AppSpawnInit(void)
{
    if (SAMGR_GetInstance()->RegisterService((Service *)&g_appSpawnService) != TRUE) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] register service failed!");
        return;
    }

    HILOG_INFO(HILOG_MODULE_HIVIEW, "[appspawn] register service succeed. %{public}p.", &g_appSpawnService);

    if (SAMGR_GetInstance()->RegisterDefaultFeatureApi(APPSPAWN_SERVICE_NAME, \
        GET_IUNKNOWN(g_appSpawnService)) != TRUE) {
        (void)SAMGR_GetInstance()->UnregisterService(APPSPAWN_SERVICE_NAME);
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] register featureapi failed!");
        return;
    }

    HILOG_INFO(HILOG_MODULE_HIVIEW, "[appspawn] register featureapi succeed.");
}

SYSEX_SERVICE_INIT(AppSpawnInit);

主要关注其 Invoke 实现。Invoke 涉及 IServerProxy,因此我们可以知道是与服务的远程调用相关,具体怎么实现远程调用的不做探讨。具体地,先是根据请求 req 调用 GetMessageSt 获取 MessageSt。并根据 MessageSt 调用 CreateProcess 创建一个进程

static int Invoke(IServerProxy* iProxy, int funcId, void* origin, IpcIo* req, IpcIo* reply)
{
	// ---- 省略部分代码 ------
    MessageSt msgSt = {0};
    if (GetMessageSt(&msgSt, req) != EC_SUCCESS) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] invoke, parse failed! reply %{public}d.", INVALID_PID);
        IpcIoPushInt64(reply, INVALID_PID);
        return EC_FAILURE;
    }

    HILOG_INFO(HILOG_MODULE_HIVIEW, "[appspawn] invoke, msg<%{public}s,%{public}s,%{public}d,%{public}d>", \
        msgSt.bundleName, msgSt.identityID, msgSt.uID, msgSt.gID);

    pid_t newPid = CreateProcess(&msgSt);
    FreeMessageSt(&msgSt);
    IpcIoPushInt64(reply, newPid);
	// -------省略部分代码---------
    return ((newPid > 0) ? EC_SUCCESS : EC_FAILURE);
}

进入 CreateProcess 可以看到,该函数首先执行了 fork,创建子进程后在子进程内调用了 AbilityMain,并传入了一个 identityID 。而 AbilityMain 便是 app 框架的入口函数。

pid_t CreateProcess(const MessageSt* msgSt)
{
    pid_t newPID = fork();
    if (newPID < 0) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] create process, fork failed! err %{public}d.", errno);
        return -1;
    }

    // in child process
    if (newPID == 0) {

        // set permissions
        if (SetPerms(msgSt->uID, msgSt->gID, msgSt->capsCnt, msgSt->caps) != 0) {
            HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] sub-process %{public}s exit!", msgSt->bundleName);
            exit(0x7f); // 0x7f: user specified
        }

        (void)prctl(PR_SET_NAME, msgSt->bundleName);

        if (AbilityMain(msgSt->identityID) != 0) {
            HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] AbilityMain execute failed, pid %{public}d.", getpid());
            exit(0x7f); // 0x7f: user specified
        }

        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] sub-process exit, pid %{public}d.", getpid());
        exit(0x7f); // 0x7f: user specified
    }

    return newPID;
}

至此,我们应该能大致清楚 appspawn 为什么称作应用孵化器组件了。同时,我们也可以猜测,执行 app 时会远程调用 appspawn,并将具体地 app 请求发给该服务。触发 appspawn 的 invoke 方法,为该 app 创建一个进程,并执行 AbilityMain。通过 appspawn 间接为 app 创建进程而不是让 app 自己创建进程的好处应该是能够更好地进行权限控制。

你可能感兴趣的:(内核,openharmony)