• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 <ctype.h>
16 
17 #include "init_param.h"
18 #include "init_service_manager.h"
19 #include "init_utils.h"
20 #include "param_manager.h"
21 #include "param_message.h"
22 #include "param_utils.h"
23 #include "trigger_checker.h"
24 #include "trigger_manager.h"
25 #include "securec.h"
26 #include "hookmgr.h"
27 #include "bootstage.h"
28 
29 #define MAX_TRIGGER_COUNT_RUN_ONCE 20
30 static TriggerWorkSpace g_triggerWorkSpace = {};
31 
DoTriggerExecute_(const TriggerNode * trigger,const char * content,uint32_t size)32 static int DoTriggerExecute_(const TriggerNode *trigger, const char *content, uint32_t size)
33 {
34     PARAM_CHECK(trigger != NULL, return -1, "Invalid trigger");
35     PARAM_LOGV("Do execute trigger %s type: %d", GetTriggerName(trigger), trigger->type);
36     PARAM_CHECK(trigger->type <= TRIGGER_UNKNOW, return -1, "Invalid trigger type %d", trigger->type);
37     CommandNode *cmd = GetNextCmdNode((JobNode *)trigger, NULL);
38     while (cmd != NULL) {
39 #ifndef STARTUP_INIT_TEST
40         DoCmdByIndex(cmd->cmdKeyIndex, cmd->content, &cmd->cfgContext);
41 #endif
42         cmd = GetNextCmdNode((JobNode *)trigger, cmd);
43     }
44     return 0;
45 }
46 
DoTriggerCheckResult(TriggerNode * trigger,const char * content,uint32_t size)47 static int DoTriggerCheckResult(TriggerNode *trigger, const char *content, uint32_t size)
48 {
49     UNUSED(content);
50     UNUSED(size);
51     if (TRIGGER_IN_QUEUE(trigger)) {
52         PARAM_LOGI("DoTiggerExecute trigger %s has been waiting execute", GetTriggerName(trigger));
53         return 0;
54     }
55     TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_QUEUE);
56     PARAM_LOGV("Add trigger %s to execute queue", GetTriggerName(trigger));
57     ExecuteQueuePush(&g_triggerWorkSpace, trigger);
58     return 0;
59 }
60 
ExecuteTriggerImmediately(TriggerNode * trigger,const char * content,uint32_t size)61 static int ExecuteTriggerImmediately(TriggerNode *trigger, const char *content, uint32_t size)
62 {
63     PARAM_CHECK(trigger != NULL, return -1, "Invalid trigger");
64     PARAM_LOGV("ExecuteTriggerImmediately trigger %s", GetTriggerName(trigger));
65     TriggerHeader *triggerHead = GetTriggerHeader(&g_triggerWorkSpace, trigger->type);
66     if (triggerHead != NULL) {
67         triggerHead->executeTrigger(trigger, content, size);
68         TRIGGER_CLEAR_FLAG(trigger, TRIGGER_FLAGS_QUEUE);
69 
70         if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_ONCE)) {
71             FreeTrigger(&g_triggerWorkSpace, trigger);
72         }
73     }
74     return 0;
75 }
76 
StartTriggerExecute_(TriggerNode * trigger,const char * content,uint32_t size)77 static void StartTriggerExecute_(TriggerNode *trigger, const char *content, uint32_t size)
78 {
79     TriggerHeader *triggerHead = GetTriggerHeader(&g_triggerWorkSpace, trigger->type);
80     if (triggerHead != NULL) {
81         PARAM_LOGV("StartTriggerExecute_ trigger %s flags:0x%04x",
82             GetTriggerName(trigger), trigger->flags);
83         triggerHead->executeTrigger(trigger, content, size);
84         TRIGGER_CLEAR_FLAG(trigger, TRIGGER_FLAGS_QUEUE);
85         if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_SUBTRIGGER)) { // boot && xxx=xxx trigger
86             const char *condition = triggerHead->getCondition(trigger);
87             CheckTrigger(&g_triggerWorkSpace, TRIGGER_UNKNOW, condition, strlen(condition), ExecuteTriggerImmediately);
88         }
89         if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_ONCE)) {
90             FreeTrigger(&g_triggerWorkSpace, trigger);
91         }
92     }
93 }
94 
ExecuteQueueWork(uint32_t maxCount,void (* bootStateChange)(int start,const char *))95 static void ExecuteQueueWork(uint32_t maxCount, void (*bootStateChange)(int start, const char *))
96 {
97     uint32_t executeCount = 0;
98     TriggerNode *trigger = ExecuteQueuePop(&g_triggerWorkSpace);
99     while (trigger != NULL) {
100         if (bootStateChange != NULL) {
101             bootStateChange(0, (const char *)GetTriggerName(trigger));
102         }
103         StartTriggerExecute_(trigger, NULL, 0);
104         if (bootStateChange != NULL) {
105             bootStateChange(1, (const char *)GetTriggerName(trigger));
106         }
107         executeCount++;
108         if (executeCount > maxCount) {
109             break;
110         }
111         trigger = ExecuteQueuePop(&g_triggerWorkSpace);
112     }
113 }
114 
ProcessBeforeEvent(const ParamTaskPtr stream,uint64_t eventId,const uint8_t * content,uint32_t size)115 PARAM_STATIC void ProcessBeforeEvent(const ParamTaskPtr stream,
116     uint64_t eventId, const uint8_t *content, uint32_t size)
117 {
118     PARAM_LOGV("ProcessBeforeEvent %s ", (char *)content);
119     switch (eventId) {
120         case EVENT_TRIGGER_PARAM: {
121             CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM,
122                 (const char *)content, size, DoTriggerCheckResult);
123             ExecuteQueueWork(MAX_TRIGGER_COUNT_RUN_ONCE, NULL);
124             break;
125         }
126         case EVENT_TRIGGER_BOOT: {
127             if (g_triggerWorkSpace.bootStateChange != NULL) {
128                 g_triggerWorkSpace.bootStateChange(0, (const char *)content);
129             }
130             CheckTrigger(&g_triggerWorkSpace, TRIGGER_BOOT,
131                 (const char *)content, size, DoTriggerCheckResult);
132             ExecuteQueueWork(1, NULL);
133             if (g_triggerWorkSpace.bootStateChange != NULL) {
134                 g_triggerWorkSpace.bootStateChange(1, (const char *)content);
135             }
136             ExecuteQueueWork(MAX_TRIGGER_COUNT_RUN_ONCE, g_triggerWorkSpace.bootStateChange);
137             break;
138         }
139         case EVENT_TRIGGER_PARAM_WAIT: {
140             CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM_WAIT,
141                 (const char *)content, size, ExecuteTriggerImmediately);
142             break;
143         }
144         case EVENT_TRIGGER_PARAM_WATCH: {
145             CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM_WATCH,
146                 (const char *)content, size, ExecuteTriggerImmediately);
147             break;
148         }
149         default:
150             break;
151     }
152 }
153 
SendTriggerEvent(int type,const char * content,uint32_t contentLen)154 static void SendTriggerEvent(int type, const char *content, uint32_t contentLen)
155 {
156     PARAM_CHECK(content != NULL, return, "Invalid param");
157     PARAM_LOGV("SendTriggerEvent type %d content %s", type, content);
158     ParamEventSend(g_triggerWorkSpace.eventHandle, (uint64_t)type, content, contentLen);
159 }
160 
PostParamTrigger(int type,const char * name,const char * value)161 void PostParamTrigger(int type, const char *name, const char *value)
162 {
163     PARAM_CHECK(name != NULL && value != NULL, return, "Invalid param");
164     uint32_t bufferSize = strlen(name) + strlen(value) + 1 + 1 + 1;
165     PARAM_CHECK(bufferSize < (PARAM_CONST_VALUE_LEN_MAX + PARAM_NAME_LEN_MAX + 1 + 1 + 1),
166         return, "bufferSize is longest %d", bufferSize);
167     char *buffer = (char *)malloc(bufferSize);
168     PARAM_CHECK(buffer != NULL, return, "Failed to alloc memory for  param %s", name);
169     int ret = sprintf_s(buffer, bufferSize - 1, "%s=%s", name, value);
170     PARAM_CHECK(ret > EOK, free(buffer);
171         return, "Failed to copy param");
172     SendTriggerEvent(type, buffer, strlen(buffer));
173     free(buffer);
174 }
175 
PostTrigger(EventType type,const char * content,uint32_t contentLen)176 void PostTrigger(EventType type, const char *content, uint32_t contentLen)
177 {
178     PARAM_CHECK(content != NULL && contentLen > 0, return, "Invalid param");
179     SendTriggerEvent(type, content, contentLen);
180 }
181 
GetTriggerType(const char * type)182 static int GetTriggerType(const char *type)
183 {
184     if (strncmp("param:", type, strlen("param:")) == 0) {
185         return TRIGGER_PARAM;
186     }
187     if (strncmp("boot-service:", type, strlen("boot-service:")) == 0) {
188         return TRIGGER_BOOT;
189     }
190     const char *triggerTypeStr[] = {
191         "pre-init", "boot", "early-init", "init", "early-init", "late-init", "post-init",
192         "fs", "early-fs", "post-fs", "late-fs", "early-boot", "post-fs-data", "reboot", "suspend"
193     };
194     for (size_t i = 0; i < ARRAY_LENGTH(triggerTypeStr); i++) {
195         if (strcmp(triggerTypeStr[i], type) == 0) {
196             return TRIGGER_BOOT;
197         }
198     }
199     return TRIGGER_UNKNOW;
200 }
201 
GetCommandInfo(const char * cmdLine,int * cmdKeyIndex,char ** content)202 static int GetCommandInfo(const char *cmdLine, int *cmdKeyIndex, char **content)
203 {
204     const char *matchCmd = GetMatchCmd(cmdLine, cmdKeyIndex);
205     PARAM_CHECK(matchCmd != NULL, return -1, "Command not support %s", cmdLine);
206     char *str = strstr(cmdLine, matchCmd);
207     if (str != NULL) {
208         str += strlen(matchCmd);
209     }
210     while (str != NULL && isspace(*str)) {
211         str++;
212     }
213     *content = str;
214     return 0;
215 }
216 
ParseJobHookExecute(const char * name,const cJSON * jobNode)217 static void ParseJobHookExecute(const char *name, const cJSON *jobNode)
218 {
219     JOB_PARSE_CTX context;
220 
221     context.jobName = name;
222     context.jobNode = jobNode;
223 
224     (void)HookMgrExecute(GetBootStageHookMgr(), INIT_JOB_PARSE, (void *)(&context), NULL);
225 }
226 
ParseTrigger_(const TriggerWorkSpace * workSpace,const cJSON * triggerItem,int (* checkJobValid)(const char * jobName),const ConfigContext * cfgContext)227 static int ParseTrigger_(const TriggerWorkSpace *workSpace,
228     const cJSON *triggerItem, int (*checkJobValid)(const char *jobName), const ConfigContext *cfgContext)
229 {
230     PARAM_CHECK(triggerItem != NULL, return -1, "Invalid file");
231     PARAM_CHECK(workSpace != NULL, return -1, "Failed to create trigger list");
232     char *name = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "name"));
233     PARAM_CHECK(name != NULL, return -1, "Can not get name from cfg");
234     char *condition = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "condition"));
235     int type = GetTriggerType(name);
236     PARAM_CHECK(type <= TRIGGER_UNKNOW, return -1, "Failed to get trigger index");
237     if (type != TRIGGER_BOOT && checkJobValid != NULL && checkJobValid(name) != 0) {
238         PARAM_LOGI("Trigger %s not exist in group", name);
239         return 0;
240     }
241 
242     TriggerHeader *header = GetTriggerHeader(workSpace, type);
243     PARAM_CHECK(header != NULL, return -1, "Failed to get header %d", type);
244     JobNode *trigger = UpdateJobTrigger(workSpace, type, condition, name);
245     PARAM_CHECK(trigger != NULL, return -1, "Failed to create trigger %s", name);
246     PARAM_LOGV("ParseTrigger %s type %d count %d", name, type, header->triggerCount);
247     cJSON *cmdItems = cJSON_GetObjectItem(triggerItem, CMDS_ARR_NAME_IN_JSON);
248     if (cmdItems == NULL || !cJSON_IsArray(cmdItems)) {
249         return 0;
250     }
251     int cmdLinesCnt = cJSON_GetArraySize(cmdItems);
252     PARAM_CHECK(cmdLinesCnt > 0, return -1, "Command array size must positive %s", name);
253 
254     int ret;
255     int cmdKeyIndex = 0;
256     for (int i = 0; (i < cmdLinesCnt) && (i < TRIGGER_MAX_CMD); ++i) {
257         char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdItems, i));
258         PARAM_CHECK(cmdLineStr != NULL, continue, "Command is null");
259 
260         char *content = NULL;
261         ret = GetCommandInfo(cmdLineStr, &cmdKeyIndex, &content);
262         PARAM_CHECK(ret == 0, continue, "Command not support %s", cmdLineStr);
263         ret = AddCommand(trigger, (uint32_t)cmdKeyIndex, content, cfgContext);
264         PARAM_CHECK(ret == 0, continue, "Failed to add command %s", cmdLineStr);
265         header->cmdNodeCount++;
266     }
267     return 0;
268 }
269 
ParseTriggerConfig(const cJSON * fileRoot,int (* checkJobValid)(const char * jobName),void * context)270 int ParseTriggerConfig(const cJSON *fileRoot, int (*checkJobValid)(const char *jobName), void *context)
271 {
272     PARAM_CHECK(g_triggerWorkSpace.eventHandle != NULL, return -1, "Invalid trigger data");
273     PARAM_CHECK(fileRoot != NULL, return -1, "Invalid file");
274     ConfigContext *cfgContext = (ConfigContext *)context;
275     cJSON *triggers = cJSON_GetObjectItemCaseSensitive(fileRoot, TRIGGER_ARR_NAME_IN_JSON);
276     if (triggers == NULL || !cJSON_IsArray(triggers)) {
277         return 0;
278     }
279     int size = cJSON_GetArraySize(triggers);
280     PARAM_CHECK(size > 0, return -1, "Trigger array size must positive");
281 
282     for (int i = 0; i < size && i < TRIGGER_MAX_CMD; ++i) {
283         cJSON *item = cJSON_GetArrayItem(triggers, i);
284         ParseTrigger_(&g_triggerWorkSpace, item, checkJobValid, cfgContext);
285         /*
286          * execute job parsing hooks
287          */
288         ParseJobHookExecute(cJSON_GetStringValue(cJSON_GetObjectItem(item, "name")), item);
289     }
290     return 0;
291 }
292 
CheckAndMarkTrigger(int type,const char * name)293 int CheckAndMarkTrigger(int type, const char *name)
294 {
295     TriggerHeader *triggerHead = GetTriggerHeader(&g_triggerWorkSpace, type);
296     if (triggerHead) {
297         return triggerHead->checkAndMarkTrigger(&g_triggerWorkSpace, type, name);
298     }
299     return 0;
300 }
301 
InitTriggerWorkSpace(void)302 int InitTriggerWorkSpace(void)
303 {
304     if (g_triggerWorkSpace.eventHandle != NULL) {
305         return 0;
306     }
307     g_triggerWorkSpace.bootStateChange = NULL;
308     ParamEventTaskCreate(&g_triggerWorkSpace.eventHandle, ProcessBeforeEvent);
309     PARAM_CHECK(g_triggerWorkSpace.eventHandle != NULL, return -1, "Failed to event handle");
310 
311     // executeQueue
312     g_triggerWorkSpace.executeQueue.executeQueue = calloc(1, TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *));
313     PARAM_CHECK(g_triggerWorkSpace.executeQueue.executeQueue != NULL,
314         return -1, "Failed to alloc memory for executeQueue");
315     g_triggerWorkSpace.executeQueue.queueCount = TRIGGER_EXECUTE_QUEUE;
316     g_triggerWorkSpace.executeQueue.startIndex = 0;
317     g_triggerWorkSpace.executeQueue.endIndex = 0;
318     InitTriggerHead(&g_triggerWorkSpace);
319     RegisterTriggerExec(TRIGGER_BOOT, DoTriggerExecute_);
320     RegisterTriggerExec(TRIGGER_PARAM, DoTriggerExecute_);
321     RegisterTriggerExec(TRIGGER_UNKNOW, DoTriggerExecute_);
322     PARAM_LOGV("InitTriggerWorkSpace success");
323     return 0;
324 }
325 
CloseTriggerWorkSpace(void)326 void CloseTriggerWorkSpace(void)
327 {
328     for (size_t i = 0; i < sizeof(g_triggerWorkSpace.triggerHead) / sizeof(g_triggerWorkSpace.triggerHead[0]); i++) {
329         ClearTrigger(&g_triggerWorkSpace, i);
330     }
331     OH_HashMapDestory(g_triggerWorkSpace.hashMap, NULL);
332     g_triggerWorkSpace.hashMap = NULL;
333     free(g_triggerWorkSpace.executeQueue.executeQueue);
334     g_triggerWorkSpace.executeQueue.executeQueue = NULL;
335     ParamTaskClose(g_triggerWorkSpace.eventHandle);
336     g_triggerWorkSpace.eventHandle = NULL;
337 }
338 
GetTriggerWorkSpace(void)339 TriggerWorkSpace *GetTriggerWorkSpace(void)
340 {
341     return &g_triggerWorkSpace;
342 }
343 
RegisterTriggerExec(int type,int32_t (* executeTrigger)(const struct tagTriggerNode_ *,const char *,uint32_t))344 void RegisterTriggerExec(int type,
345     int32_t (*executeTrigger)(const struct tagTriggerNode_ *, const char *, uint32_t))
346 {
347     TriggerHeader *triggerHead = GetTriggerHeader(&g_triggerWorkSpace, type);
348     if (triggerHead != NULL) {
349         triggerHead->executeTrigger = executeTrigger;
350     }
351 }
352 
DoTriggerExec(const char * triggerName)353 void DoTriggerExec(const char *triggerName)
354 {
355     PARAM_CHECK(g_triggerWorkSpace.eventHandle != NULL, return, "Invalid trigger data");
356     PARAM_CHECK(triggerName != NULL, return, "Invalid param");
357     JobNode *trigger = GetTriggerByName(&g_triggerWorkSpace, triggerName);
358     if (trigger != NULL && !TRIGGER_IN_QUEUE((TriggerNode *)trigger)) {
359         PARAM_LOGV("Trigger job %s", trigger->name);
360         TRIGGER_SET_FLAG((TriggerNode *)trigger, TRIGGER_FLAGS_QUEUE);
361         ExecuteQueuePush(&g_triggerWorkSpace, (TriggerNode *)trigger);
362     } else {
363         PARAM_LOGW("Can not find trigger %s", triggerName);
364     }
365 }
366 
DoJobExecNow(const char * triggerName)367 void DoJobExecNow(const char *triggerName)
368 {
369     PARAM_CHECK(g_triggerWorkSpace.eventHandle != NULL, return, "Invalid trigger data");
370     PARAM_CHECK(triggerName != NULL, return, "Invalid param");
371     JobNode *trigger = GetTriggerByName(&g_triggerWorkSpace, triggerName);
372     if (trigger != NULL) {
373         if (strncmp(triggerName, "reboot", strlen("reboot")) == 0) {
374             HookMgrExecute(GetBootStageHookMgr(), INIT_SHUT_DETECTOR, NULL, NULL);
375         }
376         StartTriggerExecute_((TriggerNode *)trigger, NULL, 0);
377     }
378 }
379 
AddCompleteJob(const char * name,const char * condition,const char * cmdContent)380 int AddCompleteJob(const char *name, const char *condition, const char *cmdContent)
381 {
382     PARAM_CHECK(g_triggerWorkSpace.eventHandle != NULL, return -1, "Invalid trigger data");
383     PARAM_CHECK(name != NULL, return -1, "Invalid name");
384     PARAM_CHECK(cmdContent != NULL, return -1, "Invalid cmdContent");
385     int type = GetTriggerType(name);
386     PARAM_CHECK(type <= TRIGGER_UNKNOW, return -1, "Failed to get trigger index");
387     TriggerHeader *header = GetTriggerHeader(&g_triggerWorkSpace, type);
388     PARAM_CHECK(header != NULL, return -1, "Failed to get header %d", type);
389 
390     JobNode *trigger = UpdateJobTrigger(&g_triggerWorkSpace, type, condition, name);
391     PARAM_CHECK(trigger != NULL, return -1, "Failed to create trigger");
392     char *content = NULL;
393     int cmdKeyIndex = 0;
394     int ret = GetCommandInfo(cmdContent, &cmdKeyIndex, &content);
395     PARAM_CHECK(ret == 0, return -1, "Command not support %s", cmdContent);
396     ret = AddCommand(trigger, (uint32_t)cmdKeyIndex, content, NULL); // use default context
397     PARAM_CHECK(ret == 0, return -1, "Failed to add command %s", cmdContent);
398     header->cmdNodeCount++;
399     PARAM_LOGV("AddCompleteJob %s type %d count %d", name, type, header->triggerCount);
400     return 0;
401 }
402 
RegisterBootStateChange(void (* bootStateChange)(int,const char *))403 void RegisterBootStateChange(void (*bootStateChange)(int, const char *))
404 {
405     if (bootStateChange != NULL) {
406         g_triggerWorkSpace.bootStateChange = bootStateChange;
407     }
408 }
409