• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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