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