【HarmonyOS源码学习系列】应用程序孵化服务

2,395 阅读3分钟

应用孵化服务appspawn

appspawn是应用程序孵化模块,它在系统中以服务进程的形式存在,并且是系统的核心进程之一,它由init进程拉起,用于启动应用程序。它类似于Android操作系统里面的Zygote进程,是所有应用程序进程的父进程。

code-1.0/base/startup/services/appspawn_lite/

模块代码位于上面的路径,下面是编译配置文件。模块编译生成bin档appspawn。模块依赖于liteipc_adapter(ipc driver交互适配层)、samgr(系统能力管理者封装层)、cjson_shared(封装JSON操作的第三方C库)等。

code-1.0/base/startup/services/appspawn_lite/BUILD.gn

executable("appspawn") {
    sources = [
        "src/main.c",
        "src/appspawn_process.c",
        "src/appspawn_service.c",
        "src/appspawn_message.c",
        "src/appspawn_adapter.c",
    ]

    deps = [
        "//third_party/bounds_checking_function:libsec_shared",
        "//foundation/distributedschedule/services/samgr_lite/samgr:samgr",
        "//foundation/communication/frameworks/ipc_lite:liteipc_adapter",
        "//third_party/cJSON:cjson_shared",
    ]
}

appspawn进程载体/壳体逻辑

code-1.0/base/startup/services/appspawn_lite/src/main.c

int main(int argc, char * const argv[])
{
    // 1. ipc module init
    // 这行是关键:启动appspawn服务
    // 这里是调用samgr库里面的函数(非常多的逻辑封装在samgr库里面)
    HOS_SystemInit();

    // 2. register signal for SIGCHLD
    // 捕获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();
    }
}

appspawn服务

code-1.0/base/startup/services/appspawn_lite/include/appspawn_service.h

#define APPSPAWN_SERVICE_NAME "appspawn"

enum APPSPAWN_FUNCID {
    ID_CALL_CREATE_SERVICE = 0,
    ID_CALL_BUT
};

应用孵化服务的名字是appspawn,目前定义实现了一个功能创建服务ID_CALL_CREATE_SERVICE

code-1.0/base/startup/services/appspawn_lite/src/appspawn_service.c

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

遵循系统的服务框架,实现GetName()、Initialize()、MessageHandle()、GetTaskConfig()Invoke()五个接口。

前面四个接口都是常规实现,分别是:返回服务的名字、保存服务的Identity、空实现、返回服务的任务设置。

Invoke()是appspawn服务的核心,也就是appspawn提供的系统能力的具体实现,即启动应用程序。

创建进程

appspawn服务的端点线程从ipc driver收到启动应用的请求消息后,会把消息添加到自己的消息队列。任务处理线程读取到消息之后,会调用Invoke()函数,同时传递消息数据过来。下面就是Invoke()处理数据的过程。

code-1.0/base/startup/services/appspawn_lite/src/appspawn_service.c

static int Invoke(IServerProxy* iProxy, int funcId, void* origin, IpcIo* req, IpcIo* reply)
{
    (void)iProxy;
    (void)origin;
    // 需要返回数据给调用方,所以reply不能为NULL
    if (reply == NULL) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] invoke, reply NULL!");
        return EC_BADPTR;
    }
    // funcId必须为ID_CALL_CREATE_SERVICE,并且请求数据不能为NULL
    if (funcId != ID_CALL_CREATE_SERVICE || req == NULL) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] invoke, funcId %{public}d invalid, reply %{public}d.",\
            funcId, INVALID_PID);
        IpcIoPushInt64(reply, INVALID_PID);
        return EC_BADPTR;
    }
    // 从请求数据构建MessageSt结构体
    BuffPtr* dataPtr = IpcIoPopDataBuff(req);
    MessageSt msgSt = {0};
    int ret = SplitMessage((char*)dataPtr->buff, dataPtr->buffSz, &msgSt);

    // 释放req数据buffer
    if (FreeBuffer(NULL, dataPtr->buff) != LITEIPC_OK) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] invoke, free buffer failed!");
    }

    // 执行创建进程
    pid_t newPid = CreateProcess(&msgSt);
    // 释放msgSt占用的内存
    FreeMessageSt(&msgSt);
    // 把创建的进程的PID返回给调用方
    IpcIoPushInt64(reply, newPid);

    return ((newPid > 0) ? EC_SUCCESS : EC_FAILURE);
}

