接上篇移植openharmony标准系统后,系统进入终端后,发现执行指令特别卡顿,太影响调试了。目前还不知道是什么问题导致的,不知道是不是cpu性能不够,但是感觉不太像是这个问题,卡顿如下图。基本一个操作需要卡半天。

为了解决下这个问题,也为了更熟悉openharmony代码启动流程。现在追踪下启动过程。记录如下。
首先可以知道的是openharmony系统启动后,执行的是init进程。可以查看源码目录下base/startup/init_lite/services/BUILD.gn文件,首先是不管小型还是标准系统都会参与编译的文件。
然后根据系统类型会选择编译不同的文件,我们是标准系统,那么我们具体编译的文件如下图所示。

很明显,我们找到了init的入口了,即为源码目录下的base/startup/init_lite/services/init/main.c文件,文件内容如下,

static const pid_t INIT_PROCESS_PID = 1;int main(int argc, char * const argv[])
{int isSecondStage = 0;// Number of command line parameters is 2if (argc == 2 && (strcmp(argv[1], "--second-stage") == 0)) { //我们一般启动都是不带参数isSecondStage = 1;}if (getpid() != INIT_PROCESS_PID) { //正常情况下init进程都为1INIT_LOGE("Process id error %d!", getpid());return 0;}if (isSecondStage == 0) { //前面说了,我们是没有参数,此值肯定为0,SystemPrepare();} else {LogInit();}SystemInit();SystemExecuteRcs();SystemConfig();SystemRun();return 0;
}

所以具体执行的函数为如下顺序:

  1. SystemPrepare();
  2. SystemInit();
  3. SystemExecuteRcs();
  4. SystemConfig();
  5. SystemRun();
    那么我们就需要展开查看这五个函数的执行过程了。
    1.1 首先执行的是SystemPrepare()函数,我们查找的话,是有如下图地方的地方存在改函数。

    而我们是标准系统,那么我们执行的函数肯定就是base/startup/init_lite/services/init/standard/init.c文件中的SystemPrepare()函数了。这边我们可以添加打印函数进行验证。
