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