Openharmony的启动流程
  EzIAYXiV4scN 2023年11月02日 120 0

OpenHarmony启动流程

OpenHarmony 源码网站:

http://ci.openharmony.cn/codeSearch

https://www.lengqinjie.xyz/lxr/source/

一、kernel的启动

流程图:

Openharmony的启动流程_初始化

由于OpenHarmony(下面简称OH)的标准系统的底层系统是linux,所以前期和Android系统的启动没什么太大区别。都是调用到如下的代码:

/kernel/linux/linux-5.10/init/main.c
noinline void __ref rest_init(void)
{
	struct task_struct *tsk;
	int pid;

	rcu_scheduler_starting();
	/*
	 * We need to spawn init first so that it obtains pid 1, however
	 * the init task will end up wanting to create kthreads, which, if
	 * we schedule it before we create kthreadd, will OOPS.
	 */
    //这里和Android一样都是启动init进程
	pid = kernel_thread(kernel_init, NULL, CLONE_FS);
	...
}
static int __ref kernel_init(void *unused)
{
    ...
    //同样的和Android一样都是启动init进程
	if (!try_to_run_init_process("/sbin/init") ||
	    !try_to_run_init_process("/etc/init") ||
	    !try_to_run_init_process("/bin/init") ||
	    !try_to_run_init_process("/bin/sh"))
		return 0;

	panic("No working init found.  Try passing init= option to kernel. "
	      "See Linux Documentation/admin-guide/init.rst for guidance.");
}

由于OH标准系统是基于kernel内核开发的,所以上面的启动和Android是一样的,都是启动了init进程,那么OH的init进程的入口在哪里呢?答案是在

/base/startup/init/services/init/main.c中。

二、init进程的启动

在OH中BUILD.gn就相当于AOSP中的Android.mk或者Android.bp用于编译构建模块的。

/base/startup/init/services/init/standard/BUILD.gn
init_common_sources = [
  "../init_capability.c",
  "../init_common_cmds.c",
  "../init_common_service.c",
  "../init_config.c",
  "../init_group_manager.c",
  "../init_service_file.c",
  "../init_service_manager.c",
  "../init_service_socket.c",
  "../main.c",
]
//编译可执行文件init
ohos_executable("init") {
  sources = [
    "../adapter/init_adapter.c",
    "../standard/device.c",
    "../standard/fd_holder_service.c",
    "../standard/init.c",
    "../standard/init_cmdexecutor.c",
    "../standard/init_cmds.c",
    "../standard/init_control_fd_service.c",
    "../standard/init_jobs.c",
    "../standard/init_mount.c",
    "../standard/init_reboot.c",
    "../standard/init_service.c",
    "../standard/init_signal_handler.c",
    "../standard/switch_root.c",
  ]

  modulemgr_sources = [
    "//base/startup/init/interfaces/innerkits/hookmgr/hookmgr.c",
    "//base/startup/init/interfaces/innerkits/modulemgr/modulemgr.c",
  ]
  sources += modulemgr_sources
  sources += init_common_sources

从上面的BUILD.gn可以看到OH标准系统的init进程的入口就是init_common_sources的main.c也就是下面的代码

/base/startup/init/services/init/main.c
#include <signal.h>
#include "init.h"
#include "init_log.h"

static const pid_t INIT_PROCESS_PID = 1;

int main(int argc, char * const argv[])
{
    int isSecondStage = 0;
    (void)signal(SIGPIPE, SIG_IGN);
    // Number of command line parameters is 2
    //从kernel启动的init进程并未携带任何参数,这里是init的第一阶段
    if (argc == 2 && (strcmp(argv[1], "--second-stage") == 0)) {
        isSecondStage = 1;
    }
    if (getpid() != INIT_PROCESS_PID) {
        INIT_LOGE("Process id error %d!", getpid());
        return 0;
    }
    EnableInitLog(INIT_INFO);
    //第一次这里走的是SystemPrepare
    if (isSecondStage == 0) {
        SystemPrepare();
    } else {
        LogInit();
    }
    SystemInit();
    //启动rcs进程
    SystemExecuteRcs();
    SystemConfig();
    SystemRun();
    return 0;
}

这里很明显是将init进程的代码分成了通用的和特有的两部分,共同的代码均在 /base/startup/init/services/init/文件夹下,在这个文件夹下有两个文件夹lite/和standard/分别用来构建小型系统和标准系统的init进程。我们这里主要分析标准进程的启动流程。由于从kernel进程启动的init进程并未传递任何参数,所以会先执行SystemPrepare,而SystemPrepare有两处实现如下:

/base/startup/init/services/init/lite/
H A D	init.c	49 void SystemPrepare(void) in SystemPrepare() function
/base/startup/init/services/init/standard/
H A D	init.c	223 void SystemPrepare(void) in SystemPrepare() function

我们这里只分析标准系统的流程,所以只看/base/startup/init/services/init/standard/init.c

2.1 SystemPrepare

/base/startup/init/services/init/standard/init.c
  void SystemPrepare(void)
  {
         //挂载一些基本目录并创建一些设备节点
      MountBasicFs();
      CreateDeviceNode();
      LogInit();
      // Make sure init log always output to /dev/kmsg.
      EnableDevKmsg();
      INIT_LOGI("Start init first stage.");
      // Only ohos normal system support
      // two stages of init.
      // If we are in updater mode, only one stage of init.
         //检查是否处于升级模式如果没有处于升级模式就进入init第二阶段
      if (InUpdaterMode() == 0) {
          StartInitSecondStage();
      }
  }
/base/startup/init/services/utils/init_utils.c
  // Check if in updater mode.
  int InUpdaterMode(void)
  {
  #ifdef OHOS_LITE
      return 0;
  #else
      const char * const updaterExecutableFile = "/bin/updater";
      if (access(updaterExecutableFile, X_OK) == 0) {
          return 1;
      } else {
          return 0;
      }
  #endif
  }

SystemPrepare主要就是挂载一些基本目录比如/dev,/mnt,/storage,/dev/pts,/proc,/sys,/sys/fs/selinux,接着创建一些设备节点比如/dev/null,/dev/random,/dev/urandom 等等,接着检查系统是否处于升级模式,如果不处于升级模式就启动init的第二阶段。

2.2 StartInitSecondStage

/base/startup/init/services/init/standard/init.c
static void StartInitSecondStage(void)
{
    int requiredNum = 0;
    //从/proc/cmdline中读取fstab分区表
    Fstab *fstab = LoadRequiredFstab();
    char **devices = (fstab != NULL) ? GetRequiredDevices(*fstab, &requiredNum) : NULL;
    if (devices != NULL && requiredNum > 0) {
        //启动Ueventd进程
        int ret = StartUeventd(devices, requiredNum);
        if (ret == 0) {
            //挂载分区
            ret = MountRequriedPartitions(fstab);
        }
        FreeStringVector(devices, requiredNum);
        devices = NULL;
        ReleaseFstab(fstab);
        fstab = NULL;
        if (ret < 0) {
            // If mount required partitions failure.
            // There is no necessary to continue.
            // Just abort
            INIT_LOGE("Mount required partitions failed; please check fstab file");
            // Execute sh for debugging
#ifndef STARTUP_INIT_TEST
            execv("/bin/sh", NULL);
            abort();
#endif
        }
    }

    if (fstab != NULL) {
        ReleaseFstab(fstab);
        fstab = NULL;
    }
    // It will panic if close stdio before execv("/bin/sh", NULL)
    CloseStdio();
    //启动init进程的第二阶段
    INIT_LOGI("Start init second stage.");
    SwitchRoot("/usr");
    // Execute init second stage
    char * const args[] = {
        "/bin/init",
        "--second-stage",
        NULL,
    };
    //启动init进程并传递参数--second-stage 
    if (execv("/bin/init", args) != 0) {
        INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);
        exit(-1);
    }
}

