Files
startup_init_lite/services/param/trigger/trigger_processor.c
T
xionglei6 de150e9310 init: fix codedex
Signed-off-by: xionglei6 <xionglei6@huawei.com>
2021-11-29 14:26:36 +08:00

423 lines
16 KiB
C
Executable File

/*
* 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 <ctype.h>
#include <unistd.h>
#include "init_cmds.h"
#include "init_param.h"
#include "init_service_manager.h"
#include "init_utils.h"
#include "param_manager.h"
#include "param_utils.h"
#include "trigger_checker.h"
#include "trigger_manager.h"
#define MAX_TRIGGER_COUNT_RUN_ONCE 20
static TriggerWorkSpace g_triggerWorkSpace = {};
#ifdef PARAM_TEST
#define MAX_COUNT 1000
#define READ_DURATION 100000
#define TEST_PARAM_NAME "test.random.read.001"
static void AddTestTrigger(const TriggerWorkSpace *workSpace)
{
TriggerHeader *header = (TriggerHeader *)&workSpace->triggerHead[TRIGGER_PARAM];
TriggerNode *trigger = AddTrigger(header, "param:test.randrom.test.start=1", "test.randrom.test.start=1", 0);
PARAM_CHECK(trigger != NULL, return, "Failed to create test trigger");
int cmdKeyIndex = 0;
GetMatchCmd("setparam ", &cmdKeyIndex);
int ret = AddCommand(trigger, (uint32_t)CMD_INDEX_FOR_PARA_TEST, NULL);
PARAM_CHECK(ret == 0, return, "Failed to add command");
}
static void TestTimerCallback(ParamTaskPtr timer, void *context)
{
char buffer[32] = { 0 }; // 32 buffer size
static int index = 0;
index++;
if (index >= MAX_COUNT) {
ParamTaskClose(timer);
}
static uint32_t value = 0;
int count = 0;
while (count < MAX_COUNT) {
const int wait = READ_DURATION + READ_DURATION; // 100ms
sprintf_s(buffer, sizeof(buffer), "%u", value);
PARAM_LOGI("set param name: %s, value %s", TEST_PARAM_NAME, buffer);
SystemWriteParam(TEST_PARAM_NAME, buffer);
usleep(wait);
count++;
value++;
}
}
#endif
void DoTriggerExec(const char *triggerName)
{
PARAM_CHECK(triggerName != NULL, return, "Invalid param");
TriggerNode *trigger = GetTriggerByName(&g_triggerWorkSpace, triggerName);
if (trigger != NULL && !TRIGGER_IN_QUEUE(trigger)) { // 不在队列中
PARAM_LOGI("DoTriggerExec trigger %s", trigger->name);
TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_QUEUE);
ExecuteQueuePush(&g_triggerWorkSpace, trigger);
}
}
static void DoCmdExec(const TriggerNode *trigger, const CommandNode *cmd, const char *content, uint32_t size)
{
if (cmd->cmdKeyIndex == CMD_INDEX_FOR_PARA_WAIT || cmd->cmdKeyIndex == CMD_INDEX_FOR_PARA_WATCH) {
TriggerExtData *extData = TRIGGER_GET_EXT_DATA(trigger, TriggerExtData);
if (extData != NULL && extData->excuteCmd != NULL) {
extData->excuteCmd(extData, cmd->cmdKeyIndex, content);
}
return;
#ifdef PARAM_TEST
} else if (cmd->cmdKeyIndex == CMD_INDEX_FOR_PARA_TEST) {
ParamTaskPtr timer = NULL;
ParamTimerCreate(&timer, TestTimerCallback, NULL);
ParamTimerStart(timer, READ_DURATION, MAX_COUNT);
return;
#endif
}
#ifndef STARTUP_INIT_TEST
DoCmdByIndex(cmd->cmdKeyIndex, cmd->content);
#endif
}
static int ExecuteTrigger(const TriggerWorkSpace *workSpace, const TriggerNode *trigger)
{
PARAM_CHECK(workSpace != NULL && trigger != NULL, return -1, "Invalid trigger");
PARAM_CHECK(workSpace->cmdExec != NULL, return -1, "Invalid cmdExec");
PARAM_LOGI("ExecuteTrigger trigger %s", trigger->name);
CommandNode *cmd = GetNextCmdNode(trigger, NULL);
while (cmd != NULL) {
workSpace->cmdExec(trigger, cmd, NULL, 0);
cmd = GetNextCmdNode(trigger, cmd);
}
return 0;
}
static int DoTiggerCheckResult(TriggerNode *trigger, const char *content, uint32_t size)
{
UNUSED(content);
UNUSED(size);
if (TRIGGER_IN_QUEUE(trigger)) {
PARAM_LOGI("DoTiggerExecute trigger %s has been waiting execute", trigger->name);
return 0;
}
TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_QUEUE);
PARAM_LOGI("Add trigger %s to execute queue", trigger->name);
ExecuteQueuePush(&g_triggerWorkSpace, trigger);
return 0;
}
static int ExecuteTiggerImmediately(TriggerNode *trigger, const char *content, uint32_t size)
{
PARAM_CHECK(trigger != NULL, return -1, "Invalid trigger");
PARAM_CHECK(g_triggerWorkSpace.cmdExec != NULL, return -1, "Invalid cmdExec");
PARAM_LOGD("ExecuteTiggerImmediately trigger %s", trigger->name);
CommandNode *cmd = GetNextCmdNode(trigger, NULL);
while (cmd != NULL) {
g_triggerWorkSpace.cmdExec(trigger, cmd, content, size);
cmd = GetNextCmdNode(trigger, cmd);
}
if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_ONCE)) {
FreeTrigger(trigger);
}
return 0;
}
static void ExecuteQueueWork(uint32_t maxCount)
{
uint32_t executeCount = 0;
TriggerNode *trigger = ExecuteQueuePop(&g_triggerWorkSpace);
while (trigger != NULL) {
ExecuteTrigger(&g_triggerWorkSpace, trigger);
TRIGGER_CLEAR_FLAG(trigger, TRIGGER_FLAGS_QUEUE);
if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_SUBTRIGGER)) { // 检查boot:xxx=xxx 的trigger
CheckTrigger(&g_triggerWorkSpace, TRIGGER_UNKNOW,
trigger->name, strlen(trigger->name), ExecuteTiggerImmediately);
}
if (TRIGGER_TEST_FLAG(trigger, TRIGGER_FLAGS_ONCE)) {
FreeTrigger(trigger);
}
executeCount++;
if (executeCount > maxCount) {
break;
}
trigger = ExecuteQueuePop(&g_triggerWorkSpace);
}
}
static void ProcessParamEvent(uint64_t eventId, const char *content, uint32_t size)
{
UNUSED(eventId);
UNUSED(content);
UNUSED(size);
ExecuteQueueWork(MAX_TRIGGER_COUNT_RUN_ONCE);
}
static void ProcessBeforeEvent(uint64_t eventId, const char *content, uint32_t size)
{
switch (eventId) {
case EVENT_TRIGGER_PARAM: {
CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM, content, size, DoTiggerCheckResult);
break;
}
case EVENT_TRIGGER_BOOT: {
CheckTrigger(&g_triggerWorkSpace, TRIGGER_BOOT, content, size, DoTiggerCheckResult);
break;
}
case EVENT_TRIGGER_PARAM_WAIT: {
CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM_WAIT, content, size, ExecuteTiggerImmediately);
break;
}
case EVENT_TRIGGER_PARAM_WATCH: {
CheckTrigger(&g_triggerWorkSpace, TRIGGER_PARAM_WATCH, content, size, ExecuteTiggerImmediately);
break;
}
default:
break;
}
}
static const char *GetCmdInfo(const char *content, uint32_t contentSize, char **cmdParam)
{
static const char *ctrlCmds[][2] = {
{"reboot", "reboot "}
};
int index = 0;
for (size_t i = 0; i < sizeof(ctrlCmds) / sizeof(ctrlCmds[0]); i++) {
if (strncmp(content, ctrlCmds[i][0], strlen(ctrlCmds[i][0])) == 0) {
*cmdParam = (char *)content;
return GetMatchCmd(ctrlCmds[i][1], &index);
}
}
return NULL;
}
static void SendTriggerEvent(int type, const char *content, uint32_t contentLen)
{
PARAM_CHECK(content != NULL, return, "Invalid param");
PARAM_LOGD("SendTriggerEvent type %d content %s", type, content);
if (type == EVENT_TRIGGER_PARAM) {
int ctrlSize = strlen(SYS_POWER_CTRL);
if (strncmp(content, SYS_POWER_CTRL, ctrlSize) == 0) {
char *cmdParam = NULL;
const char *matchCmd = GetCmdInfo(content + ctrlSize, contentLen - ctrlSize, &cmdParam);
PARAM_LOGD("SendTriggerEvent matchCmd %s", matchCmd);
if (matchCmd != NULL) {
#ifndef STARTUP_INIT_TEST
DoCmdByName(matchCmd, cmdParam);
#endif
} else {
PARAM_LOGE("SendTriggerEvent cmd %s not found", content);
}
} else if (strncmp(content, OHOS_CTRL_START, strlen(OHOS_CTRL_START)) == 0) {
StartServiceByName(content + strlen(OHOS_CTRL_START), false);
} else if (strncmp(content, OHOS_CTRL_STOP, strlen(OHOS_CTRL_STOP)) == 0) {
StopServiceByName(content + strlen(OHOS_CTRL_STOP));
} else {
ParamEventSend(g_triggerWorkSpace.eventHandle, (uint64_t)type, content, contentLen);
}
} else {
ParamEventSend(g_triggerWorkSpace.eventHandle, (uint64_t)type, content, contentLen);
}
}
void PostParamTrigger(int type, const char *name, const char *value)
{
PARAM_CHECK(name != NULL && value != NULL, return, "Invalid param");
uint32_t bufferSize = strlen(name) + strlen(value) + 1 + 1 + 1;
PARAM_CHECK(bufferSize < (PARAM_CONST_VALUE_LEN_MAX + PARAM_NAME_LEN_MAX + 1 + 1 + 1),
return, "bufferSize is longest %d", bufferSize);
char *buffer = (char *)malloc(bufferSize);
PARAM_CHECK(buffer != NULL, return, "Failed to alloc memory for param %s", name);
int ret = sprintf_s(buffer, bufferSize - 1, "%s=%s", name, value);
PARAM_CHECK(ret > EOK, free(buffer);
return, "Failed to copy param");
SendTriggerEvent(type, buffer, strlen(buffer));
free(buffer);
}
void PostTrigger(EventType type, const char *content, uint32_t contentLen)
{
PARAM_CHECK(content != NULL && contentLen > 0, return, "Invalid param");
SendTriggerEvent(type, content, contentLen);
}
static int GetTriggerType(const char *type)
{
if (strncmp("param:", type, strlen("param:")) == 0) {
return TRIGGER_PARAM;
}
const char *triggerTypeStr[] = {
"pre-init", "boot", "early-init", "init", "early-init", "late-init", "post-init",
"early-fs", "post-fs", "late-fs", "post-fs-data"
};
for (size_t i = 0; i < ARRAY_LENGTH(triggerTypeStr); i++) {
if (strcmp(triggerTypeStr[i], type) == 0) {
return TRIGGER_BOOT;
}
}
return TRIGGER_UNKNOW;
}
static int GetCommandInfo(const char *cmdLine, int *cmdKeyIndex, char **content)
{
const char *matchCmd = GetMatchCmd(cmdLine, cmdKeyIndex);
PARAM_CHECK(matchCmd != NULL, return -1, "Command not support %s", cmdLine);
char *str = strstr(cmdLine, matchCmd);
if (str != NULL) {
str += strlen(matchCmd);
}
while (str != NULL && isspace(*str)) {
str++;
}
*content = str;
return 0;
}
static int ParseTrigger_(const TriggerWorkSpace *workSpace, const 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 type = GetTriggerType(name);
PARAM_CHECK(type < TRIGGER_MAX, return -1, "Failed to get trigger index");
TriggerHeader *header = (TriggerHeader *)&workSpace->triggerHead[type];
TriggerNode *trigger = GetTriggerByName(workSpace, name);
if (trigger == NULL) {
trigger = AddTrigger(header, name, condition, 0);
PARAM_CHECK(trigger != NULL, return -1, "Failed to create trigger %s", name);
}
if (type == TRIGGER_BOOT) { // 设置trigger立刻删除,如果是boot
TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_ONCE);
TRIGGER_SET_FLAG(trigger, TRIGGER_FLAGS_SUBTRIGGER);
}
PARAM_LOGD("ParseTrigger %s type %d count %d", name, type, header->triggerCount);
// 添加命令行
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);
int ret;
int cmdKeyIndex = 0;
for (int i = 0; (i < cmdLinesCnt) && (i < TRIGGER_MAX_CMD); ++i) {
char *cmdLineStr = cJSON_GetStringValue(cJSON_GetArrayItem(cmdItems, i));
PARAM_CHECK(cmdLineStr != NULL, continue, "Command is null");
char *content = NULL;
ret = GetCommandInfo(cmdLineStr, &cmdKeyIndex, &content);
PARAM_CHECK(ret == 0, continue, "Command not support %s", cmdLineStr);
ret = AddCommand(trigger, (uint32_t)cmdKeyIndex, content);
PARAM_CHECK(ret == 0, continue, "Failed to add command %s", cmdLineStr);
}
return 0;
}
int ParseTriggerConfig(const cJSON *fileRoot)
{
PARAM_CHECK(fileRoot != NULL, return -1, "Invalid file");
cJSON *triggers = cJSON_GetObjectItemCaseSensitive(fileRoot, TRIGGER_ARR_NAME_IN_JSON);
PARAM_CHECK(cJSON_IsArray(triggers), return -1, "Trigger item must array");
int size = cJSON_GetArraySize(triggers);
PARAM_CHECK(size > 0, return -1, "Trigger array size must positive");
for (int i = 0; i < size && i < TRIGGER_MAX_CMD; ++i) {
cJSON *item = cJSON_GetArrayItem(triggers, i);
ParseTrigger_(&g_triggerWorkSpace, item);
}
#ifdef PARAM_TEST
// for test
AddTestTrigger(&g_triggerWorkSpace);
#endif
return 0;
}
int InitTriggerWorkSpace(void)
{
if (g_triggerWorkSpace.eventHandle != NULL) {
return 0;
}
g_triggerWorkSpace.cmdExec = DoCmdExec;
ParamEventTaskCreate(&g_triggerWorkSpace.eventHandle, ProcessParamEvent, ProcessBeforeEvent);
PARAM_CHECK(g_triggerWorkSpace.eventHandle != NULL, return -1, "Failed to event handle");
// executeQueue
g_triggerWorkSpace.executeQueue.executeQueue = calloc(1, TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *));
PARAM_CHECK(g_triggerWorkSpace.executeQueue.executeQueue != NULL,
return -1, "Failed to alloc memory for executeQueue");
g_triggerWorkSpace.executeQueue.queueCount = TRIGGER_EXECUTE_QUEUE;
g_triggerWorkSpace.executeQueue.startIndex = 0;
g_triggerWorkSpace.executeQueue.endIndex = 0;
// normal trigger
for (size_t i = 0; i < sizeof(g_triggerWorkSpace.triggerHead) / sizeof(g_triggerWorkSpace.triggerHead[0]); i++) {
PARAM_TRIGGER_HEAD_INIT(g_triggerWorkSpace.triggerHead[i]);
}
// for watcher trigger
PARAM_TRIGGER_HEAD_INIT(g_triggerWorkSpace.watcher.triggerHead);
ListInit(&g_triggerWorkSpace.waitList);
return 0;
}
void CloseTriggerWorkSpace(void)
{
// 释放trigger
for (size_t i = 0; i < sizeof(g_triggerWorkSpace.triggerHead) / sizeof(g_triggerWorkSpace.triggerHead[0]); i++) {
ClearTrigger(&g_triggerWorkSpace.triggerHead[i]);
}
free(g_triggerWorkSpace.executeQueue.executeQueue);
g_triggerWorkSpace.executeQueue.executeQueue = NULL;
ParamTaskClose(g_triggerWorkSpace.eventHandle);
g_triggerWorkSpace.eventHandle = NULL;
}
int CheckAndMarkTrigger(int type, const char *name)
{
if (type == TRIGGER_PARAM) {
return MarkTriggerToParam(&g_triggerWorkSpace, &g_triggerWorkSpace.triggerHead[type], name);
} else if (type != TRIGGER_PARAM_WAIT) {
return 0;
}
ParamWatcher *watcher = GetNextParamWatcher(&g_triggerWorkSpace, NULL);
while (watcher != NULL) {
if (MarkTriggerToParam(&g_triggerWorkSpace, &watcher->triggerHead, name)) {
return 1;
}
watcher = GetNextParamWatcher(&g_triggerWorkSpace, watcher);
}
return 0;
}
TriggerWorkSpace *GetTriggerWorkSpace(void)
{
return &g_triggerWorkSpace;
}
ParamWatcher *GetParamWatcher(const ParamTaskPtr worker)
{
if (worker != NULL) {
return (ParamWatcher *)ParamGetTaskUserData(worker);
}
return &g_triggerWorkSpace.watcher;
}