/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "trigger_manager.h" #include #include #include #include #include #include #include #include #include #include #include "init_cmds.h" #include "init_utils.h" #include "trigger_checker.h" #define LABEL "Trigger" #define TRIGGER_AREA_SPACE 1024*64 #define TRIGGER_EXECUTE_QUEUE 64 #define BUFFER_SIZE 256 #define CHECK_INDEX_VALID(workSpace, index) \ (u_int32_t)(index) < sizeof((workSpace)->header) / sizeof((workSpace)->header[0]) #ifdef STARTUP_LOCAL #define TRIGGER_PATH "/media/sf_ubuntu/test/__trigger__/trigger" #else #define TRIGGER_PATH "/dev/__trigger__/trigger" #endif int InitTriggerWorkSpace(TriggerWorkSpace *workSpace) { PARAM_CHECK(workSpace != NULL, return -1, "Invalid parm"); if (workSpace->area != NULL) { return 0; } CheckAndCreateDir(TRIGGER_PATH); int fd = open(TRIGGER_PATH, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0444); PARAM_CHECK(fd >= 0, return -1, "Open file fail error %s", strerror(errno)); lseek(fd, TRIGGER_AREA_SPACE, SEEK_SET); write(fd, "", 1); void *areaAddr = (void *)mmap(NULL, TRIGGER_AREA_SPACE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); PARAM_CHECK(areaAddr != MAP_FAILED, close(fd); return -1, "Failed to map memory error %s", strerror(errno)); close(fd); // 第一部分做执行队列 workSpace->executeQueue.executeQueue = (u_int32_t *)areaAddr; workSpace->executeQueue.queueCount = TRIGGER_EXECUTE_QUEUE; workSpace->executeQueue.startIndex = 0; workSpace->executeQueue.endIndex = 0; pthread_mutex_init(&workSpace->executeQueue.mutex, NULL); // 动态数据保存 workSpace->area = (TriggerArea *)(areaAddr + TRIGGER_EXECUTE_QUEUE * sizeof(u_int32_t)); atomic_init(&workSpace->area->serial, ATOMIC_VAR_INIT(0)); workSpace->area->dataSize = TRIGGER_AREA_SPACE - sizeof(TriggerArea) - TRIGGER_EXECUTE_QUEUE * sizeof(u_int32_t); workSpace->area->currOffset = sizeof(TriggerArea) + TRIGGER_EXECUTE_QUEUE * sizeof(u_int32_t); for (size_t i = 0; i < sizeof(workSpace->header) / sizeof(workSpace->header[0]); i++) { atomic_init(&workSpace->header[i].firstTrigger, ATOMIC_VAR_INIT(0)); atomic_init(&workSpace->header[i].lastTrigger, ATOMIC_VAR_INIT(0)); } return 0; } static CommandNode *GetCmdByIndex(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t index) { if (index == 0 || index == (u_int32_t)-1) { return NULL; } u_int32_t size = sizeof(CommandNode) + 2; PARAM_CHECK((index + size) < workSpace->area->dataSize, return NULL, "Invalid index for cmd %u", index); return (CommandNode *)(workSpace->area->data + index); } static u_int32_t AddCommand(TriggerWorkSpace *workSpace, TriggerNode *trigger, const char *cmdName, const char *content) { PARAM_CHECK(workSpace != NULL && trigger != NULL, return 0, "list is null"); u_int32_t size = sizeof(CommandNode) + strlen(cmdName) + 1; size += (content == NULL) ? 1 : strlen(content) + 1; PARAM_CHECK((workSpace->area->currOffset + size) < workSpace->area->dataSize, return 0, "Not enough memory for cmd %u %u", size, workSpace->area->currOffset); CommandNode *node = (CommandNode *)(workSpace->area->data + workSpace->area->currOffset); PARAM_CHECK(node != NULL, return 0, "Failed to alloc memory for command"); int ret = memcpy_s(node->name, sizeof(node->name) - 1, cmdName, strlen(cmdName)); PARAM_CHECK(ret == 0, return 0, "Failed to copy command"); node->name[strlen(cmdName)] = '\0'; if (content != NULL) { ret = memcpy_s(node->content, size, content, strlen(content)); node->content[strlen(content)] = '\0'; PARAM_CHECK(ret == 0, return 0, "Failed to copy command"); } else { node->content[0] = '\0'; } u_int32_t offset = workSpace->area->currOffset; atomic_init(&node->next, ATOMIC_VAR_INIT(0)); // 插入队列 if (trigger->firstCmd == 0) { atomic_store_explicit(&trigger->firstCmd, offset, memory_order_release); atomic_store_explicit(&trigger->lastCmd, offset, memory_order_release); } else { CommandNode *lastNode = GetCmdByIndex(workSpace, trigger, trigger->lastCmd); if (lastNode != NULL) { atomic_store_explicit(&lastNode->next, offset, memory_order_release); } atomic_store_explicit(&trigger->lastCmd, offset, memory_order_release); } workSpace->area->currOffset += size; return offset; } static TriggerNode *GetTriggerByIndex(TriggerWorkSpace *workSpace, u_int32_t index) { if (index == 0 || index == (u_int32_t)-1) { return NULL; } u_int32_t size = sizeof(TriggerNode) + 1; PARAM_CHECK((index + size) < workSpace->area->dataSize, return NULL, "Invalid index for trigger %u", index); return (TriggerNode *)(workSpace->area->data + index); } static u_int32_t AddTrigger(TriggerWorkSpace *workSpace, int type, const char *name, const char *condition) { PARAM_CHECK(workSpace != NULL && name != NULL, return 0, "list is null"); const char *tmpCond = condition; if (type == TRIGGER_BOOT && condition == NULL) { tmpCond = name; } u_int32_t conditionSize = (tmpCond == NULL) ? 1 : strlen(tmpCond) + 1 + CONDITION_EXTEND_LEN; PARAM_CHECK((workSpace->area->currOffset + sizeof(TriggerNode) + conditionSize) < workSpace->area->dataSize, return -1, "Not enough memory for cmd"); TriggerNode *node = (TriggerNode *)(workSpace->area->data + workSpace->area->currOffset); PARAM_CHECK(node != NULL, return 0, "Failed to alloc memory for trigger"); node->type = type; int ret = memcpy_s(node->name, sizeof(node->name) - 1, name, strlen(name)); PARAM_CHECK(ret == 0, return 0, "Failed to memcpy_s for trigger"); node->name[strlen(name)] = '\0'; if (tmpCond != NULL) { if (type == TRIGGER_PROPERTY) { ret = ConvertInfixToPrefix(tmpCond, node->condition, conditionSize); PARAM_CHECK(ret == 0, return 0, "Failed to memcpy_s for trigger"); } else { ret = memcpy_s(node->condition, strlen(tmpCond) + 1, tmpCond, strlen(tmpCond)); PARAM_CHECK(ret == 0, return 0, "Failed to memcpy_s for trigger"); node->condition[strlen(tmpCond)] = '\0'; } } else { node->condition[0] = '\0'; } u_int32_t offset = workSpace->area->currOffset; atomic_init(&node->serial, ATOMIC_VAR_INIT(0)); atomic_init(&node->next, ATOMIC_VAR_INIT(0)); atomic_init(&node->firstCmd, ATOMIC_VAR_INIT(0)); atomic_init(&node->lastCmd, ATOMIC_VAR_INIT(0)); // 插入到trigger队列中 if (workSpace->header[type].firstTrigger == 0) { atomic_store_explicit(&workSpace->header[type].firstTrigger, offset, memory_order_release); atomic_store_explicit(&workSpace->header[type].lastTrigger, offset, memory_order_release); } else { TriggerNode *lastNode = GetTriggerByIndex(workSpace, workSpace->header[type].lastTrigger); if (lastNode != NULL) { atomic_store_explicit(&lastNode->next, offset, memory_order_release); } atomic_store_explicit(&workSpace->header[type].lastTrigger, offset, memory_order_release); } workSpace->area->currOffset += conditionSize + sizeof(TriggerNode); return offset; } static int GetTriggerIndex(const char *type) { if (strncmp("param", type, strlen("param")) == 0) { return TRIGGER_PROPERTY; } static const char *triggerType[] = { "pre-init", "boot", "early-init", "init", "early-init", "late-init", "post-init", "early-fs", "post-fs", "late-fs", "post-fs-data", "nonencrypted", "firmware_mounts_complete", "load_persist_params_action" }; for (size_t i = 0; i < sizeof(triggerType) / sizeof(char*); i++) { if (strncmp(triggerType[i], type, strlen(triggerType[i])) == 0) { return TRIGGER_BOOT; } } return TRIGGER_BOOT; } static int CheckBootTriggerMatch(TriggerNode *trigger, void *content, u_int32_t contentSize) { if (strncmp(trigger->name, (char *)content, contentSize) == 0) { return 1; } return 0; } int ParseTrigger(TriggerWorkSpace *workSpace, cJSON *triggerItem) { PARAM_CHECK(triggerItem != NULL, return -1, "Invalid file"); PARAM_CHECK(workSpace != NULL, return -1, "Failed to create trigger list"); char *name = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "name")); PARAM_CHECK(name != NULL, return -1, "Can not get name from cfg"); char *condition = cJSON_GetStringValue(cJSON_GetObjectItem(triggerItem, "condition")); int index = GetTriggerIndex(name); PARAM_CHECK(CHECK_INDEX_VALID(workSpace, index), return -1, "Failed to get trigger index"); u_int32_t offset = 0; TriggerNode *trigger = GetTriggerByName(workSpace, name, &offset); if (trigger == NULL) { offset = AddTrigger(workSpace, index, name, condition); PARAM_CHECK(offset > 0, return -1, "Failed to create trigger %s", name); trigger = GetTriggerByIndex(workSpace, offset); } else { if (condition != NULL) { PARAM_LOGE("Warning parseTrigger %s %s", name, condition); } } PARAM_LOGE("ParseTrigger %s %u", name, offset); // 添加命令行 cJSON* cmdItems = cJSON_GetObjectItem(triggerItem, CMDS_ARR_NAME_IN_JSON); PARAM_CHECK(cJSON_IsArray(cmdItems), return -1, "Command item must be array"); int cmdLinesCnt = cJSON_GetArraySize(cmdItems); PARAM_CHECK(cmdLinesCnt > 0, return -1, "Command array size must positive %s", name); for (int i = 0; i < cmdLinesCnt; ++i) { char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdItems, i)); PARAM_CHECK(cmdLinesCnt > 0, continue, "Command is null"); size_t cmdLineLen = strlen(cmdLineStr); const char *matchCmd = GetMatchCmd(cmdLineStr); if (matchCmd == NULL && strncmp(cmdLineStr, TRIGGER_CMD, strlen(TRIGGER_CMD)) == 0) { matchCmd = TRIGGER_CMD; } PARAM_CHECK(matchCmd != NULL, continue, "Command not support %s", cmdLineStr); size_t matchLen = strlen(matchCmd); if (matchLen == cmdLineLen) { offset = AddCommand(workSpace, trigger, matchCmd, NULL); } else { offset = AddCommand(workSpace, trigger, matchCmd, cmdLineStr + matchLen); } //PARAM_LOGE("AddCommand %u %s %u", offset, cmdLineStr, workSpace->area->currOffset); PARAM_CHECK(offset > 0, continue, "Failed to add command %s", cmdLineStr); } return 0; } int ExecuteTrigger(TriggerWorkSpace *workSpace, TriggerNode *trigger, CMD_EXECUTE cmdExecuter) { PARAM_CHECK(workSpace != NULL && trigger != NULL && cmdExecuter != NULL, return -1, "Invalid param"); PARAM_LOGI("ExecuteCmds trigger %s", trigger->name); CommandNode *cmd = GetCmdByIndex(workSpace, trigger, trigger->firstCmd); while (cmd != NULL) { cmdExecuter(trigger, cmd->name, cmd->content); cmd = GetCmdByIndex(workSpace, trigger, cmd->next); } return 0; } int ExecuteQueuePush(TriggerWorkSpace *workSpace, TriggerNode *trigger, u_int32_t triggerIndex) { PARAM_CHECK(workSpace != NULL, return -1, "Invalid area"); pthread_mutex_lock(&workSpace->executeQueue.mutex); u_int32_t index = workSpace->executeQueue.endIndex++ % workSpace->executeQueue.queueCount; workSpace->executeQueue.executeQueue[index] = triggerIndex; pthread_mutex_unlock(&workSpace->executeQueue.mutex); return 0; } TriggerNode *ExecuteQueuePop(TriggerWorkSpace *workSpace) { if (workSpace->executeQueue.endIndex <= workSpace->executeQueue.startIndex) { return NULL; } pthread_mutex_lock(&workSpace->executeQueue.mutex); u_int32_t currIndex = workSpace->executeQueue.startIndex % workSpace->executeQueue.queueCount; u_int32_t triggerIndex = workSpace->executeQueue.executeQueue[currIndex]; workSpace->executeQueue.executeQueue[currIndex] = 0; workSpace->executeQueue.startIndex++; pthread_mutex_unlock(&workSpace->executeQueue.mutex); return GetTriggerByIndex(workSpace, triggerIndex); } int ExecuteQueueSize(TriggerWorkSpace *workSpace) { PARAM_CHECK(workSpace != NULL, return 0, "Invalid param"); return workSpace->executeQueue.endIndex - workSpace->executeQueue.startIndex; } int CheckTrigger(TriggerWorkSpace *workSpace, int type, void *content, u_int32_t contentSize, PARAM_CHECK_DONE triggerExecuter) { static TRIGGER_MATCH triggerCheckMatch[TRIGGER_MAX] = { CheckBootTriggerMatch, NULL, NULL }; PARAM_LOGI("ExecuteTrigger check content %s", (char*)content); PARAM_CHECK(workSpace != NULL, return -1, "Trigger not init"); PARAM_CHECK(CHECK_INDEX_VALID(workSpace, type), return -1, "Invalid type %d", type); PARAM_CHECK((u_int32_t)type < sizeof(triggerCheckMatch) / sizeof(triggerCheckMatch[0]), return -1, "Failed to get check function"); PARAM_CHECK(triggerCheckMatch[type] != NULL, return 0, "Failed to get check function"); u_int32_t index = workSpace->header[type].firstTrigger; TriggerNode *trigger = GetTriggerByIndex(workSpace, workSpace->header[type].firstTrigger); while (trigger != NULL) { if (triggerCheckMatch[type](trigger, content, contentSize) == 1) { // 等于1 则认为匹配 triggerExecuter(trigger, index); } index = trigger->next; trigger = GetTriggerByIndex(workSpace, trigger->next); } return 0; } int CheckParamTrigger(TriggerWorkSpace *workSpace, const char *content, u_int32_t contentSize, PARAM_CHECK_DONE triggerExecuter) { PARAM_CHECK(workSpace != NULL && content != NULL && triggerExecuter != NULL, return -1, "Failed arg for param trigger"); LogicCalculator calculator; CalculatorInit(&calculator, 100, sizeof(LogicData), 1); // 先解析content int ret = GetValueFromContent(content, contentSize, 0, calculator.inputName, SUPPORT_DATA_BUFFER_MAX); PARAM_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Failed parse content name"); ret = GetValueFromContent(content, contentSize, strlen(calculator.inputName) + 1, calculator.inputContent, SUPPORT_DATA_BUFFER_MAX); PARAM_CHECK(ret == 0, CalculatorFree(&calculator); return -1, "Failed parse content value"); PARAM_LOGI("CheckParamTrigger content %s ", content); u_int32_t index = workSpace->header[TRIGGER_PROPERTY].firstTrigger; TriggerNode *trigger = GetTriggerByIndex(workSpace, workSpace->header[TRIGGER_PROPERTY].firstTrigger); while (trigger != NULL) { ret = ComputeCondition(&calculator, trigger->condition); if (ret == 1) { triggerExecuter(trigger, index); } index = trigger->next; trigger = GetTriggerByIndex(workSpace, trigger->next); } CalculatorFree(&calculator); return 0; } TriggerNode *GetTriggerByName(TriggerWorkSpace *workSpace, const char *triggerName, u_int32_t *triggerIndex) { PARAM_CHECK(workSpace != NULL && triggerName != NULL, return NULL, "Invalid param"); for (size_t i = 0; i < sizeof(workSpace->header) / sizeof(workSpace->header[0]); i++) { u_int32_t index = workSpace->header[i].firstTrigger; TriggerNode *trigger = GetTriggerByIndex(workSpace, workSpace->header[i].firstTrigger); while (trigger != NULL) { if (strcmp(triggerName, trigger->name) == 0) { *triggerIndex = index; return trigger; } index = trigger->next; trigger = GetTriggerByIndex(workSpace, trigger->next); } } return NULL; }