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
16#include "trigger_manager.h"
17
18#include <string.h>
19#include <sys/types.h>
20
21#include "init_cmds.h"
22#include "param_manager.h"
23#include "trigger_checker.h"
24#include "securec.h"
25
26static DUMP_PRINTF g_printf = printf;
27
28int AddCommand(JobNode *trigger, uint32_t cmdKeyIndex, const char *content, const ConfigContext *cfgContext)
29{
30    PARAM_CHECK(trigger != NULL, return -1, "trigger is null");
31    uint32_t size = sizeof(CommandNode);
32    size += (content == NULL) ? 1 : (strlen(content) + 1);
33    size = PARAM_ALIGN(size);
34
35    CommandNode *node = (CommandNode *)calloc(1, size);
36    PARAM_CHECK(node != NULL, return -1, "Failed to alloc memory for command");
37    node->cmdKeyIndex = cmdKeyIndex;
38    node->next = NULL;
39    node->content[0] = '\0';
40    if (content != NULL && strlen(content) != 0) {
41        int ret = memcpy_s(node->content, size, content, strlen(content));
42        node->content[strlen(content)] = '\0';
43        PARAM_CHECK(ret == EOK, free(node);
44            return 0, "Failed to copy command");
45    }
46    node->cfgContext.type = INIT_CONTEXT_MAIN;
47    if (cfgContext != NULL) {
48        node->cfgContext.type = cfgContext->type;
49    }
50    if (trigger->firstCmd == NULL) {
51        trigger->firstCmd = node;
52        trigger->lastCmd = node;
53    } else {
54        PARAM_CHECK(trigger->lastCmd != NULL, free(node);
55            return 0, "Invalid last cmd");
56        trigger->lastCmd->next = node;
57        trigger->lastCmd = node;
58    }
59    return 0;
60}
61
62CommandNode *GetNextCmdNode(const JobNode *trigger, const CommandNode *curr)
63{
64    PARAM_CHECK(trigger != NULL, return NULL, "trigger is null");
65    if (curr == NULL) {
66        return trigger->firstCmd;
67    }
68    return curr->next;
69}
70
71static int CopyCondition(TriggerNode *node, const char *condition)
72{
73    if (condition == NULL || strlen(condition) == 0) {
74        return 0;
75    }
76    uint32_t buffSize = 0;
77    char *cond = GetTriggerCache(&buffSize);
78    int ret = ConvertInfixToPrefix(condition, cond, buffSize);
79    PARAM_CHECK(ret == 0, return -1, "Failed to convert condition for trigger");
80    node->condition = strdup(cond);
81    PARAM_CHECK(node->condition != NULL, return -1, "Failed to dup conditition");
82    return 0;
83}
84
85static TriggerNode *AddTriggerNode_(TriggerHeader *triggerHead,
86    uint32_t type, const char *condition, uint32_t dataSize)
87{
88    TriggerNode *node = (TriggerNode *)calloc(1, dataSize);
89    PARAM_CHECK(node != NULL, return NULL, "Failed to alloc memory for trigger");
90    node->condition = NULL;
91    int ret = CopyCondition(node, condition);
92    PARAM_CHECK(ret == 0, free(node);
93            return NULL, "Failed to copy conditition");
94    node->type = type;
95    node->flags = 0;
96    OH_ListInit(&node->node);
97    OH_ListAddTail(&triggerHead->triggerList, &node->node);
98    triggerHead->triggerCount++;
99    return node;
100}
101
102static int32_t AddJobNode_(TriggerNode *trigger, const TriggerExtInfo *extInfo)
103{
104    JobNode *node = (JobNode *)trigger;
105    int ret = strcpy_s(node->name, strlen(extInfo->info.name) + 1, extInfo->info.name);
106    PARAM_CHECK(ret == EOK, return -1, "Failed to copy name for trigger");
107    node->firstCmd = NULL;
108    node->lastCmd = NULL;
109    ret = OH_HashMapAdd(GetTriggerWorkSpace()->hashMap, &node->hashNode);
110    PARAM_CHECK(ret == 0, return -1, "Failed to add hash node");
111    return 0;
112}
113
114static TriggerNode *AddJobTrigger_(const TriggerWorkSpace *workSpace,
115    const char *condition, const TriggerExtInfo *extInfo)
116{
117    PARAM_CHECK(workSpace != NULL, return NULL, "workSpace is null");
118    PARAM_CHECK(extInfo != NULL && extInfo->addNode != NULL, return NULL, "extInfo is null");
119    PARAM_CHECK(extInfo->type <= TRIGGER_UNKNOW, return NULL, "Invalid type");
120    TriggerHeader *triggerHead = GetTriggerHeader(workSpace, extInfo->type);
121    PARAM_CHECK(triggerHead != NULL, return NULL, "Failed to get header %d", extInfo->type);
122    uint32_t nameLen = strlen(extInfo->info.name);
123    uint32_t triggerNodeLen = PARAM_ALIGN(nameLen + 1) + sizeof(JobNode);
124    TriggerNode *node = (TriggerNode *)AddTriggerNode_(triggerHead, extInfo->type, condition, triggerNodeLen);
125    PARAM_CHECK(node != NULL, return NULL, "Failed to alloc jobnode");
126    int ret = extInfo->addNode(node, extInfo);
127    PARAM_CHECK(ret == 0, FreeTrigger(workSpace, node);
128        return NULL, "Failed to add hash node");
129    if (extInfo->type == TRIGGER_BOOT) {
130        TRIGGER_SET_FLAG(node, TRIGGER_FLAGS_ONCE);
131        if (strncmp("boot-service:", extInfo->info.name, strlen("boot-service:")) != 0) {
132            TRIGGER_SET_FLAG(node, TRIGGER_FLAGS_SUBTRIGGER);
133        }
134    }
135    return node;
136}
137
138static void DelJobTrigger_(const TriggerWorkSpace *workSpace, TriggerNode *trigger)
139{
140    PARAM_CHECK(workSpace != NULL, return, "Param is null");
141    PARAM_CHECK(trigger != NULL, return, "Trigger is null");
142    JobNode *jobNode = (JobNode *)trigger;
143    TriggerHeader *triggerHead = GetTriggerHeader(workSpace, trigger->type);
144    PARAM_CHECK(triggerHead != NULL, return, "Failed to get header %d", trigger->type);
145    CommandNode *cmd = jobNode->firstCmd;
146    while (cmd != NULL) {
147        CommandNode *next = cmd->next;
148        free(cmd);
149        triggerHead->cmdNodeCount--;
150        cmd = next;
151    }
152    if (jobNode->condition != NULL) {
153        free(jobNode->condition);
154        jobNode->condition = NULL;
155    }
156    jobNode->lastCmd = NULL;
157    jobNode->firstCmd = NULL;
158    OH_ListRemove(&trigger->node);
159    triggerHead->triggerCount--;
160    OH_HashMapRemove(workSpace->hashMap, jobNode->name);
161
162    if (!TRIGGER_IN_QUEUE(trigger)) {
163        free(jobNode);
164        return;
165    }
166    TriggerExecuteQueue *executeQueue = (TriggerExecuteQueue *)&workSpace->executeQueue;
167    for (uint32_t i = executeQueue->startIndex; i < executeQueue->endIndex; i++) {
168        if (executeQueue->executeQueue[i] == trigger) {
169            executeQueue->executeQueue[i] = NULL;
170            break;
171        }
172    }
173    free(jobNode);
174}
175
176static TriggerNode *AddWatchTrigger_(const TriggerWorkSpace *workSpace,
177    const char *condition, const TriggerExtInfo *extInfo)
178{
179    PARAM_CHECK(workSpace != NULL, return NULL, "workSpace is null");
180    PARAM_CHECK(extInfo != NULL && extInfo->addNode != NULL, return NULL, "extInfo is null");
181    TriggerHeader *triggerHead = GetTriggerHeader(workSpace, extInfo->type);
182    PARAM_CHECK(triggerHead != NULL, return NULL, "Failed to get header %d", extInfo->type);
183    uint32_t size = 0;
184    if (extInfo->type == TRIGGER_PARAM_WATCH) {
185        size = sizeof(WatchNode);
186    } else if (extInfo->type == TRIGGER_PARAM_WAIT) {
187        size = sizeof(WaitNode);
188    } else {
189        PARAM_LOGE("Invalid trigger type %d", extInfo->type);
190        return NULL;
191    }
192    TriggerNode *node = AddTriggerNode_(triggerHead, extInfo->type, condition, size);
193    PARAM_CHECK(node != NULL, return NULL, "Failed to alloc memory for trigger");
194    int ret = extInfo->addNode(node, extInfo);
195    PARAM_CHECK(ret == 0, FreeTrigger(workSpace, node);
196        return NULL, "Failed to add node");
197    if (extInfo->type == TRIGGER_PARAM_WAIT) {
198        TRIGGER_SET_FLAG(node, TRIGGER_FLAGS_ONCE);
199    }
200    return node;
201}
202
203static void DelWatchTrigger_(const TriggerWorkSpace *workSpace, TriggerNode *trigger)
204{
205    PARAM_CHECK(workSpace != NULL && trigger != NULL, return, "Param is null");
206    TriggerHeader *triggerHead = GetTriggerHeader(workSpace, trigger->type);
207    PARAM_CHECK(triggerHead != NULL, return, "Failed to get header %d", trigger->type);
208    OH_ListRemove(&trigger->node);
209    if (trigger->type == TRIGGER_PARAM_WAIT) {
210        WaitNode *node = (WaitNode *)trigger;
211        OH_ListRemove(&node->item);
212    } else if (trigger->type == TRIGGER_PARAM_WATCH) {
213        WatchNode *node = (WatchNode *)trigger;
214        OH_ListRemove(&node->item);
215    }
216    PARAM_LOGV("DelWatchTrigger_ %s count %d", GetTriggerName(trigger), triggerHead->triggerCount);
217    triggerHead->triggerCount--;
218    if (trigger->condition != NULL) {
219        free(trigger->condition);
220        trigger->condition = NULL;
221    }
222    free(trigger);
223}
224
225static TriggerNode *GetNextTrigger_(const TriggerHeader *triggerHead, const TriggerNode *curr)
226{
227    PARAM_CHECK(triggerHead != NULL, return NULL, "Invalid triggerHead");
228    ListNode *node = NULL;
229    if (curr != NULL) {
230        node = curr->node.next;
231    } else {
232        node = triggerHead->triggerList.next;
233    }
234    if (node != &triggerHead->triggerList) {
235        return ListEntry(node, TriggerNode, node);
236    }
237    return NULL;
238}
239
240static const char *GetTriggerCondition_(const TriggerNode *trigger)
241{
242    return (trigger == NULL || trigger->condition == NULL) ? "" : trigger->condition;
243}
244
245static const char *GetBootCondition_(const TriggerNode *trigger)
246{
247    PARAM_CHECK(trigger != NULL, return "", "Invalid trigger");
248    PARAM_CHECK(trigger->type == TRIGGER_BOOT, return "", "Invalid type");
249    const JobNode *node = (const JobNode *)trigger;
250    return node->name;
251}
252
253static const char *GetJobName_(const TriggerNode *trigger)
254{
255    PARAM_CHECK(trigger != NULL, return "", "Invalid trigger");
256    PARAM_CHECK(trigger->type <= TRIGGER_UNKNOW, return "", "Invalid type");
257    const JobNode *node = (const JobNode *)trigger;
258    return node->name;
259}
260
261static const char *GetWatchName_(const TriggerNode *trigger)
262{
263    PARAM_CHECK(trigger != NULL, return "", "Invalid trigger");
264    PARAM_CHECK(trigger->type < TRIGGER_MAX && trigger->type > TRIGGER_UNKNOW,
265        return "", "Invalid type");
266    return trigger->condition;
267}
268
269JobNode *UpdateJobTrigger(const TriggerWorkSpace *workSpace,
270    int type, const char *condition, const char *name)
271{
272    PARAM_CHECK(workSpace != NULL && name != NULL, return NULL, "name is null");
273    PARAM_CHECK(type <= TRIGGER_UNKNOW, return NULL, "Invalid type");
274    TriggerHeader *triggerHead = GetTriggerHeader(workSpace, type);
275    PARAM_CHECK(triggerHead != NULL, return NULL, "Failed to get header %d", type);
276    JobNode *jobNode = GetTriggerByName(workSpace, name);
277    if (jobNode == NULL) {
278        TriggerExtInfo extInfo = {};
279        extInfo.info.name = (char *)name;
280        extInfo.type = type;
281        extInfo.addNode = AddJobNode_;
282        return (JobNode *)triggerHead->addTrigger(workSpace, condition, &extInfo);
283    } else if (jobNode->condition == NULL && condition != NULL) {
284        int ret = CopyCondition((TriggerNode *)jobNode, condition);
285        PARAM_CHECK(ret == 0, FreeTrigger(workSpace, (TriggerNode*)jobNode);
286            return NULL, "Failed to copy conditition");
287    }
288    return jobNode;
289}
290
291JobNode *GetTriggerByName(const TriggerWorkSpace *workSpace, const char *triggerName)
292{
293    PARAM_CHECK(workSpace != NULL && triggerName != NULL, return NULL, "Invalid param");
294    HashNode *node = OH_HashMapGet(workSpace->hashMap, triggerName);
295    if (node == NULL) {
296        return NULL;
297    }
298    JobNode *trigger = HASHMAP_ENTRY(node, JobNode, hashNode);
299    return trigger;
300}
301
302void FreeTrigger(const TriggerWorkSpace *workSpace, TriggerNode *trigger)
303{
304    PARAM_CHECK(workSpace != NULL && trigger != NULL, return, "Invalid param");
305    TriggerHeader *head = GetTriggerHeader(workSpace, trigger->type);
306    if (head != NULL) {
307        head->delTrigger(workSpace, trigger);
308    }
309}
310
311void ClearTrigger(const TriggerWorkSpace *workSpace, int8_t type)
312{
313    PARAM_CHECK(workSpace != NULL, return, "head is null");
314    TriggerHeader *head = GetTriggerHeader(workSpace, type);
315    PARAM_CHECK(head != NULL, return, "Failed to get header %d", type);
316    TriggerNode *trigger = head->nextTrigger(head, NULL);
317    while (trigger != NULL) {
318        TriggerNode *next = head->nextTrigger(head, trigger);
319        FreeTrigger(workSpace, trigger);
320        trigger = next;
321    }
322    OH_ListInit(&head->triggerList);
323}
324
325int ExecuteQueuePush(TriggerWorkSpace *workSpace, const TriggerNode *trigger)
326{
327    PARAM_CHECK(workSpace != NULL, return -1, "Invalid workSpace");
328    uint32_t index = workSpace->executeQueue.endIndex++ % workSpace->executeQueue.queueCount;
329    workSpace->executeQueue.executeQueue[index] = (TriggerNode *)trigger;
330    return 0;
331}
332
333TriggerNode *ExecuteQueuePop(TriggerWorkSpace *workSpace)
334{
335    PARAM_CHECK(workSpace != NULL, return NULL, "Invalid workSpace");
336    TriggerNode *trigger = NULL;
337    do {
338        if (workSpace->executeQueue.endIndex <= workSpace->executeQueue.startIndex) {
339            return NULL;
340        }
341        uint32_t currIndex = workSpace->executeQueue.startIndex % workSpace->executeQueue.queueCount;
342        trigger = workSpace->executeQueue.executeQueue[currIndex];
343        workSpace->executeQueue.executeQueue[currIndex] = NULL;
344        workSpace->executeQueue.startIndex++;
345    } while (trigger == NULL);
346    return trigger;
347}
348
349static int CheckBootCondition_(LogicCalculator *calculator,
350    const char *condition, const char *content, uint32_t contentSize)
351{
352    UNUSED(calculator);
353    if (strncmp(condition, content, contentSize) == 0) {
354        return 1;
355    }
356    return 0;
357}
358
359static int CheckWatchCondition_(LogicCalculator *calculator,
360    const char *condition, const char *content, uint32_t contentSize)
361{
362    UNUSED(calculator);
363    UNUSED(contentSize);
364    if (strncmp(condition, content, strlen(condition)) == 0) {
365        return 1;
366    }
367    return 0;
368}
369
370static int CheckParamCondition_(LogicCalculator *calculator,
371    const char *condition, const char *content, uint32_t contentSize)
372{
373    UNUSED(content);
374    UNUSED(contentSize);
375    if (calculator->inputName != NULL) {
376        if (!CheckMatchSubCondition(condition, calculator->inputName, strlen(calculator->inputName))) {
377            return 0;
378        }
379    }
380    return ComputeCondition(calculator, condition);
381}
382
383static int CheckUnknowCondition_(LogicCalculator *calculator,
384    const char *condition, const char *content, uint32_t contentSize)
385{
386    if (condition != NULL && content != NULL && strcmp(content, condition) == 0) {
387        return 1;
388    }
389    return ComputeCondition(calculator, condition);
390}
391
392static int ExecTriggerMatch_(const TriggerWorkSpace *workSpace,
393    int type, LogicCalculator *calculator, const char *content, uint32_t contentSize)
394{
395    TriggerHeader *head = GetTriggerHeader(workSpace, type);
396    PARAM_CHECK(head != NULL, return 0, "Failed to get header %d", type);
397    TriggerNode *trigger = head->nextTrigger(head, NULL);
398    while (trigger != NULL) {
399        TriggerNode *next = head->nextTrigger(head, trigger);
400        const char *condition = head->getCondition(trigger);
401        if (head->checkCondition(calculator, condition, content, contentSize) == 1) {
402            calculator->triggerCheckDone(trigger, content, contentSize);
403        }
404        trigger = next;
405    }
406    return 0;
407}
408
409static int CheckBootMatch_(const TriggerWorkSpace *workSpace,
410    int type, LogicCalculator *calculator, const char *content, uint32_t contentSize)
411{
412    PARAM_CHECK(workSpace != NULL, return -1, "Invalid space");
413    PARAM_CHECK((type == TRIGGER_BOOT) || (type == TRIGGER_PARAM_WATCH), return -1, "Invalid type");
414    return ExecTriggerMatch_(workSpace, type, calculator, content, contentSize);
415}
416
417static int CheckParamMatch_(const TriggerWorkSpace *workSpace,
418    int type, LogicCalculator *calculator, const char *content, uint32_t contentSize)
419{
420    PARAM_CHECK(workSpace != NULL, return -1, "Invalid space");
421    PARAM_CHECK((type == TRIGGER_PARAM) || (type == TRIGGER_PARAM_WAIT), return -1, "Invalid type");
422
423    CalculatorInit(calculator, MAX_CONDITION_NUMBER, sizeof(LogicData), 1);
424    int ret = GetValueFromContent(content, contentSize, 0, calculator->inputName, SUPPORT_DATA_BUFFER_MAX);
425    PARAM_CHECK(ret == 0, return -1, "Failed parse content name");
426    ret = GetValueFromContent(content, contentSize,
427        strlen(calculator->inputName) + 1, calculator->inputContent, SUPPORT_DATA_BUFFER_MAX);
428    PARAM_CHECK(ret == 0, return -1, "Failed parse content value");
429    return ExecTriggerMatch_(workSpace, type, calculator, content, contentSize);
430}
431
432static int CheckUnknowMatch_(const TriggerWorkSpace *workSpace,
433    int type, LogicCalculator *calculator, const char *content, uint32_t contentSize)
434{
435    PARAM_CHECK(workSpace != NULL && content != NULL, return -1, "Failed arg for trigger");
436    PARAM_CHECK(type == TRIGGER_UNKNOW, return -1, "Invalid type");
437
438    CalculatorInit(calculator, MAX_CONDITION_NUMBER, sizeof(LogicData), 1);
439    int ret = memcpy_s(calculator->triggerContent, sizeof(calculator->triggerContent), content, contentSize);
440    PARAM_CHECK(ret == EOK, return -1, "Failed to memcpy");
441    calculator->inputName = NULL;
442    calculator->inputContent = NULL;
443    return ExecTriggerMatch_(workSpace, type, calculator, content, contentSize);
444}
445
446int32_t CheckAndMarkTrigger_(const TriggerWorkSpace *workSpace, int type, const char *name)
447{
448    PARAM_CHECK(workSpace != NULL && name != NULL, return 0, "Failed arg for trigger");
449    TriggerHeader *head = GetTriggerHeader(workSpace, type);
450    PARAM_CHECK(head != NULL, return 0, "Failed to get header %d", type);
451    int ret = 0;
452    TriggerNode *trigger = head->nextTrigger(head, NULL);
453    while (trigger != NULL) {
454        if (head->getCondition(trigger) == NULL) {
455            trigger = head->nextTrigger(head, trigger);
456            continue;
457        }
458        if (CheckMatchSubCondition(head->getCondition(trigger), name, strlen(name)) == 1) {
459            TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_RELATED);
460            ret = 1;
461        }
462        trigger = head->nextTrigger(head, trigger);
463    }
464    return ret;
465}
466
467int CheckTrigger(TriggerWorkSpace *workSpace, int type,
468    const char *content, uint32_t contentSize, PARAM_CHECK_DONE triggerCheckDone)
469{
470    PARAM_CHECK(workSpace != NULL && content != NULL && triggerCheckDone != NULL,
471        return -1, "Failed arg for trigger");
472    PARAM_LOGV("CheckTrigger_ type: %d content: %s ", type, content);
473    TriggerHeader *triggerHead = GetTriggerHeader(workSpace, type);
474    if (triggerHead != NULL) {
475        LogicCalculator calculator = {{0}};
476        calculator.triggerCheckDone = triggerCheckDone;
477        int ret = triggerHead->checkTriggerMatch(workSpace, type, &calculator, content, contentSize);
478        CalculatorFree(&calculator);
479        return ret;
480    }
481    return 0;
482}
483
484static void DumpJobTrigger_(const TriggerWorkSpace *workSpace, const TriggerNode *trigger)
485{
486    const JobNode *node = (const JobNode *)trigger;
487    PARAM_DUMP("trigger     flags: 0x%08x \n", trigger->flags);
488    PARAM_DUMP("trigger      name: %s \n", node->name);
489    PARAM_DUMP("trigger condition: %s \n", node->condition);
490    const int maxCmd = 1024;
491    int count = 0;
492    CommandNode *cmd = GetNextCmdNode(node, NULL);
493    while (cmd != NULL && count < maxCmd) {
494        PARAM_DUMP("    command name: %s (%s) \n", GetCmdKey(cmd->cmdKeyIndex),
495            (cmd->cfgContext.type == INIT_CONTEXT_CHIPSET) ? "chipset" : "system");
496        PARAM_DUMP("    command args    : %s \n", cmd->content);
497        cmd = GetNextCmdNode(node, cmd);
498        count++;
499    }
500}
501
502static void DumpWatchTrigger_(const TriggerWorkSpace *workSpace, const TriggerNode *trigger)
503{
504    PARAM_CHECK(trigger != NULL, return, "Empty trigger");
505    const WatchNode *node = (const WatchNode *)trigger;
506    PARAM_DUMP("trigger     flags: 0x%08x \n", trigger->flags);
507    PARAM_DUMP("trigger condition: %s \n", trigger->condition);
508    PARAM_DUMP("trigger   watchId: %d \n", node->watchId);
509}
510
511static void DumpWaitTrigger_(const TriggerWorkSpace *workSpace, const TriggerNode *trigger)
512{
513    PARAM_CHECK(trigger != NULL, return, "Empty trigger");
514    const WaitNode *node = (const WaitNode *)trigger;
515    PARAM_DUMP("trigger     flags: 0x%08x \n", trigger->flags);
516    PARAM_DUMP("trigger      name: %s \n", GetTriggerName(trigger));
517    PARAM_DUMP("trigger condition: %s \n", trigger->condition);
518    PARAM_DUMP("trigger    waitId: %d \n", node->waitId);
519    PARAM_DUMP("trigger   timeout: %d \n", node->timeout);
520}
521
522static void DumpTrigger_(const TriggerWorkSpace *workSpace, int type)
523{
524    PARAM_CHECK(workSpace != NULL, return, "Invalid workSpace ");
525    TriggerHeader *head = GetTriggerHeader(workSpace, type);
526    PARAM_CHECK(head != NULL, return, "Failed to get header %d", type);
527    TriggerNode *trigger = head->nextTrigger(head, NULL);
528    while (trigger != NULL) {
529        head->dumpTrigger(workSpace, trigger);
530        trigger = head->nextTrigger(head, trigger);
531    }
532}
533
534void SystemDumpTriggers(int verbose, int (*dump)(const char *fmt, ...))
535{
536    if (dump != NULL) {
537        g_printf = dump;
538    } else {
539        g_printf = printf;
540    }
541    TriggerWorkSpace *workSpace = GetTriggerWorkSpace();
542    PARAM_CHECK(workSpace != NULL, return, "Invalid workSpace ");
543    PARAM_DUMP("workspace queue BOOT info:\n");
544    DumpTrigger_(workSpace, TRIGGER_BOOT);
545    PARAM_DUMP("workspace queue parameter info:\n");
546    DumpTrigger_(workSpace, TRIGGER_PARAM);
547    PARAM_DUMP("workspace queue other info:\n");
548    DumpTrigger_(workSpace, TRIGGER_UNKNOW);
549    PARAM_DUMP("workspace queue watch info:\n");
550    DumpTrigger_(workSpace, TRIGGER_PARAM_WATCH);
551    PARAM_DUMP("workspace queue wait info:\n");
552    DumpTrigger_(workSpace, TRIGGER_PARAM_WAIT);
553
554    PARAM_DUMP("workspace queue execute info:\n");
555    PARAM_DUMP("queue info count: %u start: %u end: %u\n",
556        workSpace->executeQueue.queueCount, workSpace->executeQueue.startIndex, workSpace->executeQueue.endIndex);
557    for (uint32_t index = workSpace->executeQueue.startIndex; index < workSpace->executeQueue.endIndex; index++) {
558        TriggerNode *trigger = workSpace->executeQueue.executeQueue[index % workSpace->executeQueue.queueCount];
559        if (trigger != 0) {
560            PARAM_DUMP("    queue node trigger name: %s \n", GetTriggerName(trigger));
561        }
562    }
563}
564
565static int32_t CompareData_(const struct tagTriggerNode_ *trigger, const void *data)
566{
567    PARAM_CHECK(trigger != NULL && data != NULL, return -1, "Invalid trigger");
568    if (trigger->type == TRIGGER_PARAM_WAIT) {
569        WaitNode *node = (WaitNode *)trigger;
570        return node->waitId - *(uint32_t *)data;
571    } else if (trigger->type == TRIGGER_PARAM_WATCH) {
572        WatchNode *node = (WatchNode *)trigger;
573        return node->watchId - *(uint32_t *)data;
574    }
575    return -1;
576}
577
578static void TriggerHeadSetDefault(TriggerHeader *head)
579{
580    OH_ListInit(&head->triggerList);
581    head->triggerCount = 0;
582    head->cmdNodeCount = 0;
583    head->addTrigger = AddJobTrigger_;
584    head->nextTrigger = GetNextTrigger_;
585    head->delTrigger = DelJobTrigger_;
586    head->executeTrigger = NULL;
587    head->checkAndMarkTrigger = CheckAndMarkTrigger_;
588    head->checkTriggerMatch = CheckBootMatch_;
589    head->checkCondition = CheckBootCondition_;
590    head->getCondition = GetBootCondition_;
591    head->getTriggerName = GetJobName_;
592    head->dumpTrigger = DumpJobTrigger_;
593    head->compareData = CompareData_;
594}
595
596static int JobNodeNodeCompare(const HashNode *node1, const HashNode *node2)
597{
598    JobNode *jobNode1 = HASHMAP_ENTRY(node1, JobNode, hashNode);
599    JobNode *jobNode2 = HASHMAP_ENTRY(node2, JobNode, hashNode);
600    return strcmp(jobNode1->name, jobNode2->name);
601}
602
603static int JobNodeKeyCompare(const HashNode *node1, const void *key)
604{
605    JobNode *jobNode1 = HASHMAP_ENTRY(node1, JobNode, hashNode);
606    return strcmp(jobNode1->name, (char *)key);
607}
608
609static int JobNodeGetNodeHasCode(const HashNode *node)
610{
611    JobNode *jobNode = HASHMAP_ENTRY(node, JobNode, hashNode);
612    int code = 0;
613    size_t nameLen = strlen(jobNode->name);
614    for (size_t i = 0; i < nameLen; i++) {
615        code += jobNode->name[i] - 'A';
616    }
617    return code;
618}
619
620static int JobNodeGetKeyHasCode(const void *key)
621{
622    int code = 0;
623    const char *buff = (char *)key;
624    size_t buffLen = strlen(buff);
625    for (size_t i = 0; i < buffLen; i++) {
626        code += buff[i] - 'A';
627    }
628    return code;
629}
630
631static void JobNodeFree(const HashNode *node, void *context)
632{
633    JobNode *jobNode = HASHMAP_ENTRY(node, JobNode, hashNode);
634    FreeTrigger(GetTriggerWorkSpace(), (TriggerNode *)jobNode);
635}
636
637void InitTriggerHead(const TriggerWorkSpace *workSpace)
638{
639    HashInfo info = {
640        JobNodeNodeCompare,
641        JobNodeKeyCompare,
642        JobNodeGetNodeHasCode,
643        JobNodeGetKeyHasCode,
644        JobNodeFree,
645        64
646    };
647    PARAM_CHECK(workSpace != NULL, return, "Invalid workSpace");
648    int ret = OH_HashMapCreate((HashMapHandle *)&workSpace->hashMap, &info);
649    PARAM_CHECK(ret == 0, return, "Failed to create hash map");
650
651    TriggerHeader *head = (TriggerHeader *)&workSpace->triggerHead[TRIGGER_BOOT];
652    TriggerHeadSetDefault(head);
653    // param trigger
654    head = (TriggerHeader *)&workSpace->triggerHead[TRIGGER_PARAM];
655    TriggerHeadSetDefault(head);
656    head->checkTriggerMatch = CheckParamMatch_;
657    head->checkCondition = CheckParamCondition_;
658    head->getCondition = GetTriggerCondition_;
659    // unknown trigger
660    head = (TriggerHeader *)&workSpace->triggerHead[TRIGGER_UNKNOW];
661    TriggerHeadSetDefault(head);
662    head->checkTriggerMatch = CheckUnknowMatch_;
663    head->checkCondition = CheckUnknowCondition_;
664    head->getCondition = GetTriggerCondition_;
665    // wait trigger
666    head = (TriggerHeader *)&workSpace->triggerHead[TRIGGER_PARAM_WAIT];
667    TriggerHeadSetDefault(head);
668    head->addTrigger = AddWatchTrigger_;
669    head->delTrigger = DelWatchTrigger_;
670    head->checkTriggerMatch = CheckParamMatch_;
671    head->checkCondition = CheckParamCondition_;
672    head->getCondition = GetTriggerCondition_;
673    head->dumpTrigger = DumpWaitTrigger_;
674    head->getTriggerName = GetWatchName_;
675    // watch trigger
676    head = (TriggerHeader *)&workSpace->triggerHead[TRIGGER_PARAM_WATCH];
677    TriggerHeadSetDefault(head);
678    head->addTrigger = AddWatchTrigger_;
679    head->delTrigger = DelWatchTrigger_;
680    head->checkTriggerMatch = CheckBootMatch_;
681    head->checkCondition = CheckWatchCondition_;
682    head->getCondition = GetTriggerCondition_;
683    head->dumpTrigger = DumpWatchTrigger_;
684    head->getTriggerName = GetWatchName_;
685}
686
687void DelWatchTrigger(int type, const void *data)
688{
689    PARAM_CHECK(data != NULL, return, "Invalid data");
690    TriggerHeader *head = GetTriggerHeader(GetTriggerWorkSpace(), type);
691    PARAM_CHECK(head != NULL, return, "Failed to get header %d", type);
692    PARAM_CHECK(head->compareData != NULL, return, "Invalid compareData");
693    TriggerNode *trigger = head->nextTrigger(head, NULL);
694    while (trigger != NULL) {
695        if (head->compareData(trigger, data) == 0) {
696            head->delTrigger(GetTriggerWorkSpace(), trigger);
697            return;
698        }
699        trigger = head->nextTrigger(head, trigger);
700    }
701}
702
703void ClearWatchTrigger(ParamWatcher *watcher, int type)
704{
705    PARAM_CHECK(watcher != NULL, return, "Invalid watcher");
706    TriggerHeader *head = GetTriggerHeader(GetTriggerWorkSpace(), type);
707    PARAM_CHECK(head != NULL, return, "Failed to get header %d", type);
708    ListNode *node = watcher->triggerHead.next;
709    while (node != &watcher->triggerHead) {
710        TriggerNode *trigger = NULL;
711        if (type == TRIGGER_PARAM_WAIT) {
712            trigger = (TriggerNode *)ListEntry(node, WaitNode, item);
713        } else if (type == TRIGGER_PARAM_WATCH) {
714            trigger = (TriggerNode *)ListEntry(node, WatchNode, item);
715        }
716        if (trigger == NULL || type != trigger->type) {
717            PARAM_LOGE("ClearWatchTrigger %s error type %d", GetTriggerName(trigger), type);
718            return;
719        }
720        PARAM_LOGV("ClearWatchTrigger %s", GetTriggerName(trigger));
721        ListNode *next = node->next;
722        FreeTrigger(GetTriggerWorkSpace(), trigger);
723        node = next;
724    }
725}
726
727int CheckWatchTriggerTimeout(void)
728{
729    TriggerHeader *head = GetTriggerHeader(GetTriggerWorkSpace(), TRIGGER_PARAM_WAIT);
730    PARAM_CHECK(head != NULL && head->nextTrigger != NULL, return 0, "Invalid header");
731    int hasNode = 0;
732    WaitNode *node = (WaitNode *)head->nextTrigger(head, NULL);
733    while (node != NULL) {
734        WaitNode *next = (WaitNode *)head->nextTrigger(head, (TriggerNode *)node);
735        if (node->timeout > 0) {
736            node->timeout--;
737        } else {
738            head->executeTrigger((TriggerNode*)node, NULL, 0);
739            FreeTrigger(GetTriggerWorkSpace(), (TriggerNode *)node);
740        }
741        hasNode = 1;
742        node = next;
743    }
744    return hasNode;
745}
746
747TriggerHeader *GetTriggerHeader(const TriggerWorkSpace *workSpace, int type)
748{
749    if (workSpace == NULL || type >= TRIGGER_MAX) {
750        return NULL;
751    }
752    return (TriggerHeader *)&workSpace->triggerHead[type];
753}
754
755char *GetTriggerCache(uint32_t *size)
756{
757    TriggerWorkSpace *space = GetTriggerWorkSpace();
758    if (space == NULL) {
759        return NULL;
760    }
761    if (size != NULL) {
762        *size = sizeof(space->cache) / sizeof(space->cache[0]);
763    }
764    return space->cache;
765}
766
767const char *GetTriggerName(const TriggerNode *trigger)
768{
769    PARAM_CHECK(trigger != NULL, return "", "Invalid trigger");
770    TriggerHeader *triggerHead = GetTriggerHeader(GetTriggerWorkSpace(), trigger->type);
771    if (triggerHead) {
772        return triggerHead->getTriggerName(trigger);
773    }
774    return "";
775}
776