StartInitSecondStage函数主要就是读取分区表并挂载同时启动Ueventd进程接着再次调用init并传递--second-stage参数。这里的执行execv函数将不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只留下进程ID等一些表面上的信息仍保持原样。只有调用失败了,它们才会返回一个-1,从原程序的调用点接着往下执行。所以接下来的都是init第二阶段的执行过程。再次启动init进程后,当然还是走到了/base/startup/init/services/init/main.c不过不同的是由于携带了--second-stage参数,所以会走到LogInit。接着串行执行SystemInit, SystemExecuteRcs,

SystemConfig和SystemRun。下面我们一个一个来看这些函数都干了点啥。

2.3 LogInit

/base/startup/init/services/init/standard/init.c
void LogInit(void)
{
    int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,
        makedev(MEM_MAJOR, DEV_KMSG_MINOR));
    if (ret == 0) {
        OpenLogDevice();
    }
}
/base/startup/init/services/log/init_log.c
#ifdef INIT_DMESG
static int g_fd = -1;
INIT_LOCAL_API void OpenLogDevice(void)
{
    int fd = open("/dev/kmsg", O_WRONLY | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
    if (fd >= 0) {
        g_fd = fd;
    }
    return;
}

可以看到LogInit主要就是创建/dev/kmsg节点并打开设备

2.4 SystemInit

/base/startup/init/services/init/standard/init.c
void SystemInit(void)
{
    //初始化信号量
    SignalInit();

    // Set up a session keyring that all processes will have access to.
    KeyCtrlGetKeyringId(KEY_SPEC_SESSION_KEYRING, 1);
    //初始化socket /dev/unix/socket
    // umask call always succeeds and return the previous mask value which is not needed here
    (void)umask(DEFAULT_UMASK_INIT);
    MakeDirRecursive("/dev/unix/socket", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
    int sock = FdHolderSockInit();
    if (sock >= 0) {
        RegisterFdHoldWatcher(sock);
    }
    InitControlFd();
}

系统初始化相关,注册了两个socket第一个是/dev/unix/socket其对应的处理函数为ProcessFdHoldEvent

第二个socket是/dev/unix/socket/init_control_fd对应的处理函数为 ProcessControlFd

2.5 SystemConfig

/base/startup/init/services/init/standard/init.c
void SystemConfig(void)
{
    INIT_TIMING_STAT timingStat;

    InitSysAdj();
    HOOK_EXEC_OPTIONS options;
    //init 准备阶段
    options.flags = 0;
    options.preHook = InitPreHook;
    options.postHook = InitPostHook;
    InitServiceSpace();
    HookMgrExecute(GetBootStageHookMgr(), INIT_GLOBAL_INIT, (void *)&timingStat, (void *)&options);
    RecordInitBootEvent("init.prepare");

    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, (void *)&timingStat, (void *)&options);
    //初始化参数服务,和Android的属性服务一样
    InitParamService();
    InitParseGroupCfg();
    RegisterBootStateChange(BootStateChange);

    INIT_LOGI("boot init finish.");
    // load SELinux context and policy
    // Do not move position!
    //加载selinux的上下文和策略
    PluginExecCmdByName("loadSelinuxPolicy", "");
    RecordInitBootEvent("init.prepare");
    
    RecordInitBootEvent("init.ParseCfg");
    //加载特殊的参数
    LoadSpecialParam();

    // parse parameters
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, (void *)&timingStat, (void *)&options);
    //加载属性文件
    InitLoadParamFiles();
    // read config
    //读取配置文件
    HookMgrExecute(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, (void *)&timingStat, (void *)&options);
    ReadConfig();
    RecordInitBootEvent("init.ParseCfg");
    INIT_LOGI("boot parse config file done.");
    HookMgrExecute(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, (void *)&timingStat, (void *)&options);

    IsEnableSandbox();
    // execute init
    //触发pre-init阶段命令的执行
    PostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));
    //触发init阶段命令的执行
    PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));
    //启动boot阶段的服务
    TriggerServices(START_MODE_BOOT);
    //触发post-init阶段命令的执行
    PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
    ////启动正常其他的服务
    TriggerServices(START_MODE_NORMAL);
    clock_gettime(CLOCK_MONOTONIC, &(g_bootJob.startTime));
}

这里的SystemConfig做的工作其实和AOSP源码里init进程解析init.rc并启动各种服务做的工作是一样的,不过多了一步启动参数服务并加载参数。

2.5.1 ParamService

ParamService的初始化是调用InitParamService,代码如下:

/base/startup/init/services/param/linux/param_service.c
void InitParamService(void)
{
    PARAM_LOGI("InitParamService pipe: %s.", PIPE_NAME);
    CheckAndCreateDir(PIPE_NAME);
    CheckAndCreateDir(PARAM_STORAGE_PATH"/");
    // param space
    PARAM_WORKSPACE_OPS ops = {0};
    ops.updaterMode = InUpdaterMode();
    // init open log
    ops.logFunc = InitLog;
#ifdef PARAM_SUPPORT_SELINUX
    ops.setfilecon = setfilecon;
#endif
    int ret = InitParamWorkSpace(0, &ops);
    PARAM_CHECK(ret == 0, return, "Init parameter workspace fail");
    ret = InitPersistParamWorkSpace();
    PARAM_CHECK(ret == 0, return, "Init persist parameter workspace fail");
    // param server
    if (g_paramService.serverTask == NULL) {
        ParamStreamInfo info = {};
        info.server = PIPE_NAME;
        info.close = NULL;
        info.recvMessage = NULL;
        info.incomingConnect = OnIncomingConnect;
        //调用ParamServerCreate创建ParamService
        ret = ParamServerCreate(&g_paramService.serverTask, &info);
        PARAM_CHECK(ret == 0, return, "Failed to create server");
    }

    // init trigger space
    ret = InitTriggerWorkSpace();
    PARAM_CHECK(ret == 0, return, "Failed to init trigger");
    RegisterTriggerExec(TRIGGER_PARAM_WAIT, ExecuteWatchTrigger_);
    RegisterTriggerExec(TRIGGER_PARAM_WATCH, ExecuteWatchTrigger_);
}

创建一个ParamServer的StreamServerTask并设置给g_paramService的serverTask中客户端的连接会通过le_streamtask.c的HandleServerEvent_调用到param_service.c的OnIncomingConnect接着调用 ProcessMessage去处理请求。

接着是调用LoadSpecialParam从/proc/cmdline加载一些参数,并设置一些build相关的参数

void LoadSpecialParam(void)
{
    // read param area size from cfg and save to dac
    LoadParamAreaSize();
    // read selinux label
    LoadSelinuxLabel(NULL);
    // from cmdline
    LoadParamFromCmdLine();
    // from build
    LoadParamFromBuild();
}

最后则是从调用InitLoadParamFiles从/system/etc/param文件夹中加载*.para中的属性。

