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
16 #include <stdbool.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "list.h"
22 #include "beget_ext.h"
23 #include "hookmgr.h"
24
25 // Forward declaration
26 typedef struct tagHOOK_STAGE HOOK_STAGE;
27
28 /*
29 * Internal HOOK Item with priorities
30 */
31 typedef struct tagHOOK_ITEM {
32 ListNode node;
33 HOOK_INFO info;
34 HOOK_STAGE *stage;
35 } HOOK_ITEM;
36
37 /*
38 * Internal HOOK Stage in the same stage
39 */
40 struct tagHOOK_STAGE {
41 ListNode node;
42 int stage;
43 ListNode hooks;
44 };
45
46 /*
47 * HookManager is consist of different hook stages
48 */
49 struct tagHOOK_MGR {
50 const char *name;
51 ListNode stages;
52 };
53
54 /*
55 * Default HookManager is created automatically for HookMgrAddHook
56 */
57 static HOOK_MGR *defaultHookMgr = NULL;
58
getHookMgr(HOOK_MGR * hookMgr,int autoCreate)59 static HOOK_MGR *getHookMgr(HOOK_MGR *hookMgr, int autoCreate)
60 {
61 BEGET_CHECK(hookMgr == NULL, return hookMgr);
62 // Use default HOOK_MGR if possible
63 BEGET_CHECK(defaultHookMgr == NULL, return defaultHookMgr);
64
65 BEGET_CHECK(autoCreate, return NULL);
66
67 // Create default HOOK_MGR if not created
68 defaultHookMgr = HookMgrCreate("default");
69 return defaultHookMgr;
70 }
71
hookStageCompare(ListNode * node,void * data)72 static int hookStageCompare(ListNode *node, void *data)
73 {
74 const HOOK_STAGE *stage;
75 int compareStage = *((int *)data);
76
77 stage = (const HOOK_STAGE *)node;
78 return (stage->stage - compareStage);
79 }
80
hookStageDestroy(ListNode * node)81 static void hookStageDestroy(ListNode *node)
82 {
83 HOOK_STAGE *stage;
84
85 BEGET_CHECK(node != NULL, return);
86
87 stage = (HOOK_STAGE *)node;
88 OH_ListRemoveAll(&(stage->hooks), NULL);
89 free((void *)stage);
90 }
91
92 // Get HOOK_STAGE if found, otherwise create it
getHookStage(HOOK_MGR * hookMgr,int stage,int createIfNotFound)93 static HOOK_STAGE *getHookStage(HOOK_MGR *hookMgr, int stage, int createIfNotFound)
94 {
95 HOOK_STAGE *stageItem;
96
97 stageItem = (HOOK_STAGE *)OH_ListFind(&(hookMgr->stages), (void *)(&stage), hookStageCompare);
98 BEGET_CHECK(stageItem == NULL, return stageItem);
99
100 BEGET_CHECK(createIfNotFound, return NULL);
101
102 // Not found, create it
103 stageItem = (HOOK_STAGE *)malloc(sizeof(HOOK_STAGE));
104 BEGET_CHECK(stageItem != NULL, return NULL);
105 stageItem->stage = stage;
106 OH_ListInit(&(stageItem->hooks));
107 OH_ListAddTail(&(hookMgr->stages), (ListNode *)stageItem);
108 return stageItem;
109 }
110
hookItemCompare(ListNode * node,ListNode * newNode)111 static int hookItemCompare(ListNode *node, ListNode *newNode)
112 {
113 const HOOK_ITEM *hookItem;
114 const HOOK_ITEM *newItem;
115
116 hookItem = (const HOOK_ITEM *)node;
117 newItem = (const HOOK_ITEM *)newNode;
118 return (hookItem->info.prio - newItem->info.prio);
119 }
120
121 struct HOOKITEM_COMPARE_VAL {
122 int prio;
123 OhosHook hook;
124 void *hookCookie;
125 };
126
hookItemCompareValue(ListNode * node,void * data)127 static int hookItemCompareValue(ListNode *node, void *data)
128 {
129 const HOOK_ITEM *hookItem;
130 struct HOOKITEM_COMPARE_VAL *compareVal = (struct HOOKITEM_COMPARE_VAL *)data;
131
132 hookItem = (const HOOK_ITEM *)node;
133 BEGET_CHECK(hookItem->info.prio == compareVal->prio, return (hookItem->info.prio - compareVal->prio));
134 if (hookItem->info.hook == compareVal->hook && hookItem->info.hookCookie == compareVal->hookCookie) {
135 return 0;
136 }
137 return -1;
138 }
139
140 // Add hook to stage list with prio ordered
addHookToStage(HOOK_STAGE * hookStage,int prio,OhosHook hook,void * hookCookie)141 static int addHookToStage(HOOK_STAGE *hookStage, int prio, OhosHook hook, void *hookCookie)
142 {
143 HOOK_ITEM *hookItem;
144 struct HOOKITEM_COMPARE_VAL compareVal;
145
146 // Check if exists
147 compareVal.prio = prio;
148 compareVal.hook = hook;
149 compareVal.hookCookie = hookCookie;
150 hookItem = (HOOK_ITEM *)OH_ListFind(&(hookStage->hooks), (void *)(&compareVal), hookItemCompareValue);
151 BEGET_CHECK(hookItem == NULL, return 0);
152
153 // Create new item
154 hookItem = (HOOK_ITEM *)malloc(sizeof(HOOK_ITEM));
155 BEGET_CHECK(hookItem != NULL, return -1);
156 hookItem->info.stage = hookStage->stage;
157 hookItem->info.prio = prio;
158 hookItem->info.hook = hook;
159 hookItem->info.hookCookie = hookCookie;
160 hookItem->stage = hookStage;
161
162 // Insert with order
163 OH_ListAddWithOrder(&(hookStage->hooks), (ListNode *)hookItem, hookItemCompare);
164 return 0;
165 }
166
HookMgrAddEx(HOOK_MGR * hookMgr,const HOOK_INFO * hookInfo)167 int HookMgrAddEx(HOOK_MGR *hookMgr, const HOOK_INFO *hookInfo)
168 {
169 HOOK_STAGE *stageItem;
170 BEGET_CHECK(hookInfo != NULL, return -1);
171 BEGET_CHECK(hookInfo->hook != NULL, return -1);
172
173 // Get HOOK_MGR
174 hookMgr = getHookMgr(hookMgr, true);
175 BEGET_CHECK(hookMgr != NULL, return -1);
176
177 // Get HOOK_STAGE list
178 stageItem = getHookStage(hookMgr, hookInfo->stage, true);
179 BEGET_CHECK(stageItem != NULL, return -1);
180
181 // Add hook to stage
182 return addHookToStage(stageItem, hookInfo->prio, hookInfo->hook, hookInfo->hookCookie);
183 }
184
HookMgrAdd(HOOK_MGR * hookMgr,int stage,int prio,OhosHook hook)185 int HookMgrAdd(HOOK_MGR *hookMgr, int stage, int prio, OhosHook hook)
186 {
187 HOOK_INFO info;
188 info.stage = stage;
189 info.prio = prio;
190 info.hook = hook;
191 info.hookCookie = NULL;
192 return HookMgrAddEx(hookMgr, &info);
193 }
194
hookTraversalDelProc(ListNode * node,void * cookie)195 static int hookTraversalDelProc(ListNode *node, void *cookie)
196 {
197 HOOK_ITEM *hookItem = (HOOK_ITEM *)node;
198
199 // Not equal, just return
200 BEGET_CHECK((void *)hookItem->info.hook == cookie, return 0);
201
202 // Remove from the list
203 OH_ListRemove(node);
204 // Destroy myself
205 free((void *)node);
206
207 return 0;
208 }
209
210 /*
211 * 删除钩子函数
212 * hook为NULL,表示删除该stage上的所有hooks
213 */
HookMgrDel(HOOK_MGR * hookMgr,int stage,OhosHook hook)214 void HookMgrDel(HOOK_MGR *hookMgr, int stage, OhosHook hook)
215 {
216 HOOK_STAGE *stageItem;
217
218 // Get HOOK_MGR
219 hookMgr = getHookMgr(hookMgr, 0);
220 BEGET_CHECK(hookMgr != NULL, return);
221
222 // Get HOOK_STAGE list
223 stageItem = getHookStage(hookMgr, stage, false);
224 BEGET_CHECK(stageItem != NULL, return);
225
226 if (hook != NULL) {
227 OH_ListTraversal(&(stageItem->hooks), hook, hookTraversalDelProc, 0);
228 return;
229 }
230
231 // Remove from list
232 OH_ListRemove((ListNode *)stageItem);
233
234 // Destroy stage item
235 hookStageDestroy((ListNode *)stageItem);
236 }
237
238 typedef struct tagHOOK_EXECUTION_ARGS {
239 void *executionContext;
240 const HOOK_EXEC_OPTIONS *options;
241 } HOOK_EXECUTION_ARGS;
242
hookExecutionProc(ListNode * node,void * cookie)243 static int hookExecutionProc(ListNode *node, void *cookie)
244 {
245 int ret;
246 HOOK_ITEM *hookItem = (HOOK_ITEM *)node;
247 HOOK_EXECUTION_ARGS *args = (HOOK_EXECUTION_ARGS *)cookie;
248
249 if ((args->options != NULL) && (args->options->preHook != NULL)) {
250 args->options->preHook(&hookItem->info, args->executionContext);
251 }
252 ret = hookItem->info.hook(&hookItem->info, args->executionContext);
253 if ((args->options != NULL) && (args->options->postHook != NULL)) {
254 args->options->postHook(&hookItem->info, args->executionContext, ret);
255 }
256
257 return ret;
258 }
259
260 /*
261 * 执行钩子函数
262 */
HookMgrExecute(HOOK_MGR * hookMgr,int stage,void * executionContext,const HOOK_EXEC_OPTIONS * options)263 int HookMgrExecute(HOOK_MGR *hookMgr, int stage, void *executionContext, const HOOK_EXEC_OPTIONS *options)
264 {
265 unsigned int flags;
266 HOOK_STAGE *stageItem;
267 HOOK_EXECUTION_ARGS args;
268
269 // Get HOOK_MGR
270 hookMgr = getHookMgr(hookMgr, 0);
271 BEGET_CHECK(hookMgr != NULL, return -1)
272
273 // Get HOOK_STAGE list
274 stageItem = getHookStage(hookMgr, stage, false);
275 BEGET_CHECK(stageItem != NULL, return -1);
276
277 flags = 0;
278 if (options != NULL) {
279 flags = (unsigned int)(options->flags);
280 }
281
282 args.executionContext = executionContext;
283 args.options = options;
284
285 // Traversal all hooks in the specified stage
286 return OH_ListTraversal(&(stageItem->hooks), (void *)(&args), hookExecutionProc, flags);
287 }
288
HookMgrCreate(const char * name)289 HOOK_MGR *HookMgrCreate(const char *name)
290 {
291 HOOK_MGR *ret;
292
293 BEGET_CHECK(name != NULL, return NULL);
294 ret = (HOOK_MGR *)malloc(sizeof(HOOK_MGR));
295 BEGET_CHECK(ret != NULL, return NULL);
296
297 ret->name = strdup(name);
298 if (ret->name == NULL) {
299 free((void *)ret);
300 return NULL;
301 }
302 OH_ListInit(&(ret->stages));
303 return ret;
304 }
305
HookMgrDestroy(HOOK_MGR * hookMgr)306 void HookMgrDestroy(HOOK_MGR *hookMgr)
307 {
308 hookMgr = getHookMgr(hookMgr, 0);
309 BEGET_CHECK(hookMgr != NULL, return);
310
311 OH_ListRemoveAll(&(hookMgr->stages), hookStageDestroy);
312
313 if (hookMgr == defaultHookMgr) {
314 defaultHookMgr = NULL;
315 }
316 if (hookMgr->name != NULL) {
317 free((void *)hookMgr->name);
318 }
319 free((void *)hookMgr);
320 }
321
322 typedef struct tagHOOK_TRAVERSAL_ARGS {
323 void *traversalCookie;
324 OhosHookTraversal traversal;
325 } HOOK_TRAVERSAL_ARGS;
326
hookItemTraversal(ListNode * node,void * data)327 static int hookItemTraversal(ListNode *node, void *data)
328 {
329 HOOK_ITEM *hookItem;
330 HOOK_TRAVERSAL_ARGS *stageArgs;
331
332 hookItem = (HOOK_ITEM *)node;
333 stageArgs = (HOOK_TRAVERSAL_ARGS *)data;
334
335 stageArgs->traversal(&(hookItem->info), stageArgs->traversalCookie);
336 return 0;
337 }
338
hookStageTraversal(ListNode * node,void * data)339 static int hookStageTraversal(ListNode *node, void *data)
340 {
341 HOOK_STAGE *stageItem = (HOOK_STAGE *)node;
342 OH_ListTraversal(&(stageItem->hooks), data, hookItemTraversal, 0);
343 return 0;
344 }
345
346 /*
347 * 遍历所有的hooks
348 */
HookMgrTraversal(HOOK_MGR * hookMgr,void * traversalCookie,OhosHookTraversal traversal)349 void HookMgrTraversal(HOOK_MGR *hookMgr, void *traversalCookie, OhosHookTraversal traversal)
350 {
351 HOOK_TRAVERSAL_ARGS stageArgs;
352
353 BEGET_CHECK(traversal != NULL, return);
354
355 hookMgr = getHookMgr(hookMgr, 0);
356 BEGET_CHECK(hookMgr != NULL, return);
357
358 // Prepare common args
359 stageArgs.traversalCookie = traversalCookie;
360 stageArgs.traversal = traversal;
361 OH_ListTraversal(&(hookMgr->stages), (void *)(&stageArgs), hookStageTraversal, 0);
362 }
363
364 /*
365 * 获取指定stage中hooks的个数
366 */
HookMgrGetHooksCnt(HOOK_MGR * hookMgr,int stage)367 int HookMgrGetHooksCnt(HOOK_MGR *hookMgr, int stage)
368 {
369 HOOK_STAGE *stageItem;
370
371 hookMgr = getHookMgr(hookMgr, 0);
372 BEGET_CHECK(hookMgr != NULL, return 0);
373
374 // Get HOOK_STAGE list
375 stageItem = getHookStage(hookMgr, stage, false);
376 BEGET_CHECK(stageItem != NULL, return 0);
377
378 return OH_ListGetCnt(&(stageItem->hooks));
379 }
380
381 /*
382 * 获取指定stage中hooks的个数
383 */
HookMgrGetStagesCnt(HOOK_MGR * hookMgr)384 int HookMgrGetStagesCnt(HOOK_MGR *hookMgr)
385 {
386 hookMgr = getHookMgr(hookMgr, 0);
387 BEGET_CHECK(hookMgr != NULL, return 0);
388
389 return OH_ListGetCnt(&(hookMgr->stages));
390 }
391