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
ServiceExtDataCompareProc(ListNode * node,void * data)28 static 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
GetServiceExtData_(Service * service,uint32_t id)37 static ServiceExtData *GetServiceExtData_(Service *service, uint32_t id)
38 {
39 ListNode *node = OH_ListFind(&service->extDataNode, (void *)&id, ServiceExtDataCompareProc);
40 return (ServiceExtData *)node;
41 }
42
AddServiceExtData(const char * serviceName,uint32_t id,void * data,uint32_t dataLen)43 ServiceExtData *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
DelServiceExtData(const char * serviceName,uint32_t id)69 void 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
GetServiceExtData(const char * serviceName,uint32_t id)81 ServiceExtData *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
JobParseHookWrapper(const HOOK_INFO * hookInfo,void * executionContext)88 static 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
InitAddJobParseHook(JobParseHook hook)96 int 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
SetLogLevelFunc(const char * value)107 static 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
CmdSetLogLevel(int id,const char * name,int argc,const char ** argv)116 static 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
InitCmd(int id,const char * name,int argc,const char ** argv)127 static 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
ParamSetInitCmdHook(const HOOK_INFO * hookInfo,void * cookie)138 static int ParamSetInitCmdHook(const HOOK_INFO *hookInfo, void *cookie)
139 {
140 AddCmdExecutor("setloglevel", CmdSetLogLevel);
141 AddCmdExecutor("initcmd", InitCmd);
142 return 0;
143 }
144
DumpTrigger(const char * fmt,...)145 static 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
DumpServiceHook(void)154 static 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
InitLogLevelFromPersist(void)167 static 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
InitDebugHook(const HOOK_INFO * info,void * cookie)177 static 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
BootCompleteCmd(const HOOK_INFO * hookInfo,void * executionContext)187 static 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
MODULE_CONSTRUCTOR(void)212 MODULE_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