2.5.2 ReadConfig
/base/startup/init/services/init/init_config.c
void ReadConfig(void)
{
    // parse cfg
    char buffer[32] = {0}; // 32 reason max leb
    uint32_t len = sizeof(buffer);
    SystemReadParam("ohos.boot.reboot_reason", buffer, &len);
    //这里的ohos.boot.reboot_reason是NULL
    INIT_LOGV("ohos.boot.reboot_reason %s", buffer);
    if (strcmp(buffer, "poweroff_charge") == 0) {
        ParseInitCfg(INIT_CONFIGURATION_FILE, NULL);
        ReadFileInDir(OTHER_CHARGE_PATH, ".cfg", ParseInitCfg, NULL);
    } else if (InUpdaterMode() == 0) {
        //正常走这里读取"/etc/init.cfg"
        ParseInitCfg(INIT_CONFIGURATION_FILE, NULL);
        ParseInitCfgByPriority();
    } else {
        ReadFileInDir("/etc", ".cfg", ParseInitCfg, NULL);
    }
}
static void ParseInitCfgContents(const char *cfgName, const cJSON *root)
{
    INIT_ERROR_CHECK(root != NULL, return, "Root is null");
    //解析所有的service
    ParseAllServices(root);
    // parse jobs
    //解析所有的jobs,构造触发器
    ParseAllJobs(root);
    // parse imports
    //解析所有导入的配置文件
    ParseAllImports(root);
}

int ParseInitCfg(const char *configFile, void *context)
{
    UNUSED(context);
    INIT_LOGV("Parse init configs from %s", configFile);
    //读取文件内容
    char *fileBuf = ReadFileToBuf(configFile);
    INIT_ERROR_CHECK(fileBuf != NULL, return -1, "Failed to read file content %s", configFile);
    //将文件转换成json类
    cJSON *fileRoot = cJSON_Parse(fileBuf);
    INIT_ERROR_CHECK(fileRoot != NULL, free(fileBuf);
        return -1, "Failed to parse json file %s", configFile);
    //解析json配置文件
    ParseInitCfgContents(configFile, fileRoot);
    cJSON_Delete(fileRoot);
    free(fileBuf);
    return 0;
}

ReadConfig从/etc/init.cfg读取配置信息,init.cfg其实就是android中init.rc的替代品,主要由三部分构成,import,service,jobs

格式大致如下:

"import" : [
        "/etc/init.usb.cfg",
        "/etc/init.usb.configfs.cfg",
        "/vendor/etc/init.${ohos.boot.hardware}.cfg"
],
"jobs" : [{
        "name" : "pre-init",
        "cmds" : [
            ....
        ]
    }, {
        "name" : "init",
        "cmds" : [
            ....
        ]
    },...
],
 "services" : [{
            "name" : "usb_service",
            "path" : ["/system/bin/sa_main", "/system/profile/usb_service.xml"],
            "ondemand" : true,
            "uid" : "usb",
            "gid" : ["usb", "shell"],
            "permission" : [
                "ohos.permission.LISTEN_BUNDLE_CHANGE"
            ],
            "apl" : "system_basic",
            "secon" : "u:r:usb_service:s0"
        }
    ],

从上面可以看到和android的init.rc是一样的,都是由导入其他配置文件,触发器和服务启动构成。服务大部分都在/etc/init目录下的各种以服务名命名的cfg文件中。其中import主要对应导入其他的配置文件,jobs对应各种触发器,service则是对应需要启动的服务。下面我们一步一步看是如何解析的。

2.5.3 ParseAllServices

ParseAllServices函数主要用来解析/etc/init目录下的各种以服务名命名的cfg文件

/base/startup/init/services/init/init_service_manager.c
void ParseAllServices(const cJSON *fileRoot)
{
    int servArrSize = 0;
    cJSON *serviceArr = GetArrayItem(fileRoot, &servArrSize, SERVICES_ARR_NAME_IN_JSON);
    INIT_CHECK(serviceArr != NULL, return);

    INIT_ERROR_CHECK(servArrSize <= MAX_SERVICES_CNT_IN_FILE, return,
        "Too many services[cnt %d] detected, should not exceed %d.",
        servArrSize, MAX_SERVICES_CNT_IN_FILE);

    size_t strLen = 0;
    //for循环解析service并添加到NODE_TYPE_SERVICES中的InitGroupNode
    for (int i = 0; i < servArrSize; ++i) {
        cJSON *curItem = cJSON_GetArrayItem(serviceArr, i);
        char *fieldStr = GetStringValue(curItem, "name", &strLen);
        if (fieldStr == NULL) {
            INIT_LOGE("Failed to get service name");
            continue;
        }
        Service *service = GetServiceByName(fieldStr);
        if (service == NULL) {
            service = AddService(fieldStr);
            if (service == NULL) {
                INIT_LOGE("Failed to add service name %s", fieldStr);
                continue;
            }
        } else {
            INIT_LOGI("Service %s already exists, updating.", fieldStr);
#ifndef __MUSL__
            continue;
#endif
        }

        service->pid = -1;
        //解析服务
        int ret = ParseOneService(curItem, service);
        if (ret != SERVICE_SUCCESS) {
            ReleaseService(service);
            service = NULL;
            continue;
        }
        //解析服务中的socket
        ret = ParseServiceSocket(curItem, service);
        INIT_CHECK(ret == 0, FreeServiceSocket(service->socketCfg); service->socketCfg = NULL);
        ret = ParseServiceFile(curItem, service);
        INIT_CHECK(ret == 0, FreeServiceFile(service->fileCfg); service->fileCfg = NULL);
        // Watch "/dev/console" node for starting console service ondemand.
        if ((strcmp(service->name, "console") == 0) && IsOnDemandService(service)) {
            if (WatchConsoleDevice(service) < 0) {
                INIT_LOGW("Failed to watch \'/dev/console\' device");
            }
        }
#ifndef OHOS_LITE
        /*
         * Execute service parsing hooks
         */
        ParseServiceHookExecute(fieldStr, curItem);
#endif

        ret = GetCmdLinesFromJson(cJSON_GetObjectItem(curItem, "onrestart"), &service->restartArg);
        INIT_CHECK(ret == SERVICE_SUCCESS, service->restartArg = NULL);
    }
}

ParseAllServices使用for循环调用ParseOneService解析服务的相关参数,调用ParseServiceSocket解析服务中的socket

2.5.4 ParseAllJobs

ParseAllJobs主要是用来解析cfg配置文件中的job标签,job和android的触发器比较相似。

