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)155 static void GroupNodeFree(const HashNode *node)
156 {
157 InitGroupNode *groupNode = HASHMAP_ENTRY(node, InitGroupNode, hashNode);
158 free(groupNode);
159 }
160
InitServiceSpace(void)161 void InitServiceSpace(void)
162 {
163 if (g_initWorkspace.initFlags != 0) {
164 return;
165 }
166 HashInfo info = {
167 GroupNodeNodeCompare,
168 GroupNodeKeyCompare,
169 GroupNodeGetNodeHashCode,
170 GroupNodeGetKeyHashCode,
171 GroupNodeFree,
172 GROUP_HASHMAP_BUCKET
173 };
174 for (size_t i = 0; i < ARRAY_LENGTH(g_initWorkspace.hashMap); i++) {
175 int ret = OH_HashMapCreate(&g_initWorkspace.hashMap[i], &info);
176 if (ret != 0) {
177 INIT_LOGE("%s", "Failed to create hash map");
178 }
179 }
180
181 for (int i = 0; i < NODE_TYPE_MAX; i++) {
182 g_initWorkspace.groupNodes[i] = NULL;
183 }
184 // get boot mode, set default mode
185 strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), BOOT_GROUP_DEFAULT);
186 char *data = ReadFileData(BOOT_CMD_LINE);
187 if (data != NULL) {
188 int ret = GetProcCmdlineValue(BOOT_GROUP_NAME, data,
189 g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr));
190 if (ret != 0) {
191 INIT_LOGV("Failed to get boot group");
192 if (GetBootModeFromMisc() == GROUP_CHARGE) {
193 strcpy_s(g_initWorkspace.groupModeStr, sizeof(g_initWorkspace.groupModeStr), "device.charge.group");
194 }
195 }
196 free(data);
197 }
198 INIT_LOGI("boot start %s", g_initWorkspace.groupModeStr);
199 g_initWorkspace.groupMode = GetBootGroupMode();
200 g_initWorkspace.initFlags = 1;
201 }
202
InitParseGroupCfg(void)203 int InitParseGroupCfg(void)
204 {
205 char buffer[128] = {0}; // 128 buffer size
206 char *realPath = GetAbsolutePath(GROUP_DEFAULT_PATH,
207 g_initWorkspace.groupModeStr, buffer, sizeof(buffer));
208 INIT_ERROR_CHECK(realPath != NULL, return -1,
209 "Failed to get path for %s", g_initWorkspace.groupModeStr);
210 InitParseGroupCfg_(realPath);
211 InitGroupNode *groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
212 int level = 0;
213 while ((groupRoot != NULL) && (level < GROUP_IMPORT_MAX_LEVEL)) { // for more import
214 g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
215 InitImportGroupCfg_(groupRoot);
216 groupRoot = g_initWorkspace.groupNodes[NODE_TYPE_GROUPS];
217 level++;
218 }
219 InitFreeGroupNodes_(g_initWorkspace.groupNodes[NODE_TYPE_GROUPS]);
220 g_initWorkspace.groupNodes[NODE_TYPE_GROUPS] = NULL;
221 return 0;
222 }
223
AddGroupNode(int type,const char * name)224 InitGroupNode *AddGroupNode(int type, const char *name)
225 {
226 INIT_ERROR_CHECK(type <= NODE_TYPE_MAX, return NULL, "Invalid type");
227 INIT_ERROR_CHECK(name != NULL, return NULL, "Invalid name");
228 InitGroupNode *groupNode = GetGroupNode(type, name);
229 if (groupNode != NULL) {
230 return groupNode;
231 }
232 INIT_LOGV("AddGroupNode type %d name %s", type, name);
233 uint32_t nameLen = (uint32_t)strlen(name);
234 groupNode = (InitGroupNode *)calloc(1, sizeof(InitGroupNode) + nameLen + 1);
235 INIT_ERROR_CHECK(groupNode != NULL, return NULL, "Failed to alloc for group %s", name);
236 int ret = memcpy_s(groupNode->name, nameLen + 1, name, nameLen + 1);
237 INIT_ERROR_CHECK(ret == 0, free(groupNode);
238 return NULL, "Failed to alloc for group %s", name);
239 groupNode->type = type;
240 groupNode->next = g_initWorkspace.groupNodes[type];
241 g_initWorkspace.groupNodes[type] = groupNode;
242
243 if (type < NODE_TYPE_GROUPS) { // add hashmap
244 OH_HashMapAdd(g_initWorkspace.hashMap[type], &groupNode->hashNode);
245 }
246 return groupNode;
247 }
248
GetGroupNode(int type,const char * name)249 InitGroupNode *GetGroupNode(int type, const char *name)
250 {
251 if (type >= NODE_TYPE_GROUPS) {
252 return NULL;
253 }
254 INIT_LOGV("GetGroupNode type %d name %s", type, name);
255 HashNode *node = OH_HashMapGet(g_initWorkspace.hashMap[type], name);
256 if (node == NULL) {
257 return NULL;
258 }
259 return HASHMAP_ENTRY(node, InitGroupNode, hashNode);
260 }
261
GetNextGroupNode(int type,const InitGroupNode * curr)262 InitGroupNode *GetNextGroupNode(int type, const InitGroupNode *curr)
263 {
264 INIT_ERROR_CHECK(type <= NODE_TYPE_MAX, return NULL, "Invalid type");
265 if (curr == NULL) {
266 return g_initWorkspace.groupNodes[type];
267 }
268 return curr->next;
269 }
270
DelGroupNode(int type,const char * name)271 void DelGroupNode(int type, const char *name)
272 {
273 if (type >= NODE_TYPE_GROUPS) {
274 return;
275 }
276 INIT_LOGV("DelGroupNode type %d name %s", type, name);
277 OH_HashMapRemove(g_initWorkspace.hashMap[type], name);
278 InitGroupNode *groupNode = g_initWorkspace.groupNodes[type];
279 InitGroupNode *preNode = groupNode;
280 while (groupNode != NULL) {
281 if (strcmp(groupNode->name, name) != 0) {
282 preNode = groupNode;
283 groupNode = groupNode->next;
284 continue;
285 }
286 if (groupNode == g_initWorkspace.groupNodes[type]) {
287 g_initWorkspace.groupNodes[type] = groupNode->next;
288 } else {
289 preNode->next = groupNode->next;
290 }
291 free(groupNode);
292 break;
293 }
294 }
295
CheckNodeValid(int type,const char * name)296 int CheckNodeValid(int type, const char *name)
297 {
298 if (type >= NODE_TYPE_GROUPS) {
299 return -1;
300 }
301 HashNode *node = OH_HashMapGet(g_initWorkspace.hashMap[type], name);
302 if (node != NULL) {
303 INIT_LOGI("Found %s in %s group", name, type == NODE_TYPE_JOBS ? "job" : "service");
304 return 0;
305 }
306 if (g_initWorkspace.groupMode == GROUP_BOOT) {
307 // for boot start, can not start charger service
308 if (strcmp(name, "charger") == 0) {
309 return -1;
310 }
311 return 0;
312 }
313 return -1;
314 }
315
GetGroupHashMap(int type)316 HashMapHandle GetGroupHashMap(int type)
317 {
318 if (type >= NODE_TYPE_GROUPS) {
319 return NULL;
320 }
321 return g_initWorkspace.hashMap[type];
322 }
323
324 #ifdef STARTUP_INIT_TEST
GetInitWorkspace(void)325 InitWorkspace *GetInitWorkspace(void)
326 {
327 return &g_initWorkspace;
328 }
329 #endif