startup_init/services/init/init_group_manager.c
cheng_jinsong e18e0d7f07 系统优化
Signed-off-by: cheng_jinsong <chengjinsong2@huawei.com>
2023-05-08 16:15:45 +08:00

361 lines
11 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 "init_group_manager.h"
#include "init_jobs_internal.h"
#include "init_log.h"
#include "init_utils.h"
#include "securec.h"
#include "init_service_manager.h"
static InitWorkspace g_initWorkspace = {0, 0, {0}, {0}, {0}};
int GenerateHashCode(const char *key)
{
int code = 0;
size_t keyLen = strlen(key);
for (size_t i = 0; i < keyLen; i++) {
code += key[i] - 'A';
}
return code;
}
static int GetBootGroupMode(void)
{
static const char *groupModes[] = {
"device.boot.group",
"device.charge.group"
};
for (size_t i = 0; i < ARRAY_LENGTH(groupModes); i++) {
if (strcmp(g_initWorkspace.groupModeStr, groupModes[i]) == 0) {
return i;
}
}
return (int)GROUP_UNKNOW;
}
static int ParseGroupCfgItem(cJSON *root, int type, const char *itemName)
{
int itemNumber = 0;
cJSON *json = GetArrayItem(root, &itemNumber, itemName);
if (json == NULL) {
return 0;
}
for (int i = 0; i < itemNumber; ++i) {
cJSON *item = cJSON_GetArrayItem(json, i);
char *strValue = cJSON_GetStringValue(item);
if (strValue != NULL) {
AddGroupNode(type, strValue);
}
}
return 0;
}
static int InitParseGroupCfg_(const char *groupCfg)
{
INIT_LOGI("Parse group config %s", groupCfg);
char *fileBuf = ReadFileData(groupCfg);
INIT_ERROR_CHECK(fileBuf != NULL, return -1, "Failed to read file content %s", groupCfg);
cJSON *fileRoot = cJSON_Parse(fileBuf);
INIT_ERROR_CHECK(fileRoot != NULL, free(fileBuf);
return -1, "Failed to parse json file %s", groupCfg);
ParseGroupCfgItem(fileRoot, NODE_TYPE_JOBS, "jobs");
ParseGroupCfgItem(fileRoot, NODE_TYPE_SERVICES, "services");
ParseGroupCfgItem(fileRoot, NODE_TYPE_GROUPS, "groups");
cJSON_Delete(fileRoot);
free(fileBuf);
return 0;
}
static int InitImportGroupCfg_(InitGroupNode *groupRoot)
{
InitGroupNode *groupNode = groupRoot;
while (groupNode != NULL) {
groupRoot = groupNode->next;
InitParseGroupCfg_(groupNode->name);
free(groupNode);
groupNode = groupRoot;
}
return 0;
}
static int InitFreeGroupNodes_(InitGroupNode *groupRoot)
{
InitGroupNode *groupNode = groupRoot;
while (groupNode != NULL) {
groupRoot = groupNode->next;
if (groupNode->type < NODE_TYPE_GROUPS) { // remove from hashmap
OH_HashMapRemove(g_initWorkspace.hashMap[groupNode->type], groupNode->name);
}
free(groupNode);
groupNode = groupRoot;
}
return 0;
}
static char *GetAbsolutePath(const char *path, const char *cfgName, char *buffer, uint32_t buffSize)
{
int len = 0;
size_t cfgNameLen = strlen(cfgName);
int ext = 0;
if (cfgNameLen > strlen(".cfg")) {
ext = strcmp(cfgName + cfgNameLen - strlen(".cfg"), ".cfg") == 0;
}
if (cfgName[0] != '/') {
const char *format = ((ext != 0) ? "%s/%s" : "%s/%s.cfg");
len = sprintf_s(buffer, buffSize, format, path, cfgName);
} else {
const char *format = ((ext != 0) ? "%s" : "%s.cfg");
len = sprintf_s(buffer, buffSize, format, cfgName);
}
if (len <= 0) {
return NULL;
}
buffer[len] = '\0';
return buffer;
}
static int GroupNodeNodeCompare(const HashNode *node1, const HashNode *node2)
{
InitGroupNode *groupNode1 = HASHMAP_ENTRY(node1, InitGroupNode, hashNode);
InitGroupNode *groupNode2 = HASHMAP_ENTRY(node2, InitGroupNode, hashNode);
return strcmp(groupNode1->name, groupNode2->name);
}
static int GroupNodeKeyCompare(const HashNode *node1, const void *key)
{
InitGroupNode *groupNode1 = HASHMAP_ENTRY(node1, InitGroupNode, hashNode);
return strcmp(groupNode1->name, (char *)key);
}
static int GroupNodeGetKeyHashCode(const void *key)
{
return GenerateHashCode((const char *)key);
}
static int GroupNodeGetNodeHashCode(const HashNode *node)
{
InitGroupNode *groupNode = HASHMAP_ENTRY(node, InitGroupNode, hashNode);
return GenerateHashCode((const char *)groupNode->name);
}
static void GroupNodeFree(const HashNode *node, void *context)
{
InitGroupNode *groupNode = HASHMAP_ENTRY(node, InitGroupNode, hashNode);
if (groupNode->type == NODE_TYPE_SERVICES) {
ReleaseService(groupNode->data.service);
groupNode->data.service = NULL;
} else if (groupNode->type == NODE_TYPE_CMDS) {
ReleaseCmd(groupNode->data.cmd);
groupNode->data.cmd = NULL;
}
free(groupNode);
}
void InitServiceSpace(void)
{
if (g_initWorkspace.initFlags != 0) {
return;
}
HashInfo info = {
GroupNodeNodeCompare,
GroupNodeKeyCompare,
GroupNodeGetNodeHashCode,
GroupNodeGetKeyHashCode,
GroupNodeFree,
GROUP_HASHMAP_BUCKET
};
for (size_t i = 0; i < ARRAY_LENGTH(g_initWorkspace.hashMap); i++) {
int ret = OH_HashMapCreate(&g_initWorkspace.hashMap[i], &info);
if (ret != 0) {
INIT_LOGE("%s", "Failed to create hash map");
}
}
for (int i = 0; i < NODE_TYPE_MAX; i++) {
g_initWorkspace.groupNodes[i] = NULL;
}
// get boot mode, set default mode
strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), BOOT_GROUP_DEFAULT);
int ret = GetParameterFromCmdLine(BOOT_GROUP_NAME,
g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr));
if (ret != 0) {
INIT_LOGV("Failed to get boot group");
if (GetBootModeFromMisc() == GROUP_CHARGE) {
strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), "device.charge.group");
}
}
INIT_LOGI("boot start %s", g_initWorkspace.groupModeStr);
g_initWorkspace.groupMode = GetBootGroupMode();
g_initWorkspace.initFlags = 1;
}
int InitParseGroupCfg(void)
{
char buffer[128] = {0}; // 128 buffer size
char *realPath = GetAbsolutePath(GROUP_DEFAULT_PATH,
g_initWorkspace.groupModeStr, buffer, sizeof(buffer));
INIT_ERROR_CHECK(realPath != NULL, return -1,
"Failed to get path for %s", g_initWorkspace.groupModeStr);
InitParseGroupCfg_(realPath);
InitGroupNode *groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
int level = 0;
while ((groupRoot != NULL) && (level < GROUP_IMPORT_MAX_LEVEL)) { // for more import
g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
InitImportGroupCfg_(groupRoot);
groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
level++;
}
InitFreeGroupNodes_(g_initWorkspace.groupNodes[NODE_TYPE_GROUPS]);
g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
return 0;
}
InitGroupNode *AddGroupNode(int type, const char *name)
{
INIT_ERROR_CHECK(type <= NODE_TYPE_MAX, return NULL, "Invalid type");
INIT_ERROR_CHECK(name != NULL, return NULL, "Invalid name");
InitGroupNode *groupNode = GetGroupNode(type, name);
if (groupNode != NULL) {
return groupNode;
}
INIT_LOGV("AddGroupNode type %d name %s", type, name);
uint32_t nameLen = (uint32_t)strlen(name);
groupNode = (InitGroupNode *)calloc(1, sizeof(InitGroupNode) + nameLen + 1);
INIT_ERROR_CHECK(groupNode != NULL, return NULL, "Failed to alloc for group %s", name);
int ret = memcpy_s(groupNode->name, nameLen + 1, name, nameLen + 1);
INIT_ERROR_CHECK(ret == 0, free(groupNode);
return NULL, "Failed to alloc for group %s", name);
groupNode->type = type;
groupNode->next = g_initWorkspace.groupNodes[type];
g_initWorkspace.groupNodes[type] = groupNode;
if (type < NODE_TYPE_GROUPS) { // add hashmap
OH_HashMapAdd(g_initWorkspace.hashMap[type], &groupNode->hashNode);
}
return groupNode;
}
InitGroupNode *GetGroupNode(int type, const char *name)
{
if (type >= NODE_TYPE_GROUPS) {
return NULL;
}
HashNode *node = OH_HashMapGet(g_initWorkspace.hashMap[type], name);
if (node == NULL) {
return NULL;
}
return HASHMAP_ENTRY(node, InitGroupNode, hashNode);
}
InitGroupNode *GetNextGroupNode(int type, const InitGroupNode *curr)
{
INIT_ERROR_CHECK(type <= NODE_TYPE_MAX, return NULL, "Invalid type");
if (curr == NULL) {
return g_initWorkspace.groupNodes[type];
}
return curr->next;
}
void DelGroupNode(int type, const char *name)
{
if (type >= NODE_TYPE_GROUPS) {
return;
}
INIT_LOGV("DelGroupNode type %d name %s", type, name);
OH_HashMapRemove(g_initWorkspace.hashMap[type], name);
InitGroupNode *groupNode = g_initWorkspace.groupNodes[type];
InitGroupNode *preNode = groupNode;
while (groupNode != NULL) {
if (strcmp(groupNode->name, name) != 0) {
preNode = groupNode;
groupNode = groupNode->next;
continue;
}
if (groupNode == g_initWorkspace.groupNodes[type]) {
g_initWorkspace.groupNodes[type] = groupNode->next;
} else {
preNode->next = groupNode->next;
}
free(groupNode);
break;
}
}
int CheckNodeValid(int type, const char *name)
{
if (type >= NODE_TYPE_GROUPS) {
return -1;
}
HashNode *node = OH_HashMapGet(g_initWorkspace.hashMap[type], name);
if (node != NULL) {
INIT_LOGV("Found %s in %s group", name, type == NODE_TYPE_JOBS ? "job" : "service");
return 0;
}
if (g_initWorkspace.groupMode == GROUP_BOOT) {
// for boot start, can not start charger service
if (strcmp(name, "charger") == 0) {
return -1;
}
return 0;
}
return -1;
}
HashMapHandle GetGroupHashMap(int type)
{
if (type >= NODE_TYPE_GROUPS) {
return NULL;
}
return g_initWorkspace.hashMap[type];
}
void CloseServiceSpace(void)
{
if (g_initWorkspace.initFlags == 0) {
return;
}
for (size_t i = 0; i < ARRAY_LENGTH(g_initWorkspace.hashMap); i++) {
if (g_initWorkspace.hashMap[i] != NULL) {
HashMapHandle handle = g_initWorkspace.hashMap[i];
g_initWorkspace.hashMap[i] = NULL;
OH_HashMapDestory(handle, NULL);
}
}
g_initWorkspace.initFlags = 0;
}
void ReleaseCmd(PluginCmd *cmd)
{
if (cmd == NULL) {
return;
}
ListNode *node = cmd->cmdExecutor.next;
while (node != &cmd->cmdExecutor) {
PluginCmdExecutor *cmdExec = ListEntry(node, PluginCmdExecutor, node);
OH_ListRemove(&cmdExec->node);
free(cmdExec);
node = cmd->cmdExecutor.next;
}
free(cmd);
}
#ifdef STARTUP_INIT_TEST
InitWorkspace *GetInitWorkspace(void)
{
return &g_initWorkspace;
}
#endif