/base/startup/init/services/init/standard/init_jobs.c
void ParseAllJobs(const cJSON *fileRoot)
{
    ParseTriggerConfig(fileRoot, CheckJobValid);
}
int ParseTriggerConfig(const cJSON *fileRoot, int (*checkJobValid)(const char *jobName))
{
    PARAM_CHECK(fileRoot != NULL, return -1, "Invalid file");
    cJSON *triggers = cJSON_GetObjectItemCaseSensitive(fileRoot, TRIGGER_ARR_NAME_IN_JSON);
    if (triggers == NULL || !cJSON_IsArray(triggers)) {
        return 0;
    }
    int size = cJSON_GetArraySize(triggers);
    PARAM_CHECK(size > 0, return -1, "Trigger array size must positive");

    for (int i = 0; i < size && i < TRIGGER_MAX_CMD; ++i) {
        cJSON *item = cJSON_GetArrayItem(triggers, i);
        //解析Trigger
        ParseTrigger_(&g_triggerWorkSpace, item, checkJobValid);
        /*
         * execute job parsing hooks
         */
        ParseJobHookExecute(cJSON_GetStringValue(cJSON_GetObjectItem(item, "name")), item);
    }
    return 0;
}
/base/startup/init/services/param/trigger/trigger_processor.c
static int ParseTrigger_(const TriggerWorkSpace *workSpace,
    const cJSON *triggerItem, int (*checkJobValid)(const char *jobName))
{
    PARAM_CHECK(triggerItem != NULL, return -1, "Invalid file");
    PARAM_CHECK(workSpace != NULL, return -1, "Failed to create trigger list");
    //拿到trigger的name
    char *name = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "name"));
    PARAM_CHECK(name != NULL, return -1, "Can not get name from cfg");
    char *condition = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "condition"));
    //从name获取到type
    int type = GetTriggerType(name);
    PARAM_CHECK(type <= TRIGGER_UNKNOW, return -1, "Failed to get trigger index");
    if (type != TRIGGER_BOOT && checkJobValid != NULL && checkJobValid(name) != 0) {
        PARAM_LOGI("Trigger %s not exist in group", name);
        return 0;
    }

    TriggerHeader *header = GetTriggerHeader(workSpace, type);
    PARAM_CHECK(header != NULL, return -1, "Failed to get header %d", type);
    JobNode *trigger = UpdateJobTrigger(workSpace, type, condition, name);
    PARAM_CHECK(trigger != NULL, return -1, "Failed to create trigger %s", name);
    PARAM_LOGV("ParseTrigger %s type %d count %d", name, type, header->triggerCount);
    cJSON *cmdItems = cJSON_GetObjectItem(triggerItem, CMDS_ARR_NAME_IN_JSON);
    if (cmdItems == NULL || !cJSON_IsArray(cmdItems)) {
        return 0;
    }
    int cmdLinesCnt = cJSON_GetArraySize(cmdItems);
    PARAM_CHECK(cmdLinesCnt > 0, return -1, "Command array size must positive %s", name);

    int ret;
    int cmdKeyIndex = 0;
    //for循环解析命令
    for (int i = 0; (i < cmdLinesCnt) && (i < TRIGGER_MAX_CMD); ++i) {
        char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdItems, i));
        PARAM_CHECK(cmdLineStr != NULL, continue, "Command is null");

        char *content = NULL;
        ret = GetCommandInfo(cmdLineStr, &cmdKeyIndex, &content);
        PARAM_CHECK(ret == 0, continue, "Command not support %s", cmdLineStr);
        //将命令加入到trigger的命令链表中
        ret = AddCommand(trigger, (uint32_t)cmdKeyIndex, content);
        PARAM_CHECK(ret == 0, continue, "Failed to add command %s", cmdLineStr);
        header->cmdNodeCount++;
    }
    return 0;
}

同样的for循环调用ParseTrigger_来解析Trigger

2.5.5 ParseAllImports
/base/startup/init/services/init/init_config.c
static void ParseAllImports(const cJSON *root)
{
    char *tmpParamValue = calloc(PARAM_VALUE_LEN_MAX + 1, sizeof(char));
    INIT_ERROR_CHECK(tmpParamValue != NULL, return, "Failed to alloc memory for param");

    cJSON *importAttr = cJSON_GetObjectItemCaseSensitive(root, "import");
    if (!cJSON_IsArray(importAttr)) {
        free(tmpParamValue);
        return;
    }
    int importAttrSize = cJSON_GetArraySize(importAttr);
    for (int i = 0; i < importAttrSize; i++) {
        cJSON *importItem = cJSON_GetArrayItem(importAttr, i);
        if (!cJSON_IsString(importItem)) {
            INIT_LOGE("Invalid type of import item. should be string");
            break;
        }
        char *importContent = cJSON_GetStringValue(importItem);
        if (importContent == NULL) {
            INIT_LOGE("cannot get import config file");
            break;
        }
        int ret = GetParamValue(importContent, strlen(importContent), tmpParamValue, PARAM_VALUE_LEN_MAX);
        if (ret != 0) {
            INIT_LOGE("cannot get value for %s", importContent);
            continue;
        }
        INIT_LOGI("Import %s  ...", tmpParamValue);
        ParseInitCfg(tmpParamValue, NULL);
    }
    free(tmpParamValue);
    return;
}

通过for循环调用ParseInitCfg去解析引入的cfg文件。引入的cfg文件有以下:

[    4.320616] [pid=1][Init][INFO][init_config.c:78]Import /etc/init.usb.cfg  ...
[    4.321108] [pid=1][Init][INFO][init_config.c:78]Import /vendor/etc/init.rk3568.usb.cfg  ...
[    4.321907] [pid=1][Init][INFO][init_config.c:78]Import /etc/init.usb.configfs.cfg  ...
[    4.322003] [pid=1][Init][INFO][init_config.c:78]Import /vendor/etc/init.rk3568.cfg  ...
[    4.322808] [pid=1][Init][INFO][init_config.c:78]Import init.rk3568.usb.cfg  ...
2.5.6 PostTrigger

接着就是调用PostTrigger去触发"pre-init"和"init"阶段的jobs

/base/startup/init/services/param/trigger/trigger_processor.c
void PostTrigger(EventType type, const char *content, uint32_t contentLen)
{
    //这里的type = EVENT_TRIGGER_BOOT content分别是"pre-init"和"init“或者"post-init"
    PARAM_CHECK(content != NULL && contentLen > 0, return, "Invalid param");
    SendTriggerEvent(type, content, contentLen);
}
static void SendTriggerEvent(int type, const char *content, uint32_t contentLen)
{
    PARAM_CHECK(content != NULL, return, "Invalid param");
    PARAM_LOGV("SendTriggerEvent type %d content %s", type, content);
    ParamEventSend(g_triggerWorkSpace.eventHandle, (uint64_t)type, content, contentLen);
}

这里回调用到g_triggerWorkSpace.eventHandle,g_triggerWorkSpace.eventHandle是在初始化ParamService设置成了ProcessBeforeEvent所以最终会调用到

trigger_processor中的ProcessBeforeEvent。

/base/startup/init/services/param/trigger/trigger_processor.c
PARAM_STATIC void ProcessBeforeEvent(const ParamTaskPtr stream,
    uint64_t eventId, const uint8_t *content, uint32_t size)
{
    PARAM_LOGV("ProcessBeforeEvent %s ", (char *)content);
    switch (eventId) {
        case EVENT_TRIGGER_PARAM: {
            CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM,
                (const char *)content, size, DoTriggerCheckResult);
            ExecuteQueueWork(MAX_TRIGGER_COUNT_RUN_ONCE);
            break;
        }
        //走中间
        case EVENT_TRIGGER_BOOT: {
            if (g_triggerWorkSpace.bootStateChange != NULL) {
                g_triggerWorkSpace.bootStateChange(0, (const char *)content);
            }
            //DoTriggerCheckResult会将当前的
            CheckTrigger(&g_triggerWorkSpace, TRIGGER_BOOT,
                (const char *)content, size, DoTriggerCheckResult);
            ExecuteQueueWork(MAX_TRIGGER_COUNT_RUN_ONCE);
            if (g_triggerWorkSpace.bootStateChange != NULL) {
                //这里的bootStateChange主要是统计状态变化使用的时间
                g_triggerWorkSpace.bootStateChange(1, (const char *)content);
            }
            break;
        }
        case EVENT_TRIGGER_PARAM_WAIT: {
            CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM_WAIT,
                (const char *)content, size, ExecuteTriggerImmediately);
            break;
        }
        case EVENT_TRIGGER_PARAM_WATCH: {
            CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM_WATCH,
                (const char *)content, size, ExecuteTriggerImmediately);
            break;
        }
        default:
            break;
    }
}

可以看到主要是调用了ExecuteQueueWork

