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 24typedef struct { 25 const AppSpawnContent *content; 26 const AppSpawnedProcessInfo *appInfo; 27} AppSpawnAppArg; 28 29static 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}; 40static HOOK_MGR *g_appspawnHookMgr = NULL; 41 42int 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 61void 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 73int 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 90HOOK_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 99void DeleteAppSpawnHookMgr(void) 100{ 101 HookMgrDestroy(g_appspawnHookMgr); 102 g_appspawnHookMgr = NULL; 103} 104 105static 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 117static 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 124static 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 132static 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 143int 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 160int 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 174static 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 181static 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 188static 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 197int 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 218int AppSpawnExecuteClearEnvHook(AppSpawnContent *content, AppSpawnClient *client) 219{ 220 return AppSpawnHookExecute(STAGE_CHILD_PRE_COLDBOOT, HOOK_STOP_WHEN_ERROR, content, client); 221} 222 223int AppSpawnExecuteSpawningHook(AppSpawnContent *content, AppSpawnClient *client) 224{ 225 return AppSpawnHookExecute(STAGE_CHILD_EXECUTE, HOOK_STOP_WHEN_ERROR, content, client); 226} 227 228int AppSpawnExecutePostReplyHook(AppSpawnContent *content, AppSpawnClient *client) 229{ 230 return AppSpawnHookExecute(STAGE_CHILD_POST_RELY, HOOK_STOP_WHEN_ERROR, content, client); 231} 232 233int AppSpawnExecutePreReplyHook(AppSpawnContent *content, AppSpawnClient *client) 234{ 235 return AppSpawnHookExecute(STAGE_CHILD_PRE_RELY, HOOK_STOP_WHEN_ERROR, content, client); 236} 237 238void AppSpawnEnvClear(AppSpawnContent *content, AppSpawnClient *client) 239{ 240 (void)AppSpawnHookExecute(STAGE_CHILD_PRE_RUN, 0, content, client); 241} 242 243int 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 257int 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_DIED), 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 272static 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 279int 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_DIED), 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 292void 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