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