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