mirror of
https://github.com/openharmony/startup_init_lite.git
synced 2026-07-21 20:45:22 -04:00
0ebd5aa69c
Signed-off-by: xionglei6@huawei.com <xionglei6@huawei.com>
373 lines
14 KiB
C
373 lines
14 KiB
C
/*
|
|
* 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 <pthread.h>
|
|
#include <unistd.h>
|
|
|
|
#include "init_cmds.h"
|
|
#include "init_service_manager.h"
|
|
#include "param_manager.h"
|
|
#include "param_utils.h"
|
|
#include "trigger_checker.h"
|
|
#include "trigger_manager.h"
|
|
|
|
#define LABEL "Trigger"
|
|
#define MAX_TRIGGER_COUNT_RUN_ONCE 20
|
|
static TriggerWorkSpace g_triggerWorkSpace = {};
|
|
|
|
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(TriggerNode *trigger, 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;
|
|
}
|
|
const char *cmdName = GetCmdKey(cmd->cmdKeyIndex);
|
|
if (cmdName == NULL) {
|
|
return;
|
|
}
|
|
if (strncmp(cmdName, TRIGGER_CMD, strlen(TRIGGER_CMD)) == 0) {
|
|
DoTriggerExec(cmd->content);
|
|
return;
|
|
}
|
|
#ifndef STARTUP_INIT_TEST
|
|
DoCmdByName(cmdName, cmd->content);
|
|
#endif
|
|
}
|
|
|
|
static int ExecuteTrigger(TriggerWorkSpace *workSpace, 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_LOGI("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:
|
|
PARAM_LOGI("CheckTriggers: %lu", eventId);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static const char *GetCmdInfo(const char *content, uint32_t contentSize, char **cmdParam)
|
|
{
|
|
static const char *ctrlCmds[][2] = {
|
|
{"reboot", "reboot "}
|
|
};
|
|
uint32_t 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;
|
|
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 < sizeof(triggerTypeStr) / sizeof(char *); i++) {
|
|
if (strcmp(triggerTypeStr[i], type) == 0) {
|
|
return TRIGGER_BOOT;
|
|
}
|
|
}
|
|
return TRIGGER_UNKNOW;
|
|
}
|
|
|
|
static 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 type = GetTriggerType(name);
|
|
PARAM_CHECK(type < TRIGGER_MAX, return -1, "Failed to get trigger index");
|
|
|
|
TriggerNode *trigger = GetTriggerByName(workSpace, name);
|
|
if (trigger == NULL) {
|
|
trigger = AddTrigger(&workSpace->triggerHead[type], 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, workSpace->triggerHead[type].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 = 0;
|
|
uint32_t cmdKeyIndex = 0;
|
|
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, &cmdKeyIndex);
|
|
PARAM_CHECK(matchCmd != NULL, continue, "Command not support %s", cmdLineStr);
|
|
size_t matchLen = strlen(matchCmd);
|
|
if (matchLen == cmdLineLen) {
|
|
ret = AddCommand(trigger, cmdKeyIndex, NULL);
|
|
} else {
|
|
ret = AddCommand(trigger, cmdKeyIndex, cmdLineStr + matchLen);
|
|
}
|
|
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) {
|
|
cJSON *item = cJSON_GetArrayItem(triggers, i);
|
|
ParseTrigger_(&g_triggerWorkSpace, item);
|
|
}
|
|
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 = malloc(TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *));
|
|
g_triggerWorkSpace.executeQueue.queueCount = TRIGGER_EXECUTE_QUEUE;
|
|
g_triggerWorkSpace.executeQueue.startIndex = 0;
|
|
g_triggerWorkSpace.executeQueue.endIndex = 0;
|
|
PARAM_CHECK(g_triggerWorkSpace.executeQueue.executeQueue != NULL,
|
|
return -1, "Failed to alloc memory for executeQueue");
|
|
int ret = memset_s(g_triggerWorkSpace.executeQueue.executeQueue,
|
|
TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *), 0, TRIGGER_EXECUTE_QUEUE * sizeof(TriggerNode *));
|
|
PARAM_CHECK(ret == EOK, return -1, "Failed to memset for executeQueue");
|
|
|
|
// 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);
|
|
ParamTaskClose(g_triggerWorkSpace.eventHandle);
|
|
}
|
|
|
|
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;
|
|
}
|