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