/base/startup/init/services/param/trigger/trigger_processor.c
static void ExecuteQueueWork(uint32_t maxCount)
{
    uint32_t executeCount = 0;
    //获取到trigger
    TriggerNode *trigger = ExecuteQueuePop(&g_triggerWorkSpace);
    while (trigger != NULL) {
        //执行trigger
        StartTriggerExecute_(trigger, NULL, 0);
        executeCount++;
        if (executeCount > maxCount) {
            break;
        }
        trigger = ExecuteQueuePop(&g_triggerWorkSpace);
    }
}
static void StartTriggerExecute_(TriggerNode *trigger, const char *content, uint32_t size)
{
    TriggerHeader *triggerHead = GetTriggerHeader(&g_triggerWorkSpace, trigger->type);
    if (triggerHead != NULL) {
        PARAM_LOGV("StartTriggerExecute_ trigger %s flags:0x%04x",
            GetTriggerName(trigger), trigger->flags);
        //执行Trigger
        triggerHead->executeTrigger(trigger, content, size);
        TRIGGER_CLEAR_FLAG(trigger, TRIGGER_FLAGS_QUEUE);
        if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_SUBTRIGGER)) { // boot && xxx=xxx trigger
            const char *condition = triggerHead->getCondition(trigger);
            CheckTrigger(&g_triggerWorkSpace, TRIGGER_UNKNOW, condition, strlen(condition), ExecuteTriggerImmediately);
        }
        if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_ONCE)) {
            FreeTrigger(&g_triggerWorkSpace, trigger);
        }
    }
}

这里的executeTrigger也是在trigger_processor初始化时通过RegisterTriggerExec成DoTriggerExecute_,所以最终Trigger的执行调用到了DoTriggerExecute_

如下:

/base/startup/init/services/param/trigger/trigger_processor.c
static int DoTriggerExecute_(const TriggerNode *trigger, const char *content, uint32_t size)
{
    PARAM_CHECK(trigger != NULL, return -1, "Invalid trigger");
    PARAM_LOGV("Do execute trigger %s type: %d", GetTriggerName(trigger), trigger->type);
    PARAM_CHECK(trigger->type <= TRIGGER_UNKNOW, return -1, "Invalid trigger type %d", trigger->type);
    CommandNode *cmd = GetNextCmdNode((JobNode *)trigger, NULL);
    while (cmd != NULL) {
#ifndef STARTUP_INIT_TEST
        //执行命令
        DoCmdByIndex(cmd->cmdKeyIndex, cmd->content);
#endif
        cmd = GetNextCmdNode((JobNode *)trigger, cmd);
    }
    return 0;
}

DoTriggerExecute_遍历trigger的命令链表通过调用DoCmdByIndex来执行。

2.5.7 TriggerServices

继续就到了启动服务的流程了首先是启动boot阶段的服务,

/base/startup/init/services/init/standard/init.c
INIT_STATIC void TriggerServices(int startMode)
{
    int index = 0;
    int jobNum = 0;
    char jobName[64] = {0}; // 64 job name
    char cmd[64] = {0};  // 64 job name
    const int maxServiceInJob = 4; // 4 service in job
    //获取到NODE_TYPE_SERVICES中的InitGroupNode
    InitGroupNode *node = GetNextGroupNode(NODE_TYPE_SERVICES, NULL);
    //通过while循环拿出代表服务的InitGroupNode
    while (node != NULL) {
        //获取到上面解析的服务
        Service *service = node->data.service;
        //异常处理
        if (service == NULL || service->startMode != startMode) {
            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
            continue;
        }
        if (IsOnDemandService(service)) {
            if (CreateServiceSocket(service) != 0) {
                INIT_LOGE("service %s exit! create socket failed!", service->name);
            }
            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
            continue;
        }
        //组合 start xxx 命令一同来启动服务
        if (sprintf_s(cmd, sizeof(cmd), "start %s", service->name) <= 0) {
            node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
            continue;
        }
        //构建job的名字
        if (index == 0) {
            if (sprintf_s(jobName, sizeof(jobName), "boot-service:service-%d-%03d", startMode, jobNum) <= 0) {
                node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
                continue;
            }
            jobNum++;
        }
        index++;
        //调用AddCompleteJob通过job机制来调用start xxx来启动服务
        AddCompleteJob(jobName, NULL, cmd);
        INIT_LOGV("Add %s to job %s", service->name, jobName);
        if (index == maxServiceInJob) {
            //触发上面的job
            PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
            index = 0;
        }
        node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
    }
    if (index > 0) {
        PostTrigger(EVENT_TRIGGER_BOOT, jobName, strlen(jobName));
    }
}

TriggerServices启动服务的大概机制就是创建一个job,在这个job中添加4条命令,每一条命令启动一个服务,然后触发这个job这样就可以一直启动服务了。

每一个job的log如下:

//这里的boot-service:service-2-001 其中的2代表是START_MODE_NORMAL
[   10.612132] [pid=1][Init][INFO][init.c:270]boot job boot-service:service-2-001 start.
[   10.612188] [pid=1][Init][INFO][init_service_manager.c:1087]Start service codec_host
[   10.612961] [pid=1][Init][INFO][init_common_service.c:383]Service codec_host(pid 543) started
[   10.613187] [pid=1][Init][INFO][init_service_manager.c:1087]Start service light_host
[   10.613858] [pid=1][Init][INFO][init_common_service.c:383]Service light_host(pid 544) started
[   10.614059] [pid=1][Init][INFO][init_service_manager.c:1087]Start service vibrator_host
[   10.614761] [pid=1][Init][INFO][init_common_service.c:383]Service vibrator_host(pid 545) started
[   10.614957] [pid=1][Init][INFO][init_service_manager.c:1087]Start service sensor_host
[   10.615849] [pid=1][Init][INFO][init_common_service.c:383]Service sensor_host(pid 546) started
[   10.616218] [pid=1][Init][INFO][init.c:275]boot job boot-service:service-2-001 finish diff 4068 us.

从Log上看启动的所有服务如下:

[    4.385955] [pid=1][Init][INFO][init_service_manager.c:1087]Start service ueventd
[    4.386713] [pid=1][Init][INFO][init_service_manager.c:1087]Start service watchdog_service
[    7.025390] [pid=1][Init][INFO][init_service_manager.c:1087]Start service hilogd
START_MODE_BOOT阶段启动的服务
[    7.110652] [pid=1][Init][INFO][init_service_manager.c:1087]Start service hdf_devmgr
[    7.115731] [pid=1][Init][INFO][init_service_manager.c:1087]Start service hiview
[    7.116619] [pid=1][Init][INFO][init_service_manager.c:1087]Start service param_watcher
[    7.117657] [pid=1][Init][INFO][init_service_manager.c:1087]Start service samgr

[    7.118868] [pid=1][Init][INFO][init_service_manager.c:1087]Start service storage_daemon
[    7.119847] [pid=1][Init][INFO][init_service_manager.c:1087]Start service device_manager
[    7.120716] [pid=1][Init][INFO][init_service_manager.c:1087]Start service storage_manager
[    7.121675] [pid=1][Init][INFO][init_service_manager.c:1087]Start service appspawn