void SystemPrepare(void)
{INIT_LOGI("base/startup/init_lite/services/init/standard/init.c"); //添加的打印测试MountBasicFs();LogInit();// Make sure init log always output to /dev/kmsg.EnableDevKmsg();CreateDeviceNode();// Only ohos normal system support// two stages of init.// If we are in updater mode, only one stage of init,INIT_LOGI("DISABLE_INIT_TWO_STAGES not defined");if (InUpdaterMode() == 0) {StartInitSecondStage();}
}
void MountBasicFs(void)
{if (mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755") != 0) {INIT_LOGE("Mount tmpfs failed. %s", strerror(errno));}if (mount("tmpfs", "/mnt", "tmpfs", MS_NOSUID, "mode=0755") != 0) {INIT_LOGE("Mount tmpfs failed. %s", strerror(errno));}if (mkdir("/dev/pts", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {INIT_LOGE("mkdir /dev/pts failed. %s", strerror(errno));}if (mount("devpts", "/dev/pts", "devpts", 0, NULL) != 0) {INIT_LOGE("Mount devpts failed. %s", strerror(errno));}if (mount("proc", "/proc", "proc", 0, "hidepid=2") != 0) {INIT_LOGE("Mount procfs failed. %s", strerror(errno));}if (mount("sysfs", "/sys", "sysfs", 0, NULL) != 0) {INIT_LOGE("Mount sysfs failed. %s", strerror(errno));}if (mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL) != 0) {INIT_LOGE("Mount selinuxfs failed. %s", strerror(errno));}
}
其中mount函数说明如下:
int mount( const char* source, const char* target, const char* filesystemtype, unsigned long mountflags, const void * data);
source : 待挂载的文件系统,通常是一个设备名
target : 挂载点
filesystemtype : 文件系统的类型,例如:"ext2","ext3","msdos","proc","nfs4","iso9660"
mountflags : 指定文件系统的读写访问标志.
值通常如下 :
MS_BIND : 执行bind挂载,使文件或者子目录树在文件系统内的另一个点上可视。
MS_DIRSYNC : 同步目录的更新。
MS_MANDLOCK : 允许在文件上执行强制锁。
MS_MOVE : 移动子目录树。
MS_NOATIME : 不要更新文件上的访问时间。
MS_NODEV : 不允许访问设备文件。
MS_NODIRATIME : 不允许更新目录上的访问时间。
MS_NOEXEC : 不允许在挂上的文件系统上执行程序。
MS_NOSUID : 执行程序时,不遵照set-user-ID 和 set-group-ID位。
MS_RDONLY : 指定文件系统为只读。
MS_REMOUNT : 重新加载文件系统。允许改变现存文件系统的mountflag和数据而无需先卸载再挂上文件系统
MS_SYNCHRONOUS : 同步文件的更新。
MNT_FORCE : 强制卸载,即使文件系统处于忙状态。
MNT_EXPIRE : 将挂载点标志为过时。
data : 文件系统特有的参数。函数成功执行时返回0。失败返回-1,errno被设为以下的某个值
EACCES : 权能不足,可能原因是:路径的一部分不可搜索或者挂载只读的文件系统时,没有指定 MS_RDONLY 标志。
EAGAIN : 成功地将不处于忙状态的文件系统标志为过时。
EBUSY : 1.源文件系统已被挂上或者不可以以只读的方式重新挂载,因为它还拥有以写方式打开的文件。2.目标处于忙状态。
EFAULT : 内存空间访问出错。
EINVAL : 操作无效,可能是源文件系统超级块无效。
ELOOP : 路径解析的过程中存在太多的符号连接。
EMFILE : 无需块设备要求的情况下,无用设备表已满。
ENAMETOOLONG : 路径名超出可允许的长度。
ENODEV : 内核不支持某中文件系统。
ENOENT : 路径名部分内容表示的目录不存在。
ENOMEM : 核心内存不足。
ENOTBLK : source不是块设备。
ENOTDIR : 路径名的部分内容不是目录。
EPERM : 调用者权能不足。
ENXIO : 块主设备号超出所允许的范围。

然后执行LogInit函数,依然在base/startup/init_lite/services/init/standard/init.c文件中。

void LogInit(void)
{CloseStdio();int ret = mknod("/dev/kmsg", S_IFCHR | S_IWUSR | S_IRUSR,makedev(MEM_MAJOR, DEV_KMSG_MINOR));if (ret == 0) {OpenLogDevice(); // base/startup/init_lite/services/log/init_log.c文件中,做了打开文件,获取设备描述符的操作。}
}

然后是函数CreateDeviceNode(),在文件base/startup/init_lite/services/init/standard/device.c中。

void CreateDeviceNode(void)
{if (mknod("/dev/null", S_IFCHR | DEFAULT_RW_MODE, makedev(MEM_MAJOR, DEV_NULL_MINOR)) != 0) {INIT_LOGE("Create /dev/null device node failed. %s", strerror(errno));}if (mknod("/dev/random", S_IFCHR | DEFAULT_RW_MODE, makedev(MEM_MAJOR, DEV_RANDOM_MINOR)) != 0) {INIT_LOGE("Create /dev/random device node failed. %s", strerror(errno));}if (mknod("/dev/urandom", S_IFCHR | DEFAULT_RW_MODE, makedev(MEM_MAJOR, DEV_URANDOM_MINOR)) != 0) {INIT_LOGE("Create /dev/urandom device node failed. %s", strerror(errno));}
}

然后进行判断是不是在升级模式 ,函数为InUpdaterMode(),在base/startup/init_lite/services/utils/init_utils.c文件中,

int InUpdaterMode(void)
{const char * const updaterExecutabeFile = "/bin/updater";if (access(updaterExecutabeFile, X_OK) == 0) { //判断/bin/updater文件是否有执行权限,由于文件不存在,所以不可能为0,那么此函数的返回值为0.return 1;} else {return 0;}
}access函数 : 确定文件或文件夹的访问权限。如果指定的存取方式有效,则函数返回0,否则函数返回-1。
R_OK 只判断是否有读权限
W_OK 只判断是否有写权限
X_OK 判断是否有执行权限
F_OK 只判断是否存在

然后执行StartInitSecondStage()函数,依然是在base/startup/init_lite/services/init/standard/init.c文件中

static void StartInitSecondStage(void)
{const char *fstabFile = "/etc/fstab.required";Fstab *fstab = NULL;if (access(fstabFile, F_OK) != 0) { //判断/etc/fstab.required文件是否存在fstabFile = "/system/etc/fstab.required"; //如果不存在,则使用/system/etc/fstab.required文件}//判断是否有/system/etc/fstab.required文件,不存在则报错。INIT_ERROR_CHECK(access(fstabFile, F_OK) == 0, abort(), "Failed get fstab.required");fstab = ReadFstabFromFile(fstabFile, false); //读取fstab.required文件的内容到fstab中,在base/startup/init_lite/interfaces/innerkits/fs_manager/fstab.c中实现INIT_ERROR_CHECK(fstab != NULL, abort(), "Read fstab file \" %s \" failed\n", fstabFile);int requiredNum = 0;char **devices = GetRequiredDevices(*fstab, &requiredNum);if (devices != NULL && requiredNum > 0) {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 abortINIT_LOGE("Mount requried partitions failed; please check fstab file");// Execute sh for debuggingexecv("/bin/sh", NULL);abort();}}
#ifndef DISABLE_INIT_TWO_STAGES //这里因为我们关闭了ramdisk所以这里是有这个定义的,所以以下不执行//base/startup/init_lite/services/BUILD.gn中的/*if (!enable_ramdisk) {defines += [ "DISABLE_INIT_TWO_STAGES" ]}*/SwitchRoot("/usr");// Execute init second stagechar * const args[] = {"/bin/init","--second-stage",NULL,};if (execv("/bin/init", args) != 0) {INIT_LOGE("Failed to exec \"/bin/init\", err = %d", errno);exit(-1);}
#endif
}

如果没有fstab.required文件,系统进入init后,会发生如下报错信息。

Freeing unused kernel memory: 1024K
Run /init as init process
[pid=1][INIT][INFO] [init.c:225)] DISABLE_INIT_TWO_STAGES not defined
[pid=1][INIT][ERROR] [init.c:175)] Failed get fstab.required
Kernel panic - not syncing: Attempted to kill init! exitcode=0x00000004
CPU: 1 PID: 1 Comm: init Not tainted 5.10.79 #1
Hardware name: Generic DT based system
[<c011105c>] (unwind_backtrace) from [<c010c770>] (show_stack+0x10/0x14)
[<c010c770>] (show_stack) from [<c05d0a14>] (dump_stack+0x90/0xc4)
[<c05d0a14>] (dump_stack) from [<c0120d78>] (panic+0x114/0x330)
[<c0120d78>] (panic) from [<c0125f90>] (complete_and_exit+0x0/0x1c)
[<c0125f90>] (complete_and_exit) from [<00000000>] (0x0)

如果有则会执行如下正确挂载的信息。

[    7.169987] [pid=1][INIT][INFO] [init.c:227)] DISABLE_INIT_TWO_STAGES not defined
[    7.184059] [pid=1][INIT][ERROR] [ueventd.c:297)] Failed get default_boot_device value from cmdline
[    7.339797] [pid=1][INIT][INFO] [ueventd.c:144)] Handle block device partitionName rootfs
[    7.355829] [pid=1][INIT][INFO] [ueventd.c:134)] Match with /dev/block/platform/soc@3000000/4020000.sdmmc/by-name/rootfs for /devices/platform/soc@3000000/4020000.sdmmc/mmc_host/mmc0/mmc0:1234/block/mmcblk0
[    7.376373] [pid=1][INIT][INFO] [ueventd.c:140)] uevent->syspath /devices/platform/soc@3000000/4020000.sdmmc/mmc_host/mmc0/mmc0:1234/block/mmcblk0 not match deviceName /platform/soc@3000000/4020000.sdmmc/by-name/rootfs
[    7.406339] [pid=1][INIT][INFO] [ueventd.c:144)] Handle block device partitionName vendor
[    8.064424] [pid=1][INIT][INFO] [init_mount.c:24)] Mount required partitions
[    8.957499] BEGET[pid=1][INIT][INFO] [fstab_mount.c:331)] Mount /dev/block/platform/soc@3000000/4020000.sdmmc/by-name/rootfs to /usr successful
[    9.478341] EXT4-fs (mmcblk0p6): mounted filesystem without journal. Opts: barrier=1
[    9.487070] BEGET[pid=1][INIT][INFO] [fstab_mount.c:331)] Mount /dev/block/platform/soc@3000000/4020000.sdmmc/by-name/vendor to /vendor successful
[    9.501871] [pid=1][INIT][INFO] [init_hashmap.c:49)] Create hash map success 0
[    9.509974] LoopEvent[pid=1][INIT][INFO] [le_signal.c:76)] LE_AddSignal 17 0
[    9.517879] LoopEvent[pid=1][INIT][INFO] [le_signal.c:76)] LE_AddSignal 15 1
[    9.526092] [pid=1][INIT][INFO] [init.c:87)] Init fd holder socket done
[    9.533586] [pid=1][INIT][INFO] [init_hashmap.c:49)] Create hash map success 0
[    9.541677] [pid=1][INIT][INFO] [init_hashmap.c:49)] Create hash map success 0
[    9.549751] [pid=1][INIT][INFO] [init_hashmap.c:49)] Create hash map success 0
[    9.557826] [pid=1][INIT][INFO] [init_hashmap.c:49)] Create hash map success 0
[    9.565969] [pid=1][INIT][ERROR] [init_group_manager.c:189)] Failed to get boot group

