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