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