所以再来回顾下SystemPrepare()函数,其实就是做一些准备工作。

void SystemPrepare(void)
{MountBasicFs(); //挂载tmpfs,创建"/dev/pts",挂载devpts,proc,sysfs,selinuxfsLogInit();    //打开 "/dev/kmsg" 节点文件,获取设备描述符EnableDevKmsg(); //打开proc/sys/kernel/printk_devkmsg节点,往里面写入 "on"CreateDeviceNode(); //创建 /dev/null,/dev/random,/dev/urandom节点文件INIT_LOGI("DISABLE_INIT_TWO_STAGES not defined");if (InUpdaterMode() == 0) { //这里我们返回的是0,StartInitSecondStage(); //这里主要的功能就是将我们fatab文件里面的语句去做解析并执行挂载操作}
}

接着分析SystemInit()函数,实现在base/startup/init_lite/services/init/standard/init.c中,具体函数内容如下.

void SystemInit(void)
{SignalInit();// 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); //创建节点文件/dev/unix/socketint sock = FdHolderSockInit(); //if (sock >= 0) {RegisterFdHoldWatcher(sock);}
}
static int FdHolderSockInit(void)
{int sock = -1;int on = 1;int fdHolderBufferSize = FD_HOLDER_BUFFER_SIZE; // 4KiB//创建一个本地通信的socket,sock 是创建成功的套接字sock = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);if (sock < 0) {INIT_LOGE("Failed to create fd holder socket, err = %d", errno);return -1;}setsockopt(sock, SOL_SOCKET, SO_RCVBUFFORCE, &fdHolderBufferSize, sizeof(fdHolderBufferSize)); //设置接收缓冲区setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));//允许SCM_CREDENTIALS 控制消息的接收if (access(INIT_HOLDER_SOCKET_PATH, F_OK) == 0) { //#define INIT_HOLDER_SOCKET_PATH "/dev/unix/socket/fd_holder"INIT_LOGI("%s exist, remove it", INIT_HOLDER_SOCKET_PATH);unlink(INIT_HOLDER_SOCKET_PATH);}struct sockaddr_un addr;addr.sun_family = AF_UNIX;if (strncpy_s(addr.sun_path, sizeof(addr.sun_path),INIT_HOLDER_SOCKET_PATH, strlen(INIT_HOLDER_SOCKET_PATH)) != 0) {INIT_LOGE("Faild to copy fd hoder socket path");close(sock);return -1;}socklen_t len = (socklen_t)(offsetof(struct sockaddr_un, sun_path) + strlen(addr.sun_path) + 1);if (bind(sock, (struct sockaddr *)&addr, len) < 0) {INIT_LOGE("Failed to binder fd folder socket %d", errno);close(sock);return -1;}// Owned by rootif (lchown(addr.sun_path, 0, 0)) {INIT_LOGW("Failed to change owner of fd holder socket, err = %d", errno);}mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;if (fchmodat(AT_FDCWD, addr.sun_path, mode, AT_SYMLINK_NOFOLLOW)) {INIT_LOGW("Failed to change mode of fd holder socket, err = %d", errno);}INIT_LOGI("Init fd holder socket done");return sock;
}

