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 #include "init_group_manager.h"
16
17 #include "init_jobs_internal.h"
18 #include "init_log.h"
19 #include "init_utils.h"
20 #include "securec.h"
21 #include "init_service_manager.h"
22
23 static InitWorkspace g_initWorkspace = {0, 0, {0}, {0}, {0}};
GenerateHashCode(const char * key)24 int GenerateHashCode(const char *key)
25 {
26 int code = 0;
27 size_t keyLen = strlen(key);
28 for (size_t i = 0; i < keyLen; i++) {
29 code += key[i] - 'A';
30 }
31 return code;
32 }
33
GetBootGroupMode(void)34 static int GetBootGroupMode(void)
35 {
36 static const char *groupModes[] = {
37 "device.boot.group",
38 "device.charge.group"
39 };
40 for (size_t i = 0; i < ARRAY_LENGTH(groupModes); i++) {
41 if (strcmp(g_initWorkspace.groupModeStr, groupModes[i]) == 0) {
42 return i;
43 }
44 }
45 return (int)GROUP_UNKNOW;
46 }
47
ParseGroupCfgItem(cJSON * root,int type,const char * itemName)48 static int ParseGroupCfgItem(cJSON *root, int type, const char *itemName)
49 {
50 int itemNumber = 0;
51 cJSON *json = GetArrayItem(root, &itemNumber, itemName);
52 if (json == NULL) {
53 return 0;
54 }
55
56 for (int i = 0; i < itemNumber; ++i) {
57 cJSON *item = cJSON_GetArrayItem(json, i);
58 char *strValue = cJSON_GetStringValue(item);
59 if (strValue != NULL) {
60 AddGroupNode(type, strValue);
61 }
62 }
63 return 0;
64 }
65
InitParseGroupCfg_(const char * groupCfg)66 static int InitParseGroupCfg_(const char *groupCfg)
67 {
68 INIT_LOGI("Parse group config %s", groupCfg);
69 char *fileBuf = ReadFileData(groupCfg);
70 INIT_ERROR_CHECK(fileBuf != NULL, return -1, "Failed to read file content %s", groupCfg);
71 cJSON *fileRoot = cJSON_Parse(fileBuf);
72 INIT_ERROR_CHECK(fileRoot != NULL, free(fileBuf);
73 return -1, "Failed to parse json file %s", groupCfg);
74
75 ParseGroupCfgItem(fileRoot, NODE_TYPE_JOBS, "jobs");
76 ParseGroupCfgItem(fileRoot, NODE_TYPE_SERVICES, "services");
77 ParseGroupCfgItem(fileRoot, NODE_TYPE_GROUPS, "groups");
78 cJSON_Delete(fileRoot);
79 free(fileBuf);
80 return 0;
81 }
82
InitImportGroupCfg_(InitGroupNode * groupRoot)83 static int InitImportGroupCfg_(InitGroupNode *groupRoot)
84 {
85 InitGroupNode *groupNode = groupRoot;
86 while (groupNode != NULL) {
87 groupRoot = groupNode->next;
88 InitParseGroupCfg_(groupNode->name);
89 free(groupNode);
90 groupNode = groupRoot;
91 }
92 return 0;
93 }
94
InitFreeGroupNodes_(InitGroupNode * groupRoot)95 static int InitFreeGroupNodes_(InitGroupNode *groupRoot)
96 {
97 InitGroupNode *groupNode = groupRoot;
98 while (groupNode != NULL) {
99 groupRoot = groupNode->next;
100 if (groupNode->type < NODE_TYPE_GROUPS) { // remove from hashmap
101 OH_HashMapRemove(g_initWorkspace.hashMap[groupNode->type], groupNode->name);
102 }
103 free(groupNode);
104 groupNode = groupRoot;
105 }
106 return 0;
107 }
108
GetAbsolutePath(const char * path,const char * cfgName,char * buffer,uint32_t buffSize)109 static char *GetAbsolutePath(const char *path, const char *cfgName, char *buffer, uint32_t buffSize)
110 {
111 int len = 0;
112 size_t cfgNameLen = strlen(cfgName);
113 int ext = 0;
114 if (cfgNameLen > strlen(".cfg")) {
115 ext = strcmp(cfgName + cfgNameLen - strlen(".cfg"), ".cfg") == 0;
116 }
117 if (cfgName[0] != '/') {
118 const char *format = ((ext != 0) ? "%s/%s" : "%s/%s.cfg");
119 len = sprintf_s(buffer, buffSize, format, path, cfgName);
120 } else {
121 const char *format = ((ext != 0) ? "%s" : "%s.cfg");
122 len = sprintf_s(buffer, buffSize, format, cfgName);
123 }
124 if (len <= 0) {
125 return NULL;
126 }
127 buffer[len] = '\0';
128 return buffer;
129 }
130
GroupNodeNodeCompare(const HashNode * node1,const HashNode * node2)131 static int GroupNodeNodeCompare(const HashNode *node1, const HashNode *node2)
132 {
133 InitGroupNode *groupNode1 = HASHMAP_ENTRY(node1, InitGroupNode, hashNode);
134 InitGroupNode *groupNode2 = HASHMAP_ENTRY(node2, InitGroupNode, hashNode);
135 return strcmp(groupNode1->name, groupNode2->name);
136 }
137
GroupNodeKeyCompare(const HashNode * node1,const void * key)138 static int GroupNodeKeyCompare(const HashNode *node1, const void *key)
139 {
140 InitGroupNode *groupNode1 = HASHMAP_ENTRY(node1, InitGroupNode, hashNode);
141 return strcmp(groupNode1->name, (char *)key);
142 }
143
GroupNodeGetKeyHashCode(const void * key)144 static int GroupNodeGetKeyHashCode(const void *key)
145 {
146 return GenerateHashCode((const char *)key);
147 }
148
GroupNodeGetNodeHashCode(const HashNode * node)149 static int GroupNodeGetNodeHashCode(const HashNode *node)
150 {
151 InitGroupNode *groupNode = HASHMAP_ENTRY(node, InitGroupNode, hashNode);
152 return GenerateHashCode((const char *)groupNode->name);
153 }
154
GroupNodeFree(const HashNode * node,void * context)155 static void GroupNodeFree(const HashNode *node, void *context)
156 {
157 InitGroupNode *groupNode = HASHMAP_ENTRY(node, InitGroupNode, hashNode);
158 if (groupNode->type == NODE_TYPE_SERVICES) {
159 ReleaseService(groupNode->data.service);
160 groupNode->data.service = NULL;
161 } else if (groupNode->type == NODE_TYPE_CMDS) {
162 ReleaseCmd(groupNode->data.cmd);
163 groupNode->data.cmd = NULL;
164 }
165 free(groupNode);
166 }
167
InitServiceSpace(void)168 void InitServiceSpace(void)
169 {
170 if (g_initWorkspace.initFlags != 0) {
171 return;
172 }
173 HashInfo info = {
174 GroupNodeNodeCompare,
175 GroupNodeKeyCompare,
176 GroupNodeGetNodeHashCode,
177 GroupNodeGetKeyHashCode,
178 GroupNodeFree,
179 GROUP_HASHMAP_BUCKET
180 };
181 for (size_t i = 0; i < ARRAY_LENGTH(g_initWorkspace.hashMap); i++) {
182 int ret = OH_HashMapCreate(&g_initWorkspace.hashMap[i], &info);
183 if (ret != 0) {
184 INIT_LOGE("%s", "Failed to create hash map");
185 }
186 }
187
188 for (int i = 0; i < NODE_TYPE_MAX; i++) {
189 g_initWorkspace.groupNodes[i] = NULL;
190 }
191 // get boot mode, set default mode
192 strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), BOOT_GROUP_DEFAULT);
193 int ret = GetParameterFromCmdLine(BOOT_GROUP_NAME,
194 g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr));
195 if (ret != 0) {
196 INIT_LOGV("Failed to get boot group");
197 if (GetBootModeFromMisc() == GROUP_CHARGE) {
198 strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), "device.charge.group");
199 }
200 }
201 INIT_LOGI("boot start %s", g_initWorkspace.groupModeStr);
202 g_initWorkspace.groupMode = GetBootGroupMode();
203 g_initWorkspace.initFlags = 1;
204 }
205
InitParseGroupCfg(void)206 int InitParseGroupCfg(void)
207 {
208 char buffer[128] = {0}; // 128 buffer size
209 char *realPath = GetAbsolutePath(GROUP_DEFAULT_PATH,
210 g_initWorkspace.groupModeStr, buffer, sizeof(buffer));
211 INIT_ERROR_CHECK(realPath != NULL, return -1,
212 "Failed to get path for %s", g_initWorkspace.groupModeStr);
213 InitParseGroupCfg_(realPath);
214 InitGroupNode *groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
215 int level = 0;
216 while ((groupRoot != NULL) && (level < GROUP_IMPORT_MAX_LEVEL)) { // for more import
217 g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
218 InitImportGroupCfg_(groupRoot);
219 groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
220 level++;
221 }
222 InitFreeGroupNodes_(g_initWorkspace.groupNodes[NODE_TYPE_GROUPS]);
223 g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
224 return 0;
225 }
226
AddGroupNode(int type,const char * name)227 InitGroupNode *AddGroupNode(int type, const char *name)
228 {
229 INIT_ERROR_CHECK(type <= NODE_TYPE_MAX, return NULL, "Invalid type");
230 INIT_ERROR_CHECK(name != NULL, return NULL, "Invalid name");
231 InitGroupNode *groupNode = GetGroupNode(type, name);
232 if (groupNode != NULL) {
233 return groupNode;
234 }
235 INIT_LOGV("AddGroupNode type %d name %s", type, name);
236 uint32_t nameLen = (uint32_t)strlen(name);
237 groupNode = (InitGroupNode *)calloc(1, sizeof(InitGroupNode) + nameLen + 1);
238 INIT_ERROR_CHECK(groupNode != NULL, return NULL, "Failed to alloc for group %s", name);
239 int ret = memcpy_s(groupNode->name, nameLen + 1, name, nameLen + 1);
240 INIT_ERROR_CHECK(ret == 0, free(groupNode);
241 return NULL, "Failed to alloc for group %s", name);
242 groupNode->type = type;
243 groupNode->next = g_initWorkspace.groupNodes[type];
244 g_initWorkspace.groupNodes[type] = groupNode;
245
246 if (type < NODE_TYPE_GROUPS) { // add hashmap
247 OH_HashMapAdd(g_initWorkspace.hashMap[type], &groupNode->hashNode);
248 }
249 return groupNode;
250 }
251
GetGroupNode(int type,const char * name)252 InitGroupNode *GetGroupNode(int type, const char *name)
253 {
254 if (type >= NODE_TYPE_GROUPS) {
255 return NULL;
256 }
257 HashNode *node = OH_HashMapGet(g_initWorkspace.hashMap[type], name);
258 if (node == NULL) {
259 return NULL;
260 }
261 return HASHMAP_ENTRY(node, InitGroupNode, hashNode);
262 }
263
GetNextGroupNode(int type,const InitGroupNode * curr)264 InitGroupNode *GetNextGroupNode(int type, const InitGroupNode *curr)
265 {
266 INIT_ERROR_CHECK(type <= NODE_TYPE_MAX, return NULL, "Invalid type");
267 if (curr == NULL) {
268 return g_initWorkspace.groupNodes[type];
269 }
270 return curr->next;
271 }
272
DelGroupNode(int type,const char * name)273 void DelGroupNode(int type, const char *name)
274 {
275 if (type >= NODE_TYPE_GROUPS) {
276 return;
277 }
278 INIT_LOGV("DelGroupNode type %d name %s", type, name);
279 OH_HashMapRemove(g_initWorkspace.hashMap[type], name);
280 InitGroupNode *groupNode = g_initWorkspace.groupNodes[type];
281 InitGroupNode *preNode = groupNode;
282 while (groupNode != NULL) {
283 if (strcmp(groupNode->name, name) != 0) {
284 preNode = groupNode;
285 groupNode = groupNode->next;
286 continue;
287 }
288 if (groupNode == g_initWorkspace.groupNodes[type]) {
289 g_initWorkspace.groupNodes[type] = groupNode->next;
290 } else {
291 preNode->next = groupNode->next;
292 }
293 free(groupNode);
294 break;
295 }
296 }
297
CheckNodeValid(int type,const char * name)298 int CheckNodeValid(int type, const char *name)
299 {
300 if (type >= NODE_TYPE_GROUPS) {
301 return -1;
302 }
303 HashNode *node = OH_HashMapGet(g_initWorkspace.hashMap[type], name);
304 if (node != NULL) {
305 INIT_LOGV("Found %s in %s group", name, type == NODE_TYPE_JOBS ? "job" : "service");
306 return 0;
307 }
308 if (g_initWorkspace.groupMode == GROUP_BOOT) {
309 // for boot start, can not start charger service
310 if (strcmp(name, "charger") == 0) {
311 return -1;
312 }
313 return 0;
314 }
315 return -1;
316 }
317
GetGroupHashMap(int type)318 HashMapHandle GetGroupHashMap(int type)
319 {
320 if (type >= NODE_TYPE_GROUPS) {
321 return NULL;
322 }
323 return g_initWorkspace.hashMap[type];
324 }
325
CloseServiceSpace(void)326 void CloseServiceSpace(void)
327 {
328 if (g_initWorkspace.initFlags == 0) {
329 return;
330 }
331 for (size_t i = 0; i < ARRAY_LENGTH(g_initWorkspace.hashMap); i++) {
332 if (g_initWorkspace.hashMap[i] != NULL) {
333 HashMapHandle handle = g_initWorkspace.hashMap[i];
334 g_initWorkspace.hashMap[i] = NULL;
335 OH_HashMapDestory(handle, NULL);
336 }
337 }
338 g_initWorkspace.initFlags = 0;
339 }
340
ReleaseCmd(PluginCmd * cmd)341 void ReleaseCmd(PluginCmd *cmd)
342 {
343 if (cmd == NULL) {
344 return;
345 }
346 ListNode *node = cmd->cmdExecutor.next;
347 while (node != &cmd->cmdExecutor) {
348 PluginCmdExecutor *cmdExec = ListEntry(node, PluginCmdExecutor, node);
349 OH_ListRemove(&cmdExec->node);
350 free(cmdExec);
351 node = cmd->cmdExecutor.next;
352 }
353 free(cmd);
354 }
355
356 #ifdef STARTUP_INIT_TEST
GetInitWorkspace(void)357 InitWorkspace *GetInitWorkspace(void)
358 {
359 return &g_initWorkspace;
360 }
361 #endif