START_MODE_NORMAL阶段启动的服务
[    7.148924] [pid=1][Init][INFO][init_service_manager.c:1087]Start service storage_daemon
[    7.151661] [pid=1][Init][INFO][init_service_manager.c:1087]Start service wifi_hal_service
[    7.154144] [pid=1][Init][INFO][init_service_manager.c:1087]Start service udevd_service
[    7.155264] [pid=1][Init][INFO][init_service_manager.c:1087]Start service mmi_uinput_service
[    7.167686] [pid=1][Init][INFO][init_service_manager.c:1087]Start service multimodalinput
[    9.337235] [pid=1][Init][INFO][init_service_manager.c:1087]Start service device_usage_stats_service
[    9.342437] [pid=1][Init][INFO][init_service_manager.c:1087]Start service memmgrservice
[    9.348861] [pid=1][Init][INFO][init_service_manager.c:1087]Start service accessibility
[    9.356335] [pid=1][Init][INFO][init_service_manager.c:1087]Start service huks_service
[    9.359630] [pid=1][Init][INFO][init_service_manager.c:1087]Start service devattest_service
[    9.367228] [pid=1][Init][INFO][init_service_manager.c:1087]Start service bluetooth_service
[    9.381927] [pid=1][Init][INFO][init_service_manager.c:1087]Start service locationhub
[    9.409612] [pid=1][Init][INFO][init_service_manager.c:1087]Start service deviceauth_service
[    9.421050] [pid=1][Init][INFO][init_service_manager.c:1087]Start service resource_schedule_service
[    9.469054] [pid=1][Init][INFO][init_service_manager.c:1087]Start service pulseaudio
[    9.573060] [pid=1][Init][INFO][init_service_manager.c:1087]Start service hdf_devhost
[    9.573181] [pid=1][Init][ERROR][init_service_manager.c:1092]Cannot find service hdf_devhost.
[    9.587770] [pid=1][Init][INFO][init_service_manager.c:1087]Start service netmanager
[    9.639384] [pid=1][Init][INFO][init_service_manager.c:1087]Start service wallpaper_service
[    9.650303] [pid=1][Init][INFO][init_service_manager.c:1087]Start service telephony_sa
[    9.894095] [pid=1][Init][INFO][init_service_manager.c:1087]Start service ispserver
[    9.907804] [pid=1][Init][INFO][init_service_manager.c:1087]Start service bgtaskmgr_service
[    9.921356] [pid=1][Init][INFO][init_service_manager.c:1087]Start service msdp_sa
[    9.922280] [pid=1][Init][INFO][init_service_manager.c:1087]Start service screenlock_server
[    9.923239] [pid=1][Init][INFO][init_service_manager.c:1087]Start service edm_sa
[   10.543689] [pid=1][Init][INFO][init_service_manager.c:1087]Start service time_service
[   10.577120] [pid=1][Init][INFO][init_service_manager.c:1087]Start service audio_policy
[   10.596716] [pid=1][Init][INFO][init_service_manager.c:1087]Start service fingerprint_auth_host
[   10.597655] [pid=1][Init][INFO][init_service_manager.c:1087]Start service user_auth_host
[   10.598625] [pid=1][Init][INFO][init_service_manager.c:1087]Start service pin_auth_host
[   10.599478] [pid=1][Init][INFO][init_service_manager.c:1087]Start service face_auth_host
[   10.612188] [pid=1][Init][INFO][init_service_manager.c:1087]Start service codec_host
[   10.613187] [pid=1][Init][INFO][init_service_manager.c:1087]Start service light_host
[   10.614059] [pid=1][Init][INFO][init_service_manager.c:1087]Start service vibrator_host
[   10.614957] [pid=1][Init][INFO][init_service_manager.c:1087]Start service sensor_host
[   10.617144] [pid=1][Init][INFO][init_service_manager.c:1087]Start service input_user_host
[   10.618166] [pid=1][Init][INFO][init_service_manager.c:1087]Start service camera_host
[   10.619258] [pid=1][Init][INFO][init_service_manager.c:1087]Start service audio_host
[   10.620246] [pid=1][Init][INFO][init_service_manager.c:1087]Start service wifi_host
[   10.621669] [pid=1][Init][INFO][init_service_manager.c:1087]Start service power_host
[   10.629461] [pid=1][Init][INFO][init_service_manager.c:1087]Start service usb_host
[   10.630509] [pid=1][Init][INFO][init_service_manager.c:1087]Start service blue_host
[   10.631510] [pid=1][Init][INFO][init_service_manager.c:1087]Start service disp_gralloc_host
[   10.633054] [pid=1][Init][INFO][init_service_manager.c:1087]Start service privacy_service
[   10.634105] [pid=1][Init][INFO][init_service_manager.c:1087]Start service distributeddata
[   10.641969] [pid=1][Init][INFO][init_service_manager.c:1087]Start service installs
[   10.643163] [pid=1][Init][INFO][init_service_manager.c:1087]Start service inputmethod_service
[   10.644577] [pid=1][Init][INFO][init_service_manager.c:1087]Start service netsysnative
[   10.645674] [pid=1][Init][INFO][init_service_manager.c:1087]Start service foundation
[   10.652420] [pid=1][Init][INFO][init_service_manager.c:1087]Start service sensors
[   10.653472] [pid=1][Init][INFO][init_service_manager.c:1087]Start service distributedfiledaemon
[   10.654951] [pid=1][Init][INFO][init_service_manager.c:1087]Start service accountmgr
[   10.655992] [pid=1][Init][INFO][init_service_manager.c:1087]Start service resource_schedule_service
[   10.656050] [pid=1][Init][INFO][init_service_manager.c:1087]Start service telephony_sa
[   10.656096] [pid=1][Init][INFO][init_service_manager.c:1087]Start service media_service
[   10.657599] [pid=1][Init][INFO][init_service_manager.c:1087]Start service deviceauth_service
[   10.657643] [pid=1][Init][INFO][init_service_manager.c:1087]Start service av_session
[   10.665467] [pid=1][Init][INFO][init_service_manager.c:1087]Start service distributedsched
[   10.666521] [pid=1][Init][INFO][init_service_manager.c:1087]Start service locationhub
[   10.666869] [pid=1][Init][INFO][init_service_manager.c:1087]Start service ui_service
[   10.667914] [pid=1][Init][INFO][init_service_manager.c:1087]Start service time_service
[   10.667969] [pid=1][Init][INFO][init_service_manager.c:1087]Start service edm_sa
[   10.668005] [pid=1][Init][INFO][init_service_manager.c:1087]Start service useriam
[   10.676124] [pid=1][Init][INFO][init_service_manager.c:1087]Start service wallpaper_service
[   10.676173] [pid=1][Init][INFO][init_service_manager.c:1087]Start service screenlock_server
[   10.676215] [pid=1][Init][INFO][init_service_manager.c:1087]Start service bluetooth_service
[   10.676247] [pid=1][Init][INFO][init_service_manager.c:1087]Start service camera_service
[   10.677417] [pid=1][Init][INFO][init_service_manager.c:1087]Start service faultloggerd
[   10.700828] [pid=1][Init][INFO][init_service_manager.c:1087]Start service devattest_service
[   10.700881] [pid=1][Init][INFO][init_service_manager.c:1087]Start service netmanager
[   10.700924] [pid=1][Init][INFO][init_service_manager.c:1087]Start service accessibility
[   10.701302] [pid=1][Init][INFO][init_service_manager.c:1087]Start service accesstoken_service
[   10.703147] [pid=1][Init][INFO][init_service_manager.c:1087]Start service memmgrservice
[   10.703192] [pid=1][Init][INFO][init_service_manager.c:1087]Start service msdp_sa
[   10.703235] [pid=1][Init][INFO][init_service_manager.c:1087]Start service bgtaskmgr_service
[   10.703651] [pid=1][Init][INFO][init_service_manager.c:1087]Start service bootanimation
[   10.719513] [pid=1][Init][INFO][init_service_manager.c:1087]Start service render_service
[   10.720520] [pid=1][Init][INFO][init_service_manager.c:1087]Start service device_usage_stats_service
[   10.720583] [pid=1][Init][INFO][init_service_manager.c:1087]Start service wifi_manager_service
[   10.733451] [pid=1][Init][INFO][init_service_manager.c:1087]Start service hidumper_service
[   10.734381] [pid=1][Init][INFO][init_service_manager.c:1087]Start service softbus_server
[   10.735724] [pid=1][Init][INFO][init_service_manager.c:1087]Start service pasteboard_service
[   10.736756] [pid=1][Init][INFO][init_service_manager.c:1087]Start service ispserver
[   10.737957] [pid=1][Init][INFO][init_service_manager.c:1087]Start service hdcd
[   10.859875] [pid=1][Init][INFO][init_service_manager.c:1087]Start service hdcd
[   11.945313] [pid=1][Init][INFO][init_service_manager.c:1087]Start service usb_service|4201
[   12.588393] [pid=1][Init][INFO][init_service_manager.c:1087]Start service pinauth