接着分析SystemExecuteRcs(),在文件base/startup/init_lite/services/init/adapter/init_adapter.c中,具体函数内容如下

void SystemExecuteRcs(void)
{//通过查看 base/startup/init_lite/services/BUILD.gn可以发现只有小型系统并且是linux内核才会定义NEED_EXEC_RCS_LINUX,所以我们标准系统的话这里是不执行
#if (defined __LINUX__) && (defined NEED_EXEC_RCS_LINUX) //这里pid_t retPid = fork();if (retPid < 0) {INIT_LOGE("ExecuteRcs, fork failed! err %d.", errno);return;}// child processif (retPid == 0) {INIT_LOGI("ExecuteRcs, child process id %d.", getpid());if (execle("/bin/sh", "sh", "/etc/init.d/rcS", NULL, NULL) != 0) {INIT_LOGE("ExecuteRcs, execle failed! err %d.", errno);}_exit(0x7f); // 0x7f: user specified}// init processsem_t sem;if (sem_init(&sem, 0, 0) != 0) {INIT_LOGE("ExecuteRcs, sem_init failed, err %d.", errno);return;}SignalRegWaitSem(retPid, &sem);// wait until rcs process exitedif (sem_wait(&sem) != 0) {INIT_LOGE("ExecuteRcs, sem_wait failed, err %d.", errno);}
#endif
}

