浅谈OpenHarmony之appspawn应用孵化器组件
前言
在往期笔记中,通过小型系统启动日志梳理了 OHOS 的启动流程,并认识到可以从 init 进程拉起的相关服务进程进一步探究 OHOS 世界。本篇笔记则是对 appspawn 进程的初步探究
其官方仓为 https://gitee.com/openharmony/startup_appspawn_lite/tree/master
源码分析
从参考资料可以知道,appspawn 应用孵化器组件其功能如其名,就是用来启动 OHOS app 的。appspawn 的源码其实很少,因此本篇笔记不会很长。具体地,需要对 samgr 系统服务框架有所了解,因为 appspawn 启动后,是作为 appspawn service 对外提供服务的。在往期博文中,笔者对 samgr 相关内容也做了简单梳理。
代码目录
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 自己创建进程的好处应该是能够更好地进行权限控制。