1 /*
2 * Copyright (c) 2023 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_adapter.h"
17
18 #include <set>
19 #include "appspawn_service.h"
20 #include "config_policy_utils.h"
21 #include "hitrace_meter.h"
22 #include "js_runtime.h"
23 #include "parameters.h"
24 #include "runtime.h"
25 #include "json_utils.h"
26 #include "resource_manager.h"
27 #include "foundation/ability/ability_runtime/interfaces/kits/native/appkit/app/main_thread.h"
28 #include "syspara/parameter.h"
29
30 using namespace OHOS::AppSpawn;
31 using namespace OHOS::Global;
32
33 #ifdef ASAN_DETECTOR
34 static const bool DEFAULT_PRELOAD_VALUE = false;
35 #else
36 static const bool DEFAULT_PRELOAD_VALUE = true;
37 #endif
38 static const std::string PRELOAD_JSON_CONFIG("/appspawn_preload.json");
39
GetPreloadModules(const std::string & configName,std::set<std::string> & modules)40 static void GetPreloadModules(const std::string &configName, std::set<std::string> &modules)
41 {
42 // Preload napi module
43 nlohmann::json preloadJson;
44 bool rc = JsonUtils::GetJsonObjFromJson(preloadJson, configName);
45 APPSPAWN_CHECK_ONLY_EXPER(rc, return);
46 // no config
47 if (preloadJson.find("napi") == preloadJson.end()) {
48 return;
49 }
50
51 nlohmann::json modulesJson = preloadJson["napi"];
52 uint32_t moduleCount = modulesJson.size();
53 for (uint32_t i = 0; i < moduleCount; ++i) {
54 nlohmann::json moduleName = modulesJson[i];
55 APPSPAWN_LOGV("moduleName %{public}s", moduleName.get<std::string>().c_str());
56 if (!modules.count(moduleName.get<std::string>())) {
57 modules.insert(moduleName.get<std::string>());
58 }
59 }
60 }
61
PreloadModule(void)62 static void PreloadModule(void)
63 {
64 #ifndef APPSPAWN_TEST
65 OHOS::AbilityRuntime::Runtime::Options options;
66 options.lang = OHOS::AbilityRuntime::Runtime::Language::JS;
67 options.loadAce = true;
68 options.preload = true;
69
70 auto runtime = OHOS::AbilityRuntime::Runtime::Create(options);
71 if (!runtime) {
72 APPSPAWN_LOGE("LoadExtendLib: Failed to create runtime");
73 return;
74 }
75 #endif
76 std::set<std::string> modules = {};
77 CfgFiles *files = GetCfgFiles("etc/appspawn");
78 if (files == nullptr) {
79 APPSPAWN_LOGE("LoadExtendLib: Get cfg file fail");
80 return;
81 }
82 for (int i = 0; i < MAX_CFG_POLICY_DIRS_CNT; ++i) {
83 if (files->paths[i] == nullptr) {
84 continue;
85 }
86 std::string path = files->paths[i];
87 path += PRELOAD_JSON_CONFIG;
88 APPSPAWN_LOGI("PreloadModules path %{public}s", path.c_str());
89 GetPreloadModules(path, modules);
90 }
91 FreeCfgFiles(files);
92 for (std::string moduleName : modules) {
93 APPSPAWN_LOGI("moduleName %{public}s", moduleName.c_str());
94 #ifndef APPSPAWN_TEST
95 runtime->PreloadSystemModule(moduleName);
96 #endif
97 }
98 #ifndef APPSPAWN_TEST
99 // Save preloaded runtime
100 OHOS::AbilityRuntime::Runtime::SavePreloaded(std::move(runtime));
101 #endif
102 }
103
LoadExtendLib(AppSpawnContent * content)104 void LoadExtendLib(AppSpawnContent *content)
105 {
106 const char *acelibdir("libace.z.so");
107 APPSPAWN_LOGI("LoadExtendLib: Start calling dlopen acelibdir.");
108 void *aceAbilityLib = dlopen(acelibdir, RTLD_NOW | RTLD_GLOBAL);
109 APPSPAWN_CHECK(aceAbilityLib != nullptr, return, "Fail to dlopen %{public}s, [%{public}s]", acelibdir, dlerror());
110 APPSPAWN_LOGI("LoadExtendLib: Success to dlopen %{public}s", acelibdir);
111
112 #ifndef APPSPAWN_TEST
113 OHOS::AppExecFwk::MainThread::PreloadExtensionPlugin();
114 #endif
115
116 bool preload = OHOS::system::GetBoolParameter("const.appspawn.preload", DEFAULT_PRELOAD_VALUE);
117 if (!preload) {
118 APPSPAWN_LOGI("LoadExtendLib: Do not preload JS VM");
119 return;
120 }
121
122 APPSPAWN_LOGI("LoadExtendLib: Start preload JS VM");
123 SetTraceDisabled(true);
124 #ifndef APPSPAWN_TEST
125 PreloadModule();
126 #endif
127 SetTraceDisabled(false);
128
129 Resource::ResourceManager *systemResMgr = Resource::GetSystemResourceManagerNoSandBox();
130 APPSPAWN_CHECK(systemResMgr != nullptr, return, "Fail to get system resource manager");
131 APPSPAWN_LOGI("LoadExtendLib: End preload JS VM");
132 }
133
RunChildProcessor(AppSpawnContent * content,AppSpawnClient * client)134 void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
135 {
136 APPSPAWN_CHECK(client != NULL && content != NULL, return, "Invalid client");
137 AppSpawnClientExt *appProperty = reinterpret_cast<AppSpawnClientExt *>(client);
138 if (appProperty->property.code == SPAWN_NATIVE_PROCESS) {
139 APPSPAWN_LOGI("renderCmd %{public}s", appProperty->property.renderCmd);
140 (void)system(appProperty->property.renderCmd);
141 return;
142 }
143 APPSPAWN_LOGI("LoadExtendLib: RunChildProcessor");
144 #ifndef APPSPAWN_TEST
145 std::string checkExit;
146 if (GetIntParameter("persist.init.debug.checkexit", true)) {
147 checkExit = std::to_string(getpid());
148 }
149 setenv(APPSPAWN_CHECK_EXIT, checkExit.c_str(), true);
150 OHOS::AppExecFwk::MainThread::Start();
151 unsetenv(APPSPAWN_CHECK_EXIT);
152 #endif
153 }
154