1 2/* 3 * Copyright (c) 2022 Huawei Device Co., Ltd. 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "init_hook.h" 18#include "init_service.h" 19#include "init_utils.h" 20#include "plugin_adapter.h" 21#include "securec.h" 22#include "init_module_engine.h" 23#include "init_group_manager.h" 24#include "init_param.h" 25#include "hookmgr.h" 26#include "bootstage.h" 27 28static int ServiceExtDataCompareProc(ListNode *node, void *data) 29{ 30 ServiceExtData *item = ListEntry(node, ServiceExtData, node); 31 if (item->dataId == *(uint32_t *)data) { 32 return 0; 33 } 34 return -1; 35} 36 37static ServiceExtData *GetServiceExtData_(Service *service, uint32_t id) 38{ 39 ListNode *node = OH_ListFind(&service->extDataNode, (void *)&id, ServiceExtDataCompareProc); 40 return (ServiceExtData *)node; 41} 42 43ServiceExtData *AddServiceExtData(const char *serviceName, uint32_t id, void *data, uint32_t dataLen) 44{ 45 Service *service = GetServiceByName(serviceName); 46 PLUGIN_CHECK(service != NULL, return NULL, "Can not find service for %s", serviceName); 47 ServiceExtData *extData = GetServiceExtData_(service, id); 48 if (extData != NULL) { 49 return NULL; 50 } 51 extData = calloc(1, sizeof(ServiceExtData) + dataLen); 52 PLUGIN_CHECK(extData != NULL, return NULL, "Can not alloc extData for %d", id); 53 OH_ListInit(&extData->node); 54 extData->dataId = id; 55 if (data != NULL) { 56 int ret = memcpy_s(extData->data, dataLen, data, dataLen); 57 if (ret == 0) { 58 OH_ListAddTail(&service->extDataNode, &extData->node); 59 return extData; 60 } 61 } else { 62 OH_ListAddTail(&service->extDataNode, &extData->node); 63 return extData; 64 } 65 free(extData); 66 return NULL; 67} 68 69void DelServiceExtData(const char *serviceName, uint32_t id) 70{ 71 Service *service = GetServiceByName(serviceName); 72 PLUGIN_CHECK(service != NULL, return, "Can not find service for %s", serviceName); 73 ServiceExtData *extData = GetServiceExtData_(service, id); 74 if (extData == NULL) { 75 return; 76 } 77 OH_ListRemove(&extData->node); 78 free(extData); 79} 80 81ServiceExtData *GetServiceExtData(const char *serviceName, uint32_t id) 82{ 83 Service *service = GetServiceByName(serviceName); 84 PLUGIN_CHECK (service != NULL, return NULL, "Can not find service for %s", serviceName); 85 return GetServiceExtData_(service, id); 86} 87 88static int JobParseHookWrapper(const HOOK_INFO *hookInfo, void *executionContext) 89{ 90 JOB_PARSE_CTX *jobParseContext = (JOB_PARSE_CTX *)executionContext; 91 JobParseHook realHook = (JobParseHook)hookInfo->hookCookie; 92 realHook(jobParseContext); 93 return 0; 94}; 95 96int InitAddJobParseHook(JobParseHook hook) 97{ 98 HOOK_INFO info; 99 info.stage = INIT_JOB_PARSE; 100 info.prio = 0; 101 info.hook = JobParseHookWrapper; 102 info.hookCookie = (void *)hook; 103 104 return HookMgrAddEx(GetBootStageHookMgr(), &info); 105} 106 107static void SetLogLevelFunc(const char *value) 108{ 109 unsigned int level; 110 int ret = StringToUint(value, &level); 111 PLUGIN_CHECK(ret == 0, return, "Failed make %s to unsigned int", value); 112 PLUGIN_LOGI("Set log level is %d", level); 113 SetInitLogLevel(level); 114} 115 116static int CmdSetLogLevel(int id, const char *name, int argc, const char **argv) 117{ 118 UNUSED(id); 119 UNUSED(name); 120 PLUGIN_CHECK(argc >= 1, return -1, "Invalid input args"); 121 const char *value = strrchr(argv[0], '.'); 122 PLUGIN_CHECK(value != NULL, return -1, "Failed get \'.\' from string %s", argv[0]); 123 SetLogLevelFunc(value + 1); 124 return 0; 125} 126 127static int InitCmd(int id, const char *name, int argc, const char **argv) 128{ 129 UNUSED(id); 130 // process cmd by name 131 PLUGIN_LOGI("InitCmd %s argc %d", name, argc); 132 if (argc > 1 && strcmp(argv[0], "setloglevel") == 0) { 133 SetLogLevelFunc(argv[1]); 134 } 135 return 0; 136} 137 138static int ParamSetInitCmdHook(const HOOK_INFO *hookInfo, void *cookie) 139{ 140 AddCmdExecutor("setloglevel", CmdSetLogLevel); 141 AddCmdExecutor("initcmd", InitCmd); 142 return 0; 143} 144 145static int DumpTrigger(const char *fmt, ...) 146{ 147 va_list vargs; 148 va_start(vargs, fmt); 149 InitLog(INIT_INFO, INIT_LOG_DOMAIN, INIT_LOG_TAG, fmt, vargs); 150 va_end(vargs); 151 return 0; 152} 153 154static void DumpServiceHook(void) 155{ 156 // check and dump all jobs 157 char dump[8] = {0}; // 8 len 158 uint32_t len = sizeof(dump); 159 (void)SystemReadParam("persist.init.debug.dump.trigger", dump, &len); 160 PLUGIN_LOGV("boot dump trigger %s", dump); 161 if (strcmp(dump, "1") == 0) { 162 SystemDumpTriggers(1, DumpTrigger); 163 } 164 return; 165} 166 167static void InitLogLevelFromPersist(void) 168{ 169 char logLevel[2] = {0}; // 2 is set param "persist.init.debug.loglevel" value length. 170 uint32_t len = sizeof(logLevel); 171 int ret = SystemReadParam(INIT_DEBUG_LEVEL, logLevel, &len); 172 INIT_INFO_CHECK(ret == 0, return, "Can not get log level from param, keep the original loglevel."); 173 SetLogLevelFunc(logLevel); 174 return; 175} 176 177static int InitDebugHook(const HOOK_INFO *info, void *cookie) 178{ 179 UNUSED(info); 180 UNUSED(cookie); 181 InitLogLevelFromPersist(); 182 DumpServiceHook(); 183 return 0; 184} 185 186// clear extend memory 187static int BootCompleteCmd(const HOOK_INFO *hookInfo, void *executionContext) 188{ 189 PLUGIN_LOGI("boot start complete"); 190 UNUSED(hookInfo); 191 UNUSED(executionContext); 192 193 // clear hook 194 HookMgrDel(GetBootStageHookMgr(), INIT_GLOBAL_INIT, NULL); 195 HookMgrDel(GetBootStageHookMgr(), INIT_PRE_PARAM_SERVICE, NULL); 196 HookMgrDel(GetBootStageHookMgr(), INIT_PARAM_LOAD_FILTER, NULL); 197 HookMgrDel(GetBootStageHookMgr(), INIT_PRE_PARAM_LOAD, NULL); 198 HookMgrDel(GetBootStageHookMgr(), INIT_PRE_CFG_LOAD, NULL); 199 HookMgrDel(GetBootStageHookMgr(), INIT_SERVICE_PARSE, NULL); 200 HookMgrDel(GetBootStageHookMgr(), INIT_POST_PERSIST_PARAM_LOAD, NULL); 201 HookMgrDel(GetBootStageHookMgr(), INIT_POST_CFG_LOAD, NULL); 202 HookMgrDel(GetBootStageHookMgr(), INIT_JOB_PARSE, NULL); 203 // clear cmd 204 RemoveCmdExecutor("loadSelinuxPolicy", -1); 205 206 PluginExecCmdByName("init_trace", "stop"); 207 // uninstall module of inittrace 208 InitModuleMgrUnInstall("inittrace"); 209 return 0; 210} 211 212MODULE_CONSTRUCTOR(void) 213{ 214 HookMgrAdd(GetBootStageHookMgr(), INIT_BOOT_COMPLETE, 0, BootCompleteCmd); 215 InitAddGlobalInitHook(0, ParamSetInitCmdHook); 216 // Depends on parameter service 217 InitAddPostPersistParamLoadHook(0, InitDebugHook); 218} 219