2.6 SystemRun

/base/startup/init/services/init/standard/init.c
void SystemRun(void)
{
    StartParamService();
}
/base/startup/init/services/param/linux/param_service.c
int StartParamService(void)
{
    // read selinux label
    LoadSelinuxLabel("permission");
    return ParamServiceStart();
}

可以看到SystemRun主要就是启动ParamService

三、服务的启动框架

在上面的2.5.3小节我们说过ParseAllServices函数主要用来解析/etc/init目录下的各种以服务名命名的cfg文件,解析完毕后会将服务的信息存储在NODE_TYPE_SERVICES中的InitGroupNode接着在2.5.7小节的TriggerServices去启动它,TriggerServices后续的流程图如下:

Openharmony的启动流程_linux_02

这里我们以CameraService为例介绍一下OpenHarmony启动服务的基本流程,

首先camera_service的cfg文件内容如下:

/foundation/multimedia/camera_framework/services/etc/camera_service.cfg
{
    "services" : [{
            "name" : "camera_service",
            "path" : ["/system/bin/sa_main", "/system/profile/camera_service.xml"],
            "uid" : "cameraserver",
            "gid" : ["system", "shell"],
            "secon" : "u:r:camera_service:s0",
            "permission" : ["ohos.permission.GET_SENSITIVE_PERMISSIONS", "ohos.permission.PERMISSION_USED_STATS"],
            "permission_acls" : ["ohos.permission.GET_SENSITIVE_PERMISSIONS"]
        }
    ]
}

可以看到他是通过执行system/bin/sa_main程序导入了/system/profile/camera_service.xml配置文件启动的camera_service服务就和Android的init.rc中启动native进程是类似的。接着我们看一下camera_service.xml

<!--设备里的/system/profile/camera_service.xml-->
<?xml version="1.0" encoding="utf-8"?>
<info>
    <process>camera_service</process>
    <loadlibs>
        <libpath>libcamera_service.z.so</libpath>
    </loadlibs>
    <systemability>
       <name>3008</name>
       <libpath>libcamera_service.z.so</libpath>
       <run-on-create>true</run-on-create>
       <distributed>false</distributed>
       <dump-level>1</dump-level>
   </systemability>
</info>

服务的启动流程首先要先知道sa_main可执行程序的入口在哪里,在代码库中搜索sa_main 并在filePath中输入gn即可搜到sa_main的代码路径如下:

/foundation/systemabilitymgr/safwk/services/safwk/src/

3.1 sa.main

入口函数是main.cpp

/foundation/systemabilitymgr/safwk/services/safwk/src/main.cpp
int main(int argc, char *argv[]){
    //我们这里一般的服务只有一个参数 就是
    HILOGI(TAG, "[PerformanceTest] SAFWK main entry process starting!");
    //回调接口
    auto setProcessName = [argc, argv](const string& name) -> void {
        uintptr_t start = reinterpret_cast<uintptr_t>(argv[0]);
        uintptr_t end = reinterpret_cast<uintptr_t>(strchr(argv[argc - 1], 0));
        uintptr_t argvSize = end - start;

        if (memset_s(argv[0], argvSize, 0, argvSize) != EOK) {
            HILOGW(TAG, "failed to clear argv:%s", strerror(errno));
            return;
        }
        if (strcpy_s(argv[0], argvSize, name.c_str()) != EOK) {
            HILOGW(TAG, "failed to set process name:%s", strerror(errno));
            return;
        }
        HILOGI(TAG, "Set process name to %{public}s", argv[0]);
    };
    // Load ondemand system abilities related shared libraries from specific xml-format profile
    // when this process starts.
    //初始saId为-1
    int32_t saId = DEFAULT_SAID;
    if (argc > ONDEMAND_LOAD) {
        //从参数中解析saId
        saId = ParseSaId(argv);
        if (!CheckSaId(saId)) {
            HILOGE(TAG, "saId is invalid!");
            return 0;
        }
    }
    // Load default system abilities related shared libraries from specific xml-format profile,
    // when this process starts.
    //解析服务的profile文件就是camera_service.xml
    string profilePath(DEFAULT_XML);
    if (argc > DEFAULT_LOAD) {
        string filePath(argv[PROFILE_INDEX]);
        if (filePath.empty() || filePath.find(".xml") == string::npos) {
            HILOGE(TAG, "profile file path is invalid!");
            return 0;
        }
        //调用SetProcName设置进程的名字
        SetProcName(filePath, setProcessName);
        profilePath = std::move(filePath);
    }
    //调用DoStartSAProcess启动服务
    LocalAbilityManager::GetInstance().DoStartSAProcess(profilePath, saId);
    return 0;
}

3.2 LocalAbilityManager.DoStartSAProcess

可以看到sa_main的main函数主要是设置进程名字接着调用LocalAbilityManager的DoStartSAProcess来启动服务

/foundation/systemabilitymgr/safwk/services/safwk/src/local_ability_manager.cpp
void LocalAbilityManager::DoStartSAProcess(const std::string& profilePath, int32_t saId)
{
    HILOGI(TAG, "DoStartSAProcess saId : %d", saId);
    string realProfilePath = "";
    if (!CheckAndGetProfilePath(profilePath, realProfilePath)) {
        HILOGE(TAG, "DoStartSAProcess invalid path");
        return;
    }
    {
        std::string traceTag = GetTraceTag(realProfilePath);
        HITRACE_METER_NAME(HITRACE_TAG_SAMGR, traceTag);
        //InitSystemAbilityProfiles 解析进程名称并打开对应的so文件注册相应的ability
        bool ret = InitSystemAbilityProfiles(realProfilePath, saId);
        if (!ret) {
            HILOGE(TAG, "InitSystemAbilityProfiles no right profile, will exit");
            return;
        }
        //等待SystemAbilityManager启动 SystemAbilityManager和Android的ServiceManager功能类似主要负责系统能力的添加查找
        //最多等待10s
        ret = CheckSystemAbilityManagerReady();
        if (!ret) {
            HILOGE(TAG, "CheckSystemAbilityManagerReady failed! will exit");
            return;
        }
        //将注册的ability加入到abilityPhaseMap_中的saList中
        ret = InitializeSaProfiles(saId);
        if (!ret) {
            HILOGE(TAG, "InitializeSaProfiles failed! will exit");
            return;
        }
        //启动ability
        ret = Run(saId);
        if (!ret) {
            HILOGE(TAG, "Run failed! will exit");
            return;
        }
    }

    IPCSkeleton::JoinWorkThread();
    ClearResource();
    HILOGE(TAG, "JoinWorkThread stop, will exit");
}

