1 /*
2 * Copyright (c) 2024 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 "appspawn_modulemgr.h"
17
18 #include "appspawn_hook.h"
19 #include "appspawn_manager.h"
20 #include "appspawn_utils.h"
21 #include "hookmgr.h"
22 #include "modulemgr.h"
23
24 typedef struct {
25 const AppSpawnContent *content;
26 const AppSpawnedProcessInfo *appInfo;
27 } AppSpawnAppArg;
28
29 static struct {
30 MODULE_MGR *moduleMgr;
31 AppSpawnModuleType type;
32 const char *moduleName;
33 } g_moduleMgr[MODULE_MAX] = {
34 {NULL, MODULE_DEFAULT, "appspawn"},
35 {NULL, MODULE_APPSPAWN, "appspawn/appspawn"},
36 {NULL, MODULE_NWEBSPAWN, "appspawn/nwebspawn"},
37 {NULL, MODULE_COMMON, "appspawn/common"},
38 };
39 static HOOK_MGR *g_appspawnHookMgr = NULL;
40
AppSpawnModuleMgrInstall(const char * moduleName)41 int AppSpawnModuleMgrInstall(const char *moduleName)
42 {
43 if (moduleName == NULL) {
44 return -1;
45 }
46 int type = MODULE_DEFAULT;
47 if (g_moduleMgr[type].moduleMgr == NULL) {
48 g_moduleMgr[type].moduleMgr = ModuleMgrCreate(g_moduleMgr[type].moduleName);
49 }
50 if (g_moduleMgr[type].moduleMgr == NULL) {
51 return -1;
52 }
53 #ifndef APPSPAWN_TEST
54 return ModuleMgrInstall(g_moduleMgr[type].moduleMgr, moduleName, 0, NULL);
55 #else
56 return 0;
57 #endif
58 }
59
AppSpawnModuleMgrUnInstall(int type)60 void AppSpawnModuleMgrUnInstall(int type)
61 {
62 if (type >= MODULE_MAX) {
63 return;
64 }
65 if (g_moduleMgr[type].moduleMgr == NULL) {
66 return;
67 }
68 ModuleMgrDestroy(g_moduleMgr[type].moduleMgr);
69 g_moduleMgr[type].moduleMgr = NULL;
70 }
71
AppSpawnLoadAutoRunModules(int type)72 int AppSpawnLoadAutoRunModules(int type)
73 {
74 if (type >= MODULE_MAX) {
75 return -1;
76 }
77 if (g_moduleMgr[type].moduleMgr != NULL) {
78 return 0;
79 }
80 APPSPAWN_LOGI("AppSpawnLoadAutoRunModules: %{public}d moduleName: %{public}s", type, g_moduleMgr[type].moduleName);
81 #ifndef APPSPAWN_TEST
82 g_moduleMgr[type].moduleMgr = ModuleMgrScan(g_moduleMgr[type].moduleName);
83 return g_moduleMgr[type].moduleMgr == NULL ? -1 : 0;
84 #else
85 return 0;
86 #endif
87 }
88
GetAppSpawnHookMgr(void)89 HOOK_MGR *GetAppSpawnHookMgr(void)
90 {
91 if (g_appspawnHookMgr != NULL) {
92 return g_appspawnHookMgr;
93 }
94 g_appspawnHookMgr = HookMgrCreate("appspawn");
95 return g_appspawnHookMgr;
96 }
97
DeleteAppSpawnHookMgr(void)98 void DeleteAppSpawnHookMgr(void)
99 {
100 HookMgrDestroy(g_appspawnHookMgr);
101 g_appspawnHookMgr = NULL;
102 }
103
ServerStageHookRun(const HOOK_INFO * hookInfo,void * executionContext)104 static int ServerStageHookRun(const HOOK_INFO *hookInfo, void *executionContext)
105 {
106 AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
107 ServerStageHook realHook = (ServerStageHook)hookInfo->hookCookie;
108 return realHook((void *)arg->content);
109 }
110
PreHookExec(const HOOK_INFO * hookInfo,void * executionContext)111 static void PreHookExec(const HOOK_INFO *hookInfo, void *executionContext)
112 {
113 AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
114 AppSpawnMgr *spawnMgr = (AppSpawnMgr *)arg->content;
115 clock_gettime(CLOCK_MONOTONIC, &spawnMgr->perLoadStart);
116 APPSPAWN_LOGI("Hook stage: %{public}d prio: %{public}d start", hookInfo->stage, hookInfo->prio);
117 }
118
PostHookExec(const HOOK_INFO * hookInfo,void * executionContext,int executionRetVal)119 static void PostHookExec(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
120 {
121 AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
122 AppSpawnMgr *spawnMgr = (AppSpawnMgr *)arg->content;
123 clock_gettime(CLOCK_MONOTONIC, &spawnMgr->perLoadEnd);
124 uint64_t diff = DiffTime(&spawnMgr->perLoadStart, &spawnMgr->perLoadEnd);
125 APPSPAWN_LOGI("Hook stage: %{public}d prio: %{public}d end time %{public}" PRId64 " ns result: %{public}d",
126 hookInfo->stage, hookInfo->prio, diff, executionRetVal);
127 }
128
ServerStageHookExecute(AppSpawnHookStage stage,AppSpawnContent * content)129 int ServerStageHookExecute(AppSpawnHookStage stage, AppSpawnContent *content)
130 {
131 APPSPAWN_CHECK(content != NULL, return APPSPAWN_ARG_INVALID, "Invalid content");
132 APPSPAWN_CHECK((stage >= STAGE_SERVER_PRELOAD) && (stage <= STAGE_SERVER_EXIT),
133 return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
134 AppSpawnHookArg arg;
135 arg.content = content;
136 arg.client = NULL;
137 HOOK_EXEC_OPTIONS options;
138 options.flags = TRAVERSE_STOP_WHEN_ERROR;
139 options.preHook = PreHookExec;
140 options.postHook = PostHookExec;
141 int ret = HookMgrExecute(GetAppSpawnHookMgr(), stage, (void *)(&arg), &options);
142 APPSPAWN_LOGV("Execute hook [%{public}d] result %{public}d", stage, ret);
143 return ret == ERR_NO_HOOK_STAGE ? 0 : ret;
144 }
145
AddServerStageHook(AppSpawnHookStage stage,int prio,ServerStageHook hook)146 int AddServerStageHook(AppSpawnHookStage stage, int prio, ServerStageHook hook)
147 {
148 APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
149 APPSPAWN_CHECK((stage >= STAGE_SERVER_PRELOAD) && (stage <= STAGE_SERVER_EXIT),
150 return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
151 HOOK_INFO info;
152 info.stage = stage;
153 info.prio = prio;
154 info.hook = ServerStageHookRun;
155 info.hookCookie = (void *)hook;
156 APPSPAWN_LOGI("AddServerStageHook prio: %{public}d", prio);
157 return HookMgrAddEx(GetAppSpawnHookMgr(), &info);
158 }
159
AppSpawnHookRun(const HOOK_INFO * hookInfo,void * executionContext)160 static int AppSpawnHookRun(const HOOK_INFO *hookInfo, void *executionContext)
161 {
162 AppSpawnForkArg *arg = (AppSpawnForkArg *)executionContext;
163 AppSpawnHook realHook = (AppSpawnHook)hookInfo->hookCookie;
164 return realHook((AppSpawnMgr *)arg->content, (AppSpawningCtx *)arg->client);
165 }
166
PreAppSpawnHookExec(const HOOK_INFO * hookInfo,void * executionContext)167 static void PreAppSpawnHookExec(const HOOK_INFO *hookInfo, void *executionContext)
168 {
169 AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
170 clock_gettime(CLOCK_MONOTONIC, &arg->tmStart);
171 APPSPAWN_LOGV("Hook stage: %{public}d prio: %{public}d start", hookInfo->stage, hookInfo->prio);
172 }
173
PostAppSpawnHookExec(const HOOK_INFO * hookInfo,void * executionContext,int executionRetVal)174 static void PostAppSpawnHookExec(const HOOK_INFO *hookInfo, void *executionContext, int executionRetVal)
175 {
176 AppSpawnHookArg *arg = (AppSpawnHookArg *)executionContext;
177 clock_gettime(CLOCK_MONOTONIC, &arg->tmEnd);
178 uint64_t diff = DiffTime(&arg->tmStart, &arg->tmEnd);
179 APPSPAWN_LOGV("Hook stage: %{public}d prio: %{public}d end time %{public}" PRId64 " ns result: %{public}d",
180 hookInfo->stage, hookInfo->prio, diff, executionRetVal);
181 }
182
AppSpawnHookExecute(AppSpawnHookStage stage,uint32_t flags,AppSpawnContent * content,AppSpawnClient * client)183 int AppSpawnHookExecute(AppSpawnHookStage stage, uint32_t flags, AppSpawnContent *content, AppSpawnClient *client)
184 {
185 APPSPAWN_CHECK(content != NULL && client != NULL, return APPSPAWN_ARG_INVALID, "Invalid arg");
186 APPSPAWN_LOGV("Execute hook [%{public}d] for app: %{public}s", stage, GetProcessName((AppSpawningCtx *)client));
187 APPSPAWN_CHECK((stage >= STAGE_PARENT_PRE_FORK) && (stage <= STAGE_CHILD_PRE_RUN),
188 return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
189 AppSpawnHookArg forkArg;
190 forkArg.client = client;
191 forkArg.content = content;
192 HOOK_EXEC_OPTIONS options;
193 options.flags = flags; // TRAVERSE_STOP_WHEN_ERROR : 0;
194 options.preHook = PreAppSpawnHookExec;
195 options.postHook = PostAppSpawnHookExec;
196 int ret = HookMgrExecute(GetAppSpawnHookMgr(), stage, (void *)(&forkArg), &options);
197 ret = (ret == ERR_NO_HOOK_STAGE) ? 0 : ret;
198 if (ret != 0) {
199 APPSPAWN_LOGE("Execute hook [%{public}d] result %{public}d", stage, ret);
200 }
201 return ret;
202 }
203
AppSpawnExecuteClearEnvHook(AppSpawnContent * content,AppSpawnClient * client)204 int AppSpawnExecuteClearEnvHook(AppSpawnContent *content, AppSpawnClient *client)
205 {
206 return AppSpawnHookExecute(STAGE_CHILD_PRE_COLDBOOT, HOOK_STOP_WHEN_ERROR, content, client);
207 }
208
AppSpawnExecuteSpawningHook(AppSpawnContent * content,AppSpawnClient * client)209 int AppSpawnExecuteSpawningHook(AppSpawnContent *content, AppSpawnClient *client)
210 {
211 return AppSpawnHookExecute(STAGE_CHILD_EXECUTE, HOOK_STOP_WHEN_ERROR, content, client);
212 }
213
AppSpawnExecutePostReplyHook(AppSpawnContent * content,AppSpawnClient * client)214 int AppSpawnExecutePostReplyHook(AppSpawnContent *content, AppSpawnClient *client)
215 {
216 return AppSpawnHookExecute(STAGE_CHILD_POST_RELY, HOOK_STOP_WHEN_ERROR, content, client);
217 }
218
AppSpawnExecutePreReplyHook(AppSpawnContent * content,AppSpawnClient * client)219 int AppSpawnExecutePreReplyHook(AppSpawnContent *content, AppSpawnClient *client)
220 {
221 return AppSpawnHookExecute(STAGE_CHILD_PRE_RELY, HOOK_STOP_WHEN_ERROR, content, client);
222 }
223
AppSpawnEnvClear(AppSpawnContent * content,AppSpawnClient * client)224 void AppSpawnEnvClear(AppSpawnContent *content, AppSpawnClient *client)
225 {
226 (void)AppSpawnHookExecute(STAGE_CHILD_PRE_RUN, 0, content, client);
227 }
228
AddAppSpawnHook(AppSpawnHookStage stage,int prio,AppSpawnHook hook)229 int AddAppSpawnHook(AppSpawnHookStage stage, int prio, AppSpawnHook hook)
230 {
231 APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
232 APPSPAWN_CHECK((stage >= STAGE_PARENT_PRE_FORK) && (stage <= STAGE_CHILD_PRE_RUN),
233 return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
234 HOOK_INFO info;
235 info.stage = stage;
236 info.prio = prio;
237 info.hook = AppSpawnHookRun;
238 info.hookCookie = (void *)hook;
239 APPSPAWN_LOGI("AddAppSpawnHook stage: %{public}d prio: %{public}d", stage, prio);
240 return HookMgrAddEx(GetAppSpawnHookMgr(), &info);
241 }
242
ProcessMgrHookExecute(AppSpawnHookStage stage,const AppSpawnContent * content,const AppSpawnedProcessInfo * appInfo)243 int ProcessMgrHookExecute(AppSpawnHookStage stage, const AppSpawnContent *content,
244 const AppSpawnedProcessInfo *appInfo)
245 {
246 APPSPAWN_CHECK(content != NULL && appInfo != NULL,
247 return APPSPAWN_ARG_INVALID, "Invalid hook");
248 APPSPAWN_CHECK((stage >= STAGE_SERVER_APP_ADD) && (stage <= STAGE_SERVER_APP_DIED),
249 return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
250
251 AppSpawnAppArg arg;
252 arg.appInfo = appInfo;
253 arg.content = content;
254 int ret = HookMgrExecute(GetAppSpawnHookMgr(), stage, (void *)(&arg), NULL);
255 return ret == ERR_NO_HOOK_STAGE ? 0 : ret;
256 }
257
ProcessMgrHookRun(const HOOK_INFO * hookInfo,void * executionContext)258 static int ProcessMgrHookRun(const HOOK_INFO *hookInfo, void *executionContext)
259 {
260 AppSpawnAppArg *arg = (AppSpawnAppArg *)executionContext;
261 ProcessChangeHook realHook = (ProcessChangeHook)hookInfo->hookCookie;
262 return realHook((AppSpawnMgr *)arg->content, arg->appInfo);
263 }
264
AddProcessMgrHook(AppSpawnHookStage stage,int prio,ProcessChangeHook hook)265 int AddProcessMgrHook(AppSpawnHookStage stage, int prio, ProcessChangeHook hook)
266 {
267 APPSPAWN_CHECK(hook != NULL, return APPSPAWN_ARG_INVALID, "Invalid hook");
268 APPSPAWN_CHECK((stage >= STAGE_SERVER_APP_ADD) && (stage <= STAGE_SERVER_APP_DIED),
269 return APPSPAWN_ARG_INVALID, "Invalid stage %{public}d", (int)stage);
270 HOOK_INFO info;
271 info.stage = stage;
272 info.prio = prio;
273 info.hook = ProcessMgrHookRun;
274 info.hookCookie = hook;
275 return HookMgrAddEx(GetAppSpawnHookMgr(), &info);
276 }
277
RegChildLooper(struct AppSpawnContent * content,ChildLoop loop)278 void RegChildLooper(struct AppSpawnContent *content, ChildLoop loop)
279 {
280 APPSPAWN_CHECK(content != NULL && loop != NULL, return, "Invalid content for RegChildLooper");
281 content->runChildProcessor = loop;
282 }
283