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 #include "command_lexer.h"
18 #include "param_helper.h"
19
20 #include <cerrno>
21 #include <cstring>
22 #include <set>
23 #include <string>
24 #include <utility>
25 #include <vector>
26 #include <unistd.h>
27 #include "appspawn_service.h"
28 #include "config_policy_utils.h"
29 #include "hitrace_meter.h"
30 #include "js_runtime.h"
31 #include "parameters.h"
32 #include "runtime.h"
33 #include "json_utils.h"
34 #include "resource_manager.h"
35 #include "foundation/ability/ability_runtime/interfaces/kits/native/appkit/app/main_thread.h"
36 #include "syspara/parameter.h"
37 #include "ace_forward_compatibility.h"
38
39 using namespace OHOS::AppSpawn;
40 using namespace OHOS::Global;
41
42 #ifdef ASAN_DETECTOR
43 static const bool DEFAULT_PRELOAD_VALUE = false;
44 #else
45 static const bool DEFAULT_PRELOAD_VALUE = true;
46 #endif
47 static const std::string PRELOAD_JSON_CONFIG("/appspawn_preload.json");
48
GetPreloadModules(const std::string & configName,std::set<std::string> & modules)49 static void GetPreloadModules(const std::string &configName, std::set<std::string> &modules)
50 {
51 // Preload napi module
52 nlohmann::json preloadJson;
53 bool rc = JsonUtils::GetJsonObjFromJson(preloadJson, configName);
54 APPSPAWN_CHECK_ONLY_EXPER(rc, return);
55 // no config
56 if (preloadJson.find("napi") == preloadJson.end()) {
57 return;
58 }
59
60 nlohmann::json modulesJson = preloadJson["napi"];
61 uint32_t moduleCount = modulesJson.size();
62 for (uint32_t i = 0; i < moduleCount; ++i) {
63 nlohmann::json moduleName = modulesJson[i];
64 APPSPAWN_LOGV("moduleName %{public}s", moduleName.get<std::string>().c_str());
65 if (!modules.count(moduleName.get<std::string>())) {
66 modules.insert(moduleName.get<std::string>());
67 }
68 }
69 }
70
PreloadModule(void)71 static void PreloadModule(void)
72 {
73 #ifndef APPSPAWN_TEST
74 OHOS::AbilityRuntime::Runtime::Options options;
75 options.lang = OHOS::AbilityRuntime::Runtime::Language::JS;
76 options.loadAce = true;
77 options.preload = true;
78
79 auto runtime = OHOS::AbilityRuntime::Runtime::Create(options);
80 if (!runtime) {
81 APPSPAWN_LOGE("LoadExtendLib: Failed to create runtime");
82 return;
83 }
84 #endif
85 std::set<std::string> modules = {};
86 CfgFiles *files = GetCfgFiles("etc/appspawn");
87 if (files == nullptr) {
88 APPSPAWN_LOGE("LoadExtendLib: Get cfg file fail");
89 return;
90 }
91 for (int i = 0; i < MAX_CFG_POLICY_DIRS_CNT; ++i) {
92 if (files->paths[i] == nullptr) {
93 continue;
94 }
95 std::string path = files->paths[i];
96 path += PRELOAD_JSON_CONFIG;
97 APPSPAWN_LOGI("PreloadModules path %{public}s", path.c_str());
98 GetPreloadModules(path, modules);
99 }
100 FreeCfgFiles(files);
101 for (std::string moduleName : modules) {
102 APPSPAWN_LOGI("moduleName %{public}s", moduleName.c_str());
103 #ifndef APPSPAWN_TEST
104 runtime->PreloadSystemModule(moduleName);
105 #endif
106 }
107 #ifndef APPSPAWN_TEST
108 // Save preloaded runtime
109 OHOS::AbilityRuntime::Runtime::SavePreloaded(std::move(runtime));
110 #endif
111 }
112
LoadExtendLib(AppSpawnContent * content)113 void LoadExtendLib(AppSpawnContent *content)
114 {
115 const char* acelibdir = OHOS::Ace::AceForwardCompatibility::GetAceLibName();
116 APPSPAWN_LOGI("LoadExtendLib: Start calling dlopen acelibdir.");
117 void *aceAbilityLib = dlopen(acelibdir, RTLD_NOW | RTLD_LOCAL);
118 APPSPAWN_CHECK(aceAbilityLib != nullptr, return, "Fail to dlopen %{public}s, [%{public}s]", acelibdir, dlerror());
119 APPSPAWN_LOGI("LoadExtendLib: Success to dlopen %{public}s", acelibdir);
120
121 #ifndef APPSPAWN_TEST
122 OHOS::AppExecFwk::MainThread::PreloadExtensionPlugin();
123 #endif
124
125 bool preload = OHOS::system::GetBoolParameter("persist.appspawn.preload", DEFAULT_PRELOAD_VALUE);
126 if (!preload) {
127 APPSPAWN_LOGI("LoadExtendLib: Do not preload JS VM");
128 return;
129 }
130
131 APPSPAWN_LOGI("LoadExtendLib: Start preload JS VM");
132 SetTraceDisabled(true);
133 #ifndef APPSPAWN_TEST
134 PreloadModule();
135 #endif
136 SetTraceDisabled(false);
137
138 Resource::ResourceManager *systemResMgr = Resource::GetSystemResourceManagerNoSandBox();
139 APPSPAWN_CHECK(systemResMgr != nullptr, return, "Fail to get system resource manager");
140 APPSPAWN_LOGI("LoadExtendLib: End preload JS VM");
141 }
142
RunChildProcessor(AppSpawnContent * content,AppSpawnClient * client)143 void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
144 {
145 APPSPAWN_CHECK(client != NULL && content != NULL, return, "Invalid client");
146 AppSpawnClientExt *appProperty = reinterpret_cast<AppSpawnClientExt *>(client);
147 if (appProperty->property.code == SPAWN_NATIVE_PROCESS) {
148 if (!IsDeveloperModeOn()) {
149 APPSPAWN_LOGE("Denied launching a native process: not in developer mode");
150 return;
151 }
152 APPSPAWN_LOGI("renderCmd %{public}s", appProperty->property.renderCmd);
153 std::vector<std::string> args;
154 std::string command(appProperty->property.renderCmd);
155 CommandLexer lexer(command);
156 if (!lexer.GetAllArguments(args)) {
157 return;
158 }
159 if (args.empty()) {
160 APPSPAWN_LOGE("Failed to run a native process: empty command");
161 return;
162 }
163 std::vector<char *> options;
164 for (const auto &arg : args) {
165 options.push_back(const_cast<char *>(arg.c_str()));
166 }
167 options.push_back(nullptr);
168 execvp(args[0].c_str(), options.data());
169 // If it succeeds calling execvp, it never returns.
170 int err = errno;
171 APPSPAWN_LOGE("Failed to launch a native process with execvp: %{public}s",
172 strerror(err));
173 return;
174 }
175 APPSPAWN_LOGI("LoadExtendLib: RunChildProcessor");
176 #ifndef APPSPAWN_TEST
177 std::string checkExit;
178 if (GetIntParameter("persist.init.debug.checkexit", true)) {
179 checkExit = std::to_string(getpid());
180 }
181 setenv(APPSPAWN_CHECK_EXIT, checkExit.c_str(), true);
182 OHOS::AppExecFwk::MainThread::Start();
183 unsetenv(APPSPAWN_CHECK_EXIT);
184 #endif
185 }
186