> 文档中心 > 浅谈OpenHarmony之appspawn应用孵化器组件

浅谈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应用孵化器组件

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", \ 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 自己创建进程的好处应该是能够更好地进行权限控制。