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