code-1.0/base/startup/services/appspawn_lite/src/appspawn_process.c

pid_t CreateProcess(const MessageSt* msgSt)
{   // 声明两个变量,用来存放进程的名字和ID
    char identityIDStr[MAX_IDENTITY_ID_LENGTH];
    char processNameStr[MAX_PROCESS_NAME_LENGTH];
    // 变量初始化为空字符串
    if (memset_s(identityIDStr, MAX_IDENTITY_ID_LENGTH, '\0', MAX_IDENTITY_ID_LENGTH) != EOK ||
        memset_s(processNameStr, MAX_PROCESS_NAME_LENGTH, '\0', MAX_PROCESS_NAME_LENGTH) != EOK) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] create service, memset_s failed.");
        return -1;
    }
    // 从msgSt取数据给变量赋值
    if (sprintf_s(identityIDStr, MAX_IDENTITY_ID_LENGTH, "%llu", msgSt->identityID) <= 0 ||
        sprintf_s(processNameStr, MAX_PROCESS_NAME_LENGTH, "%s", msgSt->bundleName) <= 0) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] sprintf_s failed. id %{public}llu, name %{public}s.",\
            msgSt->identityID, msgSt->bundleName);
        return -1;
    }
    // 从msgSt取得LD参数
    char* envStr = GetEnvStrs(msgSt);
    if (envStr == NULL) {
        return -1;
    }

    // 检查exe文件是否存在 abilityMain
    struct stat pathStat = {0};
    if (stat(ABILITY_EXE_FILE_FULL_PATH, &pathStat) != 0) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] stat %{public}s failed, err %{public}d.",\
            ABILITY_EXE_FILE_FULL_PATH, errno);
        free(envStr);
        return -1;
    }
    // 调用fork()创建一个进程
    pid_t newPID = fork();
    if (newPID < 0) {
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] create process, fork failed! err %{public}d.", errno);
        free(envStr);
        return -1;
    }

    // in child process
    if (newPID == 0) {
        // 设置权限
        // 设置进程的用户ID和组ID
        if (SetPerms(msgSt->uID, msgSt->gID) != 0) {
            HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] process %{public}s exit!", processNameStr);
            _exit(0x7f); // 0x7f: user specified
        }

        char* argv[] = {ABILITY_EXE_FILE_NAME, identityIDStr, processNameStr, NULL};
        char* env[] = {envStr, NULL};
        // 执行exe文件abilityMain(在新创建的进程里面)
        if (execve(ABILITY_EXE_FILE_FULL_PATH, argv, env) != 0) {
            HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] execve %{public}s failed! err %{public}d.",\
                ABILITY_EXE_FILE_FULL_PATH, errno);
        }
        HILOG_ERROR(HILOG_MODULE_HIVIEW, "[appspawn] sub-process exit, pid %{public}d.", getpid());
        _exit(0x7f); // 0x7f: user specified
    }

    free(envStr);
    return newPID;
}

小节

  • appspawn是所有应用进程的父进程,所有APP进程都是由appspawn进程fork()而来的。
  • 应用启动请求发起方,通过IPC把要启动的应用的信息通过ipc driver发送给appspawn进程
  • appspawn进程fork()子进程,然后在子进程执行exe文件abilityMain,通过传参数过去
  • 新创建的进程里面运行bin档abilityMain,abilityMain会执行应用程序的逻辑
  • 启动参数包括:应用的名字和ID、LD参数、用户ID和组ID

继续分析,下面进入到abilityMain模块。