然后是SystemConfig()函数,在base/startup/init_lite/services/init/standard/init.c中,可以看出内容还是有点多的。

void SystemConfig(void)
{InitServiceSpace();InitParseGroupCfg();PluginManagerInit();InitParamService();RegisterBootStateChange(BootStateChange);// load SELinux context and policy// Do not move position!SystemLoadSelinux();// parse parametersLoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL);LoadDefaultParams("/vendor/etc/param", LOAD_PARAM_NORMAL);LoadDefaultParams("/system/etc/param", LOAD_PARAM_ONLY_ADD);// read configReadConfig();INIT_LOGI("Parse init config file done.");// dump config
#if defined(OHOS_SERVICE_DUMP)AddCmdExecutor("display", SystemDump);(void)AddCompleteJob("param:ohos.servicectrl.display", "ohos.servicectrl.display=*", "display system");
#endif// execute initPostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
}
void InitServiceSpace(void)
{if (g_initWorkspace.initFlags != 0) {return;}HashInfo info = {GroupNodeNodeCompare, //这里为函数指针,info中的nodeCompare=GroupNodeNodeCompare函数GroupNodeKeyCompare, //keyCompare = GroupNodeKeyCompareGroupNodeGetNodeHashCode,//nodeHash = GroupNodeGetNodeHashCodeGroupNodeGetKeyHashCode, //keyHash = GroupNodeGetKeyHashCodeGroupNodeFree, //nodeFree = GroupNodeFreeGROUP_HASHMAP_BUCKET //maxBucket = GROUP_HASHMAP_BUCKET #define GROUP_HASHMAP_BUCKET 32};for (size_t i = 0; i < ARRAY_LENGTH(g_initWorkspace.hashMap); i++) { //ARRAY_LENGTH(g_initWorkspace.hashMap) = 4int ret = HashMapCreate(&g_initWorkspace.hashMap[i], &info); //将info给hashMap,处理后得到的结果为,g_initWorkspace.hashMap[0,1,2,3]都指向了info结构体数据,即后面操作g_initWorkspace.hashMap就是操作infoif (ret != 0) {INIT_LOGE("%s", "Failed to create hash map");}}for (int i = 0; i < NODE_TYPE_MAX; i++) {g_initWorkspace.groupNodes[i] = NULL;}// get boot modechar *data = ReadFileData(BOOT_CMD_LINE);//#define BOOT_CMD_LINE "/proc/cmdline"if (data != NULL) {int ret = GetProcCmdlineValue(BOOT_GROUP_NAME, data, //#define BOOT_GROUP_NAME "bootgroup"g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr)); //所以这里主要是在/proc/cmdline值中寻找 bootgroup字段的值 ,我们这里是没有这个字段的值的if (ret != 0) {INIT_LOGE("%s", "Failed to get boot group"); //我们这里会打印这个,因为我们的cmdline值为: earlycon=uart8250,mmio32,0x05000000 clk_ignore_unused initcall_debug=0 console=ttyS0,115200 loglevel=8 root=/dev/mmcblk0p5 rw init=/init partitions=boot-resource@mmcblk0p1:env@mmcblk0p2:env-redund@mmcblk0p3:boot@mmcblk0p4:rootfs@mmcblk0p5:vendor@mmcblk0p6:userdata@mmcblk0p7:dsp0@mmcblk0p8:private@mmcblk0p9:UDISK@mmcblk0p10 cma=16M snum= mac_addr= wifi_mac= bt_mac= specialstr= gpt=1 androidboot.hardware=sun8iw20p1 boot_type=1 androidboot.boot_type=1 gpt=1 uboot_message=2018.05(04/26/2022-01:24:39) disp_reserve=2457600,0x448ee000 androidboot.dramsize=128
#ifdef INIT_TEST //这里在base/startup/init_lite/begetd.gni中定义为true,所以我们执行这里if (GetBootModeFromMisc() == GROUP_CHARING) { //这里我们没有miscstrcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), "device.charing.group");} else {strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), BOOT_GROUP_DEFAULT); // #define BOOT_GROUP_DEFAULT "device.boot.group"}
#elsestrcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), BOOT_GROUP_DEFAULT);
#endif}free(data);}INIT_LOGI("boot start %s", g_initWorkspace.groupModeStr); //boot start device.boot.groupg_initWorkspace.groupMode = GetBootGroupMode(); //这里等于0/*static int GetBootGroupMode(void)
{static const char *groupModes[] = {"device.boot.group","device.charing.group"};for (size_t i = 0; i < ARRAY_LENGTH(groupModes); i++) {if (strcmp(g_initWorkspace.groupModeStr, groupModes[i]) == 0) {return i;}}return (int)GROUP_UNKNOW;
}*/g_initWorkspace.initFlags = 1;
}

然后是函数InitParseGroupCfg(),

int InitParseGroupCfg(void)
{char buffer[128] = {0}; // 128 buffer sizechar *realPath = GetAbsolutePath(GROUP_DEFAULT_PATH, // #define GROUP_DEFAULT_PATH "/system/etc"//上面函数执行完成后,realPath = /system/etc/device.boot.group.cfgg_initWorkspace.groupModeStr, buffer, sizeof(buffer));INIT_ERROR_CHECK(realPath != NULL, return -1,"Failed to get path for %s", g_initWorkspace.groupModeStr);InitParseGroupCfg_(realPath);InitGroupNode *groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];int level = 0;while ((groupRoot != NULL) && (level < GROUP_IMPORT_MAX_LEVEL)) { // for more importg_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;InitImportGroupCfg_(groupRoot);groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];level++;}InitFreeGroupNodes_(g_initWorkspace.groupNodes[NODE_TYPE_GROUPS]);g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;return 0;
}
void InitParamService(void)
{PARAM_LOGI("InitParamService pipe: %s.", PIPE_NAME); // #define PIPE_NAME "/dev/unix/socket/paramservice"CheckAndCreateDir(PIPE_NAME); //确认有没有目标,没有就创建int ret = InitParamWorkSpace(&g_paramWorkSpace, 0);PARAM_CHECK(ret == 0, return, "Init parameter workspace fail");ret = InitPersistParamWorkSpace(&g_paramWorkSpace);PARAM_CHECK(ret == 0, return, "Init persist parameter workspace fail");if (g_paramWorkSpace.serverTask == NULL) {ParamStreamInfo info = {};info.server = PIPE_NAME;info.close = NULL;info.recvMessage = NULL;info.incomingConnect = OnIncomingConnect;ret = ParamServerCreate(&g_paramWorkSpace.serverTask, &info);PARAM_CHECK(ret == 0, return, "Failed to create server");}ret = InitTriggerWorkSpace();PARAM_CHECK(ret == 0, return, "Failed to init trigger");RegisterTriggerExec(TRIGGER_PARAM_WAIT, ExecuteWatchTrigger_);RegisterTriggerExec(TRIGGER_PARAM_WATCH, ExecuteWatchTrigger_);ParamAuditData auditData = {};auditData.name = "#";auditData.label = NULL;auditData.dacData.gid = getegid();auditData.dacData.uid = geteuid();auditData.dacData.mode = DAC_ALL_PERMISSION;ret = AddSecurityLabel(&auditData, (void *)&g_paramWorkSpace);PARAM_CHECK(ret == 0, return, "Failed to add default dac label");// 读取cmdline的参数LoadParamFromCmdLine();
}
去掉多余的判断后函数,然后我们是定义了DISABLE_INIT_TWO_STAGES
#ifndef DISABLE_INIT_TWO_STAGES
#define INIT_CONFIGURATION_FILE "/etc/init.cfg"
#else
#define INIT_CONFIGURATION_FILE "/etc/init.without_two_stages.cfg"
#endif
#define OTHER_CFG_PATH "/system/etc/init"
#define MAX_PATH_ARGS_CNT 20void ReadConfig(void)
{ParseInitCfg(INIT_CONFIGURATION_FILE, NULL); //这里是/etc/init.without_two_stages.cfg"文件ReadFileInDir(OTHER_CFG_PATH, ".cfg", ParseInitCfg, NULL); // /system/etc/init/下的cfg文件ReadFileInDir("/vendor/etc/init", ".cfg", ParseInitCfg, NULL); //vendor/etc/init下的文件}

所以再回过头来看SystemConfig()函数功能

void SystemConfig(void)
{InitServiceSpace();  //主要就是给g_initWorkspace结构体赋值/*g_initWorkspace.hashMap[0,1,2,3] = info;g_initWorkspace->groupNodes[0,1,2,3,4] =NULL;g_initWorkspace.groupModeStr = "device.boot.group";g_initWorkspace.groupMode = 0;g_initWorkspace.initFlags = 1;*/InitParseGroupCfg(); //将解析的cfg值放入对应的groupNodes中PluginManagerInit();// 处理system/lib/libplugin.z.so文件并解析/system/etc/plugin_modules.cfgInitParamService();RegisterBootStateChange(BootStateChange); //g_triggerWorkSpace.bootStateChange = BootStateChange;// load SELinux context and policy// Do not move position!SystemLoadSelinux(); //我这里没有定义WITH_SELINUX,所以不执行// parse parametersLoadDefaultParams("/system/etc/param/ohos_const", LOAD_PARAM_NORMAL); //不存在,所以执行失败LoadDefaultParams("/vendor/etc/param", LOAD_PARAM_NORMAL); //没有目录执行失败LoadDefaultParams("/system/etc/param", LOAD_PARAM_ONLY_ADD); //加载/system/etc/param里面的.para文件以及.dac文件,这些文件目前是做什么用还不得知// read configReadConfig();INIT_LOGI("Parse init config file done.");// dump config
#if defined(OHOS_SERVICE_DUMP)AddCmdExecutor("display", SystemDump);(void)AddCompleteJob("param:ohos.servicectrl.display", "ohos.servicectrl.display=*", "display system");
#endif// execute initPostTrigger(EVENT_TRIGGER_BOOT, "pre-init", strlen("pre-init"));PostTrigger(EVENT_TRIGGER_BOOT, "init", strlen("init"));PostTrigger(EVENT_TRIGGER_BOOT, "post-init", strlen("post-init"));
}

我修改这里让它不执行读取其他目录的cfg文件,可以进入终端不卡端了,方便调试HDC功能了,所以就不追踪下去了。

等发现其他问题再继续追。

openharmony标准系统移植之init启动流程分析相关推荐

  1. Ubuntu init启动流程分析浅析

    Ubuntu init启动流程 Linux distros主流的有两种init方式: 一种是System V initialization,它来源于Unix并至今仍被各种Linux distros所采 ...

  2. Android系统开机到Launcher启动流程分析

    本文基于Android10.0的源码. 由于google团队在对framework层代码进行大量重构,所以代码变动还是挺大的. 常见基础问题: SystemServer系统服务进程是如何创建的?Lau ...

  3. openharmony标准系统移植之添加产品编译

    首先我这里下载的是源码文件包的形式,如下图,我们使用 命令 tar xvf code-v3.1-Release.tar.gz进行解压文件.解压完成后如下图,多了code-v3.1-Release文件夹 ...

  4. PackageManagerService启动详解(七)之扫描系统应用安装目录阶段流程分析

    PKMS启动详解(七)之BOOT_PROGRESS_PMS_SYSTEM_SCAN_START阶段流程分析 Android PackageManagerService系列博客目录: PKMS启动详解系 ...

  5. Exynos4412 Uboot 移植(二)—— Uboot 启动流程分析

    uboot启动流程分析如下: 第一阶段: a -- 设置cpu工作模式为SVC模式 b -- 关闭中断,mmu,cache v -- 关看门狗 d -- 初始化内存,串口 e -- 设置栈 f -- ...

  6. u-boot启动流程分析(1)_平台相关部分

    转自:http://www.wowotech.net/u-boot/boot_flow_1.html 1. 前言 本文将结合u-boot的"board->machine->arc ...

  7. RISC-V Linux 启动流程分析

    " Author:  通天塔 985400330@qq.com Date:    2022/05/15 Revisor: lzufalcon falcon@tinylab.org Proje ...

  8. c++builder启动了怎么停止_App 竟然是这样跑起来的 —— Android App/Activity 启动流程分析...

    在我的上一篇文章: AJie:按下电源键后竟然发生了这一幕 -- Android 系统启动流程分析​zhuanlan.zhihu.com 我们分析了系统在开机以后的一系列行为,其中最后一阶段 AMS( ...

  9. bootloader启动流程分析

    bootloader启动流程分析 1.Bootloader的概念和作用 Bootloader是嵌入式系统的引导加载程序,它是系统上电后运行的第一段程序.在完成对系统的初始化任务之后,它会将Flash中 ...

最新文章

  1. 随笔之如何实现一个线程池
  2. C#实现微信AES-128-CBC加密数据的解密
  3. 云边协同 — 协同的类型
  4. Java常见的几种排序算法-插入、选择、冒泡、快排、堆排等
  5. WordPress Kyma plugin检测kyma连接状态的逻辑
  6. Loj#2035-[SDOI2016]征途【斜率优化】
  7. 持续集成之Jenkins安装部署
  8. 跨地域的VPC私网互通【高速通道案例】
  9. 工信部:三大运营商移动电话用户总数达15.92亿户 同比增长0.2%
  10. c/c++常见关键字
  11. 直接插入排序和冒泡排序有什么区别 直接插入排序和冒泡排序有哪些不同
  12. 登录个税显示局端服务器显示,天津金税三期个人所得税扣缴系统
  13. JAVA类计算机专业毕业设计题目
  14. 信息学奥赛一本通C++语言——1129:统计数字字符个数
  15. CentOS7部署WeADMIN监控主机交换机和URL(无坑版)
  16. matlab生成音阶,MATLAB 数字电子琴的功能 电子琴的每个音阶均对应一个特定频率的信号 联合开发网 - pudn.com...
  17. 网页游戏运营模式研究
  18. 文件追加 c语言,c语言追加方式想文件里面写东西
  19. 大学四年的生活规划——做一个清醒的奋斗者
  20. java基础学安卓开发_Android开发学习路线之Java基础学习

热门文章

  1. 2022摄影摄像行业年度分析报告:单反小幅下滑,微单销额增长超32%
  2. 数据结构期末大题速成
  3. 【OptiX】第6个示例 折射,玻璃材质
  4. 身份证识别+人脸识别---“人证合一”查验系统
  5. 如何通过UTON WALLET数字钱包创建和使用你的元宇宙身份
  6. CF1292C Xenon‘s Attack on the Gangs
  7. 【CSS】三行实现一个黑白网格背景(渐变)
  8. sudo、sudo -s、sudo -i、su 区别
  9. C#控制键盘按键的常用方法
  10. 《Programming in Lua 3》读书笔记(十)