DoStartSAProcess主要做了三件事情

1.调用InitSystemAbilityProfiles解析进程名称并打开和加载对应的so文件

2.等待SystemAbilityManager启动

3.将解析出来的ability加入到saList中

4.启动ability

3.3 注册Ability

其中第一条在加载so文件时会加载服务的类这时会调用到如下函数:

/foundation/multimedia/camera_framework/services/camera_service/src/hcamera_service.cpp
REGISTER_SYSTEM_ABILITY_BY_ID(HCameraService, CAMERA_SERVICE_ID, true)
/foundation/systemabilitymgr/safwk/services/safwk/include/system_ability.h
#define REGISTER_SYSTEM_ABILITY_BY_ID(abilityClassName, systemAbilityId, runOnCreate) \
    const bool abilityClassName##_##RegisterResult = \
    SystemAbility::MakeAndRegisterAbility(new abilityClassName(systemAbilityId, runOnCreate));

意思就是将HCameraService注册成为CAMERA_SERVICE_ID的systemability,可以看到最终调用到了 SystemAbility::MakeAndRegisterAbility

/foundation/systemabilitymgr/safwk/services/safwk/src/system_ability.cpp
bool SystemAbility::MakeAndRegisterAbility(SystemAbility* systemAbility)
{
    HILOGD(TAG, "registering system ability...");
    return LocalAbilityManager::GetInstance().AddAbility(systemAbility);
}

/foundation/systemabilitymgr/safwk/services/safwk/src/local_ability_manager.cpp
bool LocalAbilityManager::AddAbility(SystemAbility* ability)
{
    if (ability == nullptr) {
        HILOGW(TAG, "try to add null ability!");
        return false;
    }

    int32_t saId = ability->GetSystemAbilitId();
    SaProfile saProfile;
    bool ret = profileParser_->GetProfile(saId, saProfile);
    if (!ret) {
        return false;
    }
    std::unique_lock<std::shared_mutex> writeLock(abilityMapLock_);
    auto iter = abilityMap_.find(saId);
    if (iter != abilityMap_.end()) {
        HILOGW(TAG, "try to add existed ability:%{public}d!", saId);
        return false;
    }
    HILOGI(TAG, "set profile attributes for SA:%{public}d", saId);
    ability->SetLibPath(saProfile.libPath);
    ability->SetRunOnCreate(saProfile.runOnCreate);
    ability->SetDependSa(saProfile.dependSa);
    ability->SetDependTimeout(saProfile.dependTimeout);
    ability->SetDistributed(saProfile.distributed);
    ability->SetDumpLevel(saProfile.dumpLevel);
    ability->SetCapability(saProfile.capability);
    ability->SetPermission(saProfile.permission);
    abilityMap_.emplace(saId, ability);
    return true;
}

可以看到最终将ability加入到了abilityMap_中

3.4 启动ability

在3.2小节中启动ability走的时run函数

/foundation/systemabilitymgr/safwk/services/safwk/src/local_ability_manager.cpp
bool LocalAbilityManager::Run(int32_t saId)
{
    HILOGD(TAG, "local ability manager is running...");
    //把当前的LocalAbilityManager和processName注册给SystemAbilityManager
    bool addResult = AddLocalAbilityManager();
    if (!addResult) {
        HILOGE(TAG, "failed to add local abilitymanager");
        return false;
    }
    HILOGD(TAG, "success to add process name:%{public}s", Str16ToStr8(procName_).c_str());
    uint32_t concurrentThreads = std::thread::hardware_concurrency();
    HILOGI(TAG, "concurrentThreads is %{public}d", concurrentThreads);
    initPool_->Start(concurrentThreads);
    initPool_->SetMaxTaskNum(MAX_TASK_NUMBER);
    //启动ability
    FindAndStartPhaseTasks();
    RegisterOnDemandSystemAbility(saId);
    initPool_->Stop();
    return true;
}
void LocalAbilityManager::FindAndStartPhaseTasks()
{
    std::shared_lock<std::shared_mutex> readLock(abilityMapLock_);
    for (uint32_t startType = BOOT_START; startType <= OTHER_START; ++startType) {
        //将abilityPhaseMap_中的ability全部启动
        auto iter = abilityPhaseMap_.find(startType);
        if (iter != abilityPhaseMap_.end()) {
            StartPhaseTasks(iter->second);
        }
    }
}
void LocalAbilityManager::StartPhaseTasks(const std::list<SystemAbility*>& systemAbilityList)
{
    if (systemAbilityList.empty()) {
        return;
    }

    for (auto systemAbility : systemAbilityList) {
        if (systemAbility != nullptr) {
            HILOGD(TAG, "add phase task for SA:%{public}d", systemAbility->GetSystemAbilitId());
            std::lock_guard<std::mutex> autoLock(startPhaseLock_);
            ++startTaskNum_;
            //使用initPool_调用StartSystemAbilityTask启动systemAbility
            auto task = std::bind(&LocalAbilityManager::StartSystemAbilityTask, this, systemAbility);
            initPool_->AddTask(task);
        }
    }

    int64_t begin = GetTickCount();
    HILOGD(TAG, "start waiting for all tasks!");
    std::unique_lock<std::mutex> lck(startPhaseLock_);
    if (!startPhaseCV_.wait_for(lck, std::chrono::seconds(MAX_SA_STARTUP_TIME),
        [this] () { return startTaskNum_ == 0; })) {
        HILOGW(TAG, "start timeout!");
    }
    startTaskNum_ = 0;
    int64_t end = GetTickCount();
    HILOGI(TAG, "start tasks finished and spend %{public}" PRId64 " ms", (end - begin));
}

void LocalAbilityManager::StartSystemAbilityTask(SystemAbility* ability)
{
    if (ability != nullptr) {
        HILOGD(TAG, "StartSystemAbility is called for %{public}d", ability->GetSystemAbilitId());
        //如果ability不依赖其他sa那么直接启动
        if (ability->GetDependSa().empty()) {
            ability->Start();
        } else {
            int64_t start = GetTickCount();
            int64_t dependTimeout = ability->GetDependTimeout();
            while (!CheckDependencyStatus(ability->GetDependSa()).empty()) {
                int64_t end = GetTickCount();
                int64_t duration = ((end >= start) ? (end - start) : (INT64_MAX - end + start));
                if (duration < dependTimeout) {
                    usleep(CHECK_DEPENDENT_SA_PERIOD);
                } else {
                    break;
                }
            }
            vector<u16string> unpreparedDeps = CheckDependencyStatus(ability->GetDependSa());
            if (unpreparedDeps.empty()) {
                ability->Start();
            } else {
                for (const auto& unpreparedDep : unpreparedDeps) {
                    HILOGI(TAG, "%{public}d's dependency:%{public}s not started in %{public}d ms",
                        ability->GetSystemAbilitId(), Str16ToStr8(unpreparedDep).c_str(), ability->GetDependTimeout());
                }
            }
        }
    }

    std::lock_guard<std::mutex> lock(startPhaseLock_);
    if (startTaskNum_ > 0) {
        --startTaskNum_;
    }
    startPhaseCV_.notify_one();
}

从上面代码我们可以知道服务的启动最终调用到了SystemAbility的start函数,由于我们注册的时候注册的是HCameraService,所以会调用到HCameraService的start函数。最终会调用到HCameraService的onStart函数,至此服务就被启动起来了。不同的服务只是需要加载的so库不一样注册的服务不一样,用的都是这一套框架。

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
EzIAYXiV4scN
最新推荐 更多