• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "bootevent.h"
16 
17 #include <stdbool.h>
18 #include "init_module_engine.h"
19 #include "init_group_manager.h"
20 #include "init_cmdexecutor.h"
21 #include "trigger_manager.h"
22 #include "init_log.h"
23 #include "plugin_adapter.h"
24 #include "init_hook.h"
25 #include "init_service.h"
26 #include "bootstage.h"
27 #include "securec.h"
28 #include "init_utils.h"
29 #include "init_cmds.h"
30 #include "config_policy_utils.h"
31 
32 #ifdef WITH_SELINUX
33 #include <policycoreutils.h>
34 #endif
35 #ifndef STARTUP_INIT_TEST
36 static const int SLEPP_TIME = 100;
37 #endif
38 
GetBootSwitchEnable(const char * paramName)39 static int GetBootSwitchEnable(const char *paramName)
40 {
41     char bootEventOpen[6] = ""; // 6 is length of bool value
42     uint32_t len = sizeof(bootEventOpen);
43     SystemReadParam(paramName, bootEventOpen, &len);
44     if (strcmp(bootEventOpen, "true") == 0 || strcmp(bootEventOpen, "1") == 0) {
45         return 1;
46     }
47     return 0;
48 }
49 
50 static int g_bootEventNum = 0;
51 
52 static ListNode bootEventList = {&bootEventList, &bootEventList};
53 
BootEventParaListCompareProc(ListNode * node,void * data)54 static int BootEventParaListCompareProc(ListNode *node, void *data)
55 {
56     BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)node;
57     if (strncmp(item->paramName, BOOT_EVENT_PARA_PREFIX, BOOT_EVENT_PARA_PREFIX_LEN) != 0) {
58         return -1;
59     }
60     if (strcmp(item->paramName + BOOT_EVENT_PARA_PREFIX_LEN, (const char *)data) == 0) {
61         return 0;
62     }
63     return -1;
64 }
65 
ParseBooteventCompareProc(ListNode * node,void * data)66 static int ParseBooteventCompareProc(ListNode *node, void *data)
67 {
68     BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)node;
69     if (strcmp(item->paramName, (const char *)data) == 0) {
70         return 0;
71     }
72     return -1;
73 }
74 
AddBootEventItem(BOOT_EVENT_PARAM_ITEM * item,const char * paramName)75 static int AddBootEventItem(BOOT_EVENT_PARAM_ITEM *item, const char *paramName)
76 {
77     OH_ListInit(&item->node);
78     for (int i = 0; i < BOOTEVENT_MAX; i++) {
79         item->timestamp[i].tv_nsec = 0;
80         item->timestamp[i].tv_sec = 0;
81     }
82     item->paramName = strdup(paramName);
83     if (item->paramName == NULL) {
84         free(item);
85         return -1;
86     }
87     item->flags = BOOTEVENT_TYPE_SERVICE;
88     OH_ListAddTail(&bootEventList, (ListNode *)&item->node);
89     g_bootEventNum++;
90     return 0;
91 }
92 
AddBootEventItemByName(const char * paramName)93 static int AddBootEventItemByName(const char *paramName)
94 {
95     BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)calloc(1, sizeof(BOOT_EVENT_PARAM_ITEM));
96     if (item == NULL) {
97         return -1;
98     }
99 
100     return AddBootEventItem(item, paramName);
101 }
102 
SetServiceBooteventHookMgr(const char * serviceName,const char * paramName,int state)103 static void SetServiceBooteventHookMgr(const char *serviceName, const char *paramName, int state)
104 {
105 #ifndef STARTUP_INIT_TEST
106     SERVICE_BOOTEVENT_CTX context;
107     context.serviceName = serviceName;
108     context.reserved = paramName;
109     context.state = state;
110     HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_BOOTEVENT, (void*)(&context), NULL);
111 #endif
112 }
113 
114 
AddServiceBootEvent(const char * serviceName,const char * paramName)115 static int AddServiceBootEvent(const char *serviceName, const char *paramName)
116 {
117     ServiceExtData *extData = NULL;
118     ListNode *found = NULL;
119     if ((paramName == NULL) || (strncmp(paramName, BOOT_EVENT_PARA_PREFIX, BOOT_EVENT_PARA_PREFIX_LEN) != 0)) {
120         return -1;
121     }
122     found = OH_ListFind(&bootEventList, (void *)paramName, ParseBooteventCompareProc);
123     if (found != NULL) {
124         return -1;
125     }
126     // Find an empty bootevent data position
127     for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
128         extData = AddServiceExtData(serviceName, i, NULL, sizeof(BOOT_EVENT_PARAM_ITEM));
129         if (extData != NULL) {
130             break;
131         }
132     }
133 
134     INIT_CHECK(extData != NULL, return -1);
135 
136     BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)extData->data;
137 
138     if (AddBootEventItem(item, paramName) != 0) {
139         DelServiceExtData(serviceName, extData->dataId);
140         return -1;
141     }
142 
143     SetServiceBooteventHookMgr(serviceName, paramName, 1);
144     return 0;
145 }
146 
AddInitBootEvent(const char * bootEventName)147 static void AddInitBootEvent(const char *bootEventName)
148 {
149     BOOT_EVENT_PARAM_ITEM *found = NULL;
150     found = (BOOT_EVENT_PARAM_ITEM *)OH_ListFind(&bootEventList, (void *)bootEventName, ParseBooteventCompareProc);
151     if (found != NULL) {
152         (void)clock_gettime(CLOCK_MONOTONIC, &(found->timestamp[BOOTEVENT_READY]));
153         return;
154     }
155 
156     BOOT_EVENT_PARAM_ITEM *item = calloc(1, sizeof(BOOT_EVENT_PARAM_ITEM));
157     INIT_CHECK(item != NULL, return);
158 
159     OH_ListInit(&item->node);
160 
161     (void)clock_gettime(CLOCK_MONOTONIC, &(item->timestamp[BOOTEVENT_FORK]));
162 
163     item->paramName = strdup(bootEventName);
164     INIT_CHECK(item->paramName != NULL, free(item);
165         return);
166 
167     item->flags = BOOTEVENT_TYPE_JOB;
168     OH_ListAddTail(&bootEventList, (ListNode *)&item->node);
169     return;
170 }
171 
172 #define BOOT_EVENT_BOOT_COMPLETED "bootevent.boot.completed"
173 
BootEventDestroy(ListNode * node)174 static void BootEventDestroy(ListNode *node)
175 {
176     BOOT_EVENT_PARAM_ITEM *bootEvent = (BOOT_EVENT_PARAM_ITEM *)node;
177     INIT_CHECK(bootEvent->paramName == NULL, free((void *)bootEvent->paramName));
178     free((void *)bootEvent);
179 }
180 
AddItemToJson(cJSON * root,const char * name,double startTime,int pid,double durTime)181 static int AddItemToJson(cJSON *root, const char *name, double startTime, int pid, double durTime)
182 {
183     cJSON *obj = cJSON_CreateObject(); // release obj at traverse done
184     INIT_CHECK_RETURN_VALUE(obj != NULL, -1);
185     cJSON_AddStringToObject(obj, "name", name);
186     cJSON_AddNumberToObject(obj, "ts", startTime);
187     cJSON_AddStringToObject(obj, "ph", "X");
188     cJSON_AddNumberToObject(obj, "pid", pid);
189     cJSON_AddNumberToObject(obj, "tid", pid);
190     cJSON_AddNumberToObject(obj, "dur", durTime);
191     cJSON_AddItemToArray(root, obj);
192     return 0;
193 }
194 
BootEventTraversal(ListNode * node,void * root)195 static int BootEventTraversal(ListNode *node, void *root)
196 {
197     static int start = 0;
198     BOOT_EVENT_PARAM_ITEM *item = (BOOT_EVENT_PARAM_ITEM *)node;
199     double forkTime = (double)item->timestamp[BOOTEVENT_FORK].tv_sec * MSECTONSEC +
200         (double)item->timestamp[BOOTEVENT_FORK].tv_nsec / USTONSEC;
201     double readyTime = (double)item->timestamp[BOOTEVENT_READY].tv_sec * MSECTONSEC +
202         (double)item->timestamp[BOOTEVENT_READY].tv_nsec / USTONSEC;
203     double durTime = readyTime - forkTime;
204     if (item->pid == 0) {
205         if (durTime < SAVEINITBOOTEVENTMSEC) {
206             return 0;
207         }
208         item->pid = 1; // 1 is init pid
209     }
210     if (start == 0) {
211         // set trace start time 0
212         INIT_CHECK_RETURN_VALUE(AddItemToJson((cJSON *)root, item->paramName, 0,
213             1, 0) == 0, -1);
214         start++;
215     }
216     INIT_CHECK_RETURN_VALUE(AddItemToJson((cJSON *)root, item->paramName, forkTime,
217         item->pid, durTime > 0 ? durTime : 0) == 0, -1);
218     return 0;
219 }
220 
CreateBootEventFile(const char * file,mode_t mode)221 static int CreateBootEventFile(const char *file, mode_t mode)
222 {
223     if (access(file, F_OK) == 0) {
224         INIT_LOGW("File %s already exist", file);
225         return 0;
226     }
227     if (errno != ENOENT) {
228         INIT_LOGW("Failed to access %s, err = %d", file, errno);
229         return -1;
230     }
231     CheckAndCreateDir(file);
232     int fd = open(file, O_CREAT, mode);
233     if (fd < 0) {
234         INIT_LOGE("Failed create %s, err=%d", file, errno);
235         return -1;
236     }
237     close(fd);
238 #ifdef WITH_SELINUX
239     INIT_LOGI("start to restorecon selinux");
240     (void)RestoreconRecurse(BOOTEVENT_OUTPUT_PATH);
241 #endif
242     return 0;
243 }
244 
SaveServiceBootEvent()245 static int SaveServiceBootEvent()
246 {
247     INIT_CHECK(GetBootSwitchEnable("persist.init.bootuptrace.enable"), return 0);
248 
249     int ret = CreateBootEventFile(BOOTEVENT_OUTPUT_PATH "bootup.trace", S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
250     INIT_CHECK_RETURN_VALUE(ret == 0, -1);
251     FILE *tmpFile = fopen(BOOTEVENT_OUTPUT_PATH "bootup.trace", "wr");
252     INIT_CHECK_RETURN_VALUE(tmpFile != NULL, -1);
253     cJSON *root = cJSON_CreateArray();
254     INIT_CHECK(root != NULL, (void)fclose(tmpFile);
255         return -1);
256 
257     OH_ListTraversal(&bootEventList, (void *)root, BootEventTraversal, 0);
258     char *buff = cJSON_Print(root);
259     if (buff == NULL) {
260         cJSON_Delete(root);
261         (void)fclose(tmpFile);
262         return -1;
263     }
264     INIT_CHECK_ONLY_ELOG(fprintf(tmpFile, "%s\n", buff) >= 0, "save boot event file failed");
265     free(buff);
266     cJSON_Delete(root);
267     (void)fflush(tmpFile);
268     (void)fclose(tmpFile);
269     return 0;
270 }
271 
ReportSysEvent(void)272 static void ReportSysEvent(void)
273 {
274     INIT_CHECK(GetBootSwitchEnable("persist.init.bootevent.enable"), return);
275 #ifndef STARTUP_INIT_TEST
276     InitModuleMgrInstall("eventmodule");
277     InitModuleMgrUnInstall("eventmodule");
278 #endif
279     return;
280 }
281 
BootCompleteClearAll(void)282 static void BootCompleteClearAll(void)
283 {
284     InitGroupNode *node = GetNextGroupNode(NODE_TYPE_SERVICES, NULL);
285     while (node != NULL) {
286         if (node->data.service == NULL) {
287             node = GetNextGroupNode(NODE_TYPE_SERVICES, node);
288             continue;
289         }
290         for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
291             ServiceExtData *extData = GetServiceExtData(node->name, i);
292             if (extData == NULL) {
293                 return;
294             }
295             free(((BOOT_EVENT_PARAM_ITEM *)extData->data)->paramName);
296             OH_ListRemove(&((BOOT_EVENT_PARAM_ITEM *)extData->data)->node);
297             DelServiceExtData(node->name, i);
298         }
299     }
300 
301     // clear init boot event
302     OH_ListRemoveAll(&bootEventList, BootEventDestroy);
303     g_bootEventNum = 0;
304 }
305 
WriteBooteventSysParam(const char * paramName)306 static void WriteBooteventSysParam(const char *paramName)
307 {
308     char buf[64];
309     long long uptime;
310     char name[PARAM_NAME_LEN_MAX];
311 
312     uptime = GetUptimeInMicroSeconds(NULL);
313 
314     INIT_CHECK_ONLY_ELOG(snprintf_s(buf, sizeof(buf), sizeof(buf) - 1, "%lld", uptime) >= 0,
315                          "snprintf_s buf failed");
316     INIT_CHECK_ONLY_ELOG(snprintf_s(name, sizeof(name), sizeof(name) - 1, "ohos.boot.time.%s", paramName) >= 0,
317                          "snprintf_s name failed");
318     SystemWriteParam(name, buf);
319 }
320 
321 #ifndef STARTUP_INIT_TEST
DelayedHookMgrExecute(TimerHandle handler,void * context)322 static void DelayedHookMgrExecute(TimerHandle handler, void *context)
323 {
324     UNUSED(context);
325     INIT_LOGI("Executing delayed HookMgrExecute after sleep");
326     HookMgrExecute(GetBootStageHookMgr(), INIT_BOOT_COMPLETE, NULL, NULL);
327     LE_StopTimer(LE_GetDefaultLoop(), handler);
328 }
329 
ScheduleDelayedHookMgrExecute(void)330 static int ScheduleDelayedHookMgrExecute(void)
331 {
332     TimerHandle timer;
333     LE_STATUS status = LE_CreateTimer(LE_GetDefaultLoop(), &timer, DelayedHookMgrExecute, NULL);
334     if (status != LE_SUCCESS) {
335         INIT_LOGE("Failed to create timer for delayed HookMgrExecute");
336         return -1;
337     }
338 
339     status = LE_StartTimer(LE_GetDefaultLoop(), timer, SLEPP_TIME, 0);
340     if (status != LE_SUCCESS) {
341         LE_StopTimer(LE_GetDefaultLoop(), timer);
342         INIT_LOGE("Failed to start timer for delayed HookMgrExecute");
343         return -1;
344     }
345     return 0;
346 }
347 #endif
348 
349 
BootEventParaFireByName(const char * paramName)350 static int BootEventParaFireByName(const char *paramName)
351 {
352     BOOT_EVENT_PARAM_ITEM *found = NULL;
353 
354     char *bootEventValue = strrchr(paramName, '.');
355     INIT_CHECK(bootEventValue != NULL, return 0);
356     bootEventValue[0] = '\0';
357 
358     WriteBooteventSysParam(paramName);
359 
360     found = (BOOT_EVENT_PARAM_ITEM *)OH_ListFind(&bootEventList, (void *)paramName, BootEventParaListCompareProc);
361     if (found == NULL) {
362         return 0;
363     }
364 
365     // Already fired
366     if (found->timestamp[BOOTEVENT_READY].tv_sec > 0) {
367         return 0;
368     }
369     INIT_CHECK_RETURN_VALUE(clock_gettime(CLOCK_MONOTONIC,
370         &(found->timestamp[BOOTEVENT_READY])) == 0, 0);
371 
372     g_bootEventNum--;
373     SetServiceBooteventHookMgr(NULL, paramName, 2); // 2: bootevent service has ready
374     // Check if all boot event params are fired
375     if (g_bootEventNum > 0) {
376         return 0;
377     }
378     // All parameters are fired, set boot completed now ...
379     INIT_LOGI("All boot events are fired, boot complete now ...");
380     SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "true");
381     SetBootCompleted(true);
382     SaveServiceBootEvent();
383     // report complete event
384     ReportSysEvent();
385     BootCompleteClearAll();
386 #ifndef STARTUP_INIT_TEST
387     if (ScheduleDelayedHookMgrExecute() != 0) {
388         INIT_LOGE("Failed to schedule delayed HookMgrExecute, executing directly");
389         HookMgrExecute(GetBootStageHookMgr(), INIT_BOOT_COMPLETE, NULL, NULL);
390     }
391 #endif
392     RemoveCmdExecutor("bootevent", -1);
393     return 1;
394 }
395 
396 #define BOOT_EVENT_FIELD_NAME "bootevents"
ServiceParseBootEventHook(SERVICE_PARSE_CTX * serviceParseCtx)397 static void ServiceParseBootEventHook(SERVICE_PARSE_CTX *serviceParseCtx)
398 {
399     int cnt;
400     cJSON *bootEvents = cJSON_GetObjectItem(serviceParseCtx->serviceNode, BOOT_EVENT_FIELD_NAME);
401 
402     // No boot events in config file
403     if (bootEvents == NULL) {
404         return;
405     }
406     SERVICE_INFO_CTX ctx = {0};
407     ctx.serviceName = serviceParseCtx->serviceName;
408     HookMgrExecute(GetBootStageHookMgr(), INIT_SERVICE_CLEAR, (void *)&ctx, NULL);
409     // Single boot event in config file
410     if (!cJSON_IsArray(bootEvents)) {
411         if (AddServiceBootEvent(serviceParseCtx->serviceName,
412             cJSON_GetStringValue(bootEvents)) != 0) {
413             INIT_LOGI("Add service bootEvent failed %s", serviceParseCtx->serviceName);
414             return;
415         }
416         return;
417     }
418 
419     // Multiple boot events in config file
420     cnt = cJSON_GetArraySize(bootEvents);
421     for (int i = 0; i < cnt; i++) {
422         cJSON *item = cJSON_GetArrayItem(bootEvents, i);
423         if (AddServiceBootEvent(serviceParseCtx->serviceName,
424             cJSON_GetStringValue(item)) != 0) {
425             INIT_LOGI("Add service bootEvent failed %s", serviceParseCtx->serviceName);
426             continue;
427         }
428     }
429 }
430 
431 static int g_finished = 0;
DoBootEventCmd(int id,const char * name,int argc,const char ** argv)432 static int DoBootEventCmd(int id, const char *name, int argc, const char **argv)
433 {
434     if (g_finished) {
435         return 0;
436     }
437 
438     PLUGIN_CHECK(argc >= 1, return -1, "Invalid parameter");
439     if (strcmp(argv[0], "init") == 0) {
440         if (argc < 2) { // 2 args
441             return 0;
442         }
443         AddInitBootEvent(argv[1]);
444     } else {
445         // argv[0] samgr.ready.true
446         g_finished = BootEventParaFireByName(argv[0]);
447     }
448     return 0;
449 }
450 
AddReservedBooteventsByFile(const char * name)451 static void AddReservedBooteventsByFile(const char *name)
452 {
453     char buf[MAX_PATH_LEN];
454 
455     FILE *file = fopen(name, "r");
456     if (file == NULL) {
457         return;
458     }
459 
460     while (fgets((void *)buf, sizeof(buf) - 1, file)) {
461         buf[sizeof(buf) - 1] = '\0';
462         char *end = strchr(buf, '\r');
463         if (end != NULL) {
464             *end = '\0';
465         }
466         end = strchr(buf, '\n');
467         if (end != NULL) {
468             *end = '\0';
469         }
470         INIT_LOGI("Got priv-app bootevent: %s", buf);
471         AddBootEventItemByName(buf);
472     }
473     (void)fclose(file);
474 }
475 
AddReservedBootevents(void)476 static void AddReservedBootevents(void)
477 {
478     CfgFiles *files = GetCfgFiles("etc/init/priv_app.bootevents");
479     for (int i = MAX_CFG_POLICY_DIRS_CNT - 1; files && i >= 0; i--) {
480         if (files->paths[i]) {
481             AddReservedBooteventsByFile(files->paths[i]);
482         }
483     }
484     FreeCfgFiles(files);
485 }
486 
DoUnsetBootEventCmd(int id,const char * name,int argc,const char ** argv)487 static int DoUnsetBootEventCmd(int id, const char *name, int argc, const char **argv)
488 {
489     if ((argc < 1) || (argv[0] == NULL) || (strlen(argv[0]) <= strlen(BOOT_EVENT_PARA_PREFIX)) ||
490         (strncmp(argv[0], BOOT_EVENT_PARA_PREFIX, strlen(BOOT_EVENT_PARA_PREFIX)) != 0)) {
491         return INIT_EPARAMETER;
492     }
493     const char *eventName = argv[0] + strlen(BOOT_EVENT_PARA_PREFIX);
494     BOOT_EVENT_PARAM_ITEM *item =
495         (BOOT_EVENT_PARAM_ITEM *)OH_ListFind(&bootEventList, (void *)eventName, BootEventParaListCompareProc);
496     PLUGIN_CHECK(item != NULL, return INIT_EPARAMETER, "item NULL");
497 
498     if (item->timestamp[BOOTEVENT_READY].tv_sec == 0) {
499         INIT_LOGW("%s not set", argv[0]);
500         return INIT_OK;
501     }
502 
503     SystemWriteParam(argv[0], "false");
504     if (g_finished != 0) {
505         SystemWriteParam(BOOT_EVENT_BOOT_COMPLETED, "false");
506         SetBootCompleted(false);
507         g_finished = 0;
508     }
509 
510     item->timestamp[BOOTEVENT_READY].tv_sec = 0;
511     g_bootEventNum++;
512     INIT_LOGI("UnsetBootEvent %s g_bootEventNum:%d", argv[0], g_bootEventNum);
513     return INIT_OK;
514 }
515 
ParamSetBootEventHook(const HOOK_INFO * hookInfo,void * cookie)516 static int ParamSetBootEventHook(const HOOK_INFO *hookInfo, void *cookie)
517 {
518     AddReservedBootevents();
519     AddCmdExecutor("bootevent", DoBootEventCmd);
520     AddCmdExecutor("unset_bootevent", DoUnsetBootEventCmd);
521     return 0;
522 }
523 
SetServiceBootEventFork(SERVICE_INFO_CTX * serviceCtx)524 static void SetServiceBootEventFork(SERVICE_INFO_CTX *serviceCtx)
525 {
526     BOOT_EVENT_PARAM_ITEM *item;
527     for (int i = HOOK_ID_BOOTEVENT; i < HOOK_ID_BOOTEVENT_MAX; i++) {
528         ServiceExtData *extData = GetServiceExtData(serviceCtx->serviceName, i);
529         if (extData == NULL) {
530             return;
531         }
532         item = (BOOT_EVENT_PARAM_ITEM *)extData->data;
533         if (serviceCtx->reserved != NULL) {
534             item->pid = *((int *)serviceCtx->reserved);
535         }
536         INIT_CHECK_ONLY_RETURN(clock_gettime(CLOCK_MONOTONIC,
537             &(item->timestamp[BOOTEVENT_FORK])) == 0);
538     }
539 }
540 
GetBootEventList(void)541 ListNode *GetBootEventList(void)
542 {
543     return &bootEventList;
544 }
545 
AddCmdBootEvent(INIT_CMD_INFO * cmdCtx)546 static void AddCmdBootEvent(INIT_CMD_INFO *cmdCtx)
547 {
548     INIT_TIMING_STAT *timeStat = (INIT_TIMING_STAT *)cmdCtx->reserved;
549     long long diff = InitDiffTime(timeStat);
550     // If not time cost, just ignore
551     if (diff < SAVEINITBOOTEVENTMSEC) {
552         return;
553     }
554     BOOT_EVENT_PARAM_ITEM *item = calloc(1, sizeof(BOOT_EVENT_PARAM_ITEM));
555     if (item == NULL) {
556         return;
557     }
558     OH_ListInit(&item->node);
559     item->timestamp[BOOTEVENT_FORK] = timeStat->startTime;
560     item->timestamp[BOOTEVENT_READY] = timeStat->endTime;
561     int cmdLen = strlen(cmdCtx->cmdName) + strlen(cmdCtx->cmdContent) + 1; // 2 args 1 '\0'
562     item->paramName = calloc(1, cmdLen);
563     if (item->paramName == NULL) {
564         free(item);
565         return;
566     }
567     INIT_CHECK_ONLY_ELOG(snprintf_s(item->paramName, cmdLen, cmdLen - 1, "%s%s",
568                          cmdCtx->cmdName, cmdCtx->cmdContent) >= 0,
569                          "combine cmd args failed");
570     item->flags = BOOTEVENT_TYPE_CMD;
571     OH_ListAddTail(&bootEventList, (ListNode *)&item->node);
572 }
573 
RecordInitCmd(const HOOK_INFO * info,void * cookie)574 static int RecordInitCmd(const HOOK_INFO *info, void *cookie)
575 {
576     if (cookie == NULL) {
577         return 0;
578     }
579     AddCmdBootEvent((INIT_CMD_INFO *)cookie);
580     return 0;
581 }
582 
MODULE_CONSTRUCTOR(void)583 MODULE_CONSTRUCTOR(void)
584 {
585     // Add hook to record time-cost commands
586     HOOK_INFO info = {INIT_CMD_RECORD, 0, RecordInitCmd, NULL};
587     HookMgrAddEx(GetBootStageHookMgr(), &info);
588 
589     // Add hook to parse all services with bootevents
590     InitAddServiceParseHook(ServiceParseBootEventHook);
591 
592     // Add hook to record start time for services with bootevents
593     InitAddServiceHook(SetServiceBootEventFork, INIT_SERVICE_FORK_AFTER);
594 
595     InitAddGlobalInitHook(0, ParamSetBootEventHook);
596 }
597