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 <algorithm>
17 #include <cerrno>
18 #include <ctime>
19 #include <dlfcn.h>
20 #include <map>
21 #include <mutex>
22 #include <string>
23
24 #ifdef __MUSL__
25 #include <cerrno>
26 #include <dlfcn_ext.h>
27 #include <sys/mman.h>
28 #endif
29
30 #include "appspawn_hook.h"
31 #include "appspawn_manager.h"
32 #include "parameter.h"
33
34 #ifdef WITH_SECCOMP
35 #include "seccomp_policy.h"
36 #endif
37
38 #include "arkweb_utils.h"
39
40 namespace {
41 const std::string ARK_WEB_ENGINE_LIB_NAME = "libarkweb_engine.so";
42 const std::string ARK_WEB_RENDER_LIB_NAME = "libarkweb_render.so";
43
44 typedef enum {
45 PRELOAD_NO = 0, // 不预加载
46 PRELOAD_PARTIAL = 1, // 只预加载libohos_adapter_glue_source.z.so
47 PRELOAD_FULL = 2 // 预加载libohos_adapter_glue_source.z.so和libarkweb_engine.so
48 } RenderPreLoadMode;
49
50 } // namespace
51
SetSeccompPolicyForRenderer(void * nwebRenderHandle)52 static bool SetSeccompPolicyForRenderer(void *nwebRenderHandle)
53 {
54 #ifdef WITH_SECCOMP
55 if (IsEnableSeccomp()) {
56 using SeccompFuncType = bool (*)(void);
57 SeccompFuncType funcSetRendererSeccompPolicy =
58 reinterpret_cast<SeccompFuncType>(dlsym(nwebRenderHandle, "SetRendererSeccompPolicy"));
59 if (funcSetRendererSeccompPolicy != nullptr && funcSetRendererSeccompPolicy()) {
60 return true;
61 }
62 APPSPAWN_LOGE("SetRendererSeccompPolicy dlsym errno: %{public}d", errno);
63 return false;
64 }
65 #endif
66 return true;
67 }
68
UpdateAppWebEngineVersion(std::string & renderCmd)69 static void UpdateAppWebEngineVersion(std::string& renderCmd)
70 {
71 size_t posLeft = renderCmd.rfind(APP_ENGINE_VERSION_PREFIX);
72 if (posLeft == std::string::npos) {
73 APPSPAWN_LOGE("not found app engine type arg");
74 return;
75 }
76 size_t posRight = posLeft + strlen(APP_ENGINE_VERSION_PREFIX);
77 size_t posEnd = renderCmd.find('#', posRight);
78 std::string value = (posEnd == std::string::npos) ?
79 renderCmd.substr(posRight) :
80 renderCmd.substr(posRight, posEnd - posRight);
81
82 char* end;
83 long v = std::strtol(value.c_str(), &end, 10);
84 if (*end != '\0' || v > INT_MAX || v < 0) {
85 APPSPAWN_LOGE("invalid value: %{public}s", value.c_str());
86 return;
87 }
88 auto version = static_cast<OHOS::ArkWeb::ArkWebEngineVersion>(v);
89 OHOS::ArkWeb::setActiveWebEngineVersion(version);
90
91 // remove arg APP_ENGINE_VERSION_PREFIX
92 size_t eraseLength = (posEnd == std::string::npos) ?
93 renderCmd.length() - posLeft :
94 posEnd - posLeft;
95 renderCmd.erase(posLeft, eraseLength);
96 }
97
RunChildProcessor(AppSpawnContent * content,AppSpawnClient * client)98 APPSPAWN_STATIC int RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
99 {
100 uint32_t len = 0;
101 char *renderCmd = reinterpret_cast<char *>(GetAppPropertyExt(
102 reinterpret_cast<AppSpawningCtx *>(client), MSG_EXT_NAME_RENDER_CMD, &len));
103 if (renderCmd == nullptr) {
104 return -1;
105 }
106 std::string renderStr(renderCmd);
107 UpdateAppWebEngineVersion(renderStr);
108
109 void *webEngineHandle = nullptr;
110 void *nwebRenderHandle = nullptr;
111
112 const std::string libNsName = OHOS::ArkWeb::GetArkwebNameSpace();
113 const std::string libPath = OHOS::ArkWeb::GetArkwebLibPath();
114 const std::string engineLibName = ARK_WEB_ENGINE_LIB_NAME;
115 const std::string renderLibName = ARK_WEB_RENDER_LIB_NAME;
116
117 #ifdef __MUSL__
118 Dl_namespace dlns;
119 Dl_namespace ndkns;
120 dlns_init(&dlns, libNsName.c_str());
121 dlns_create(&dlns, libPath.c_str());
122 dlns_get("ndk", &ndkns);
123 dlns_inherit(&dlns, &ndkns, "allow_all_shared_libs");
124 // preload libweb_engine
125 webEngineHandle = dlopen_ns(&dlns, engineLibName.c_str(), RTLD_NOW | RTLD_GLOBAL);
126 // load libnweb_render
127 nwebRenderHandle = dlopen_ns(&dlns, renderLibName.c_str(), RTLD_NOW | RTLD_GLOBAL);
128 #else
129 // preload libweb_engine
130 const std::string engineLibPath = libPath + "/" + engineLibName;
131 webEngineHandle = dlopen(engineLibPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
132
133 // load libnweb_render
134 const std::string renderLibPath = libPath + "/" + renderLibName;
135 nwebRenderHandle = dlopen(renderLibPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
136 #endif
137 if (webEngineHandle == nullptr) {
138 APPSPAWN_LOGE("Fail to dlopen libweb_engine.so, errno: %{public}d", errno);
139 }
140 if (nwebRenderHandle == nullptr) {
141 APPSPAWN_LOGE("Fail to dlopen libnweb_render.so, errno: %{public}d", errno);
142 return -1;
143 }
144
145 std::string processType = reinterpret_cast<char *>(GetAppPropertyExt(
146 reinterpret_cast<AppSpawningCtx *>(client), MSG_EXT_NAME_PROCESS_TYPE, &len));
147 if (processType == "render" && !SetSeccompPolicyForRenderer(nwebRenderHandle)) {
148 return -1;
149 }
150 using FuncType = void (*)(const char *cmd);
151
152 FuncType funcNWebRenderMain = reinterpret_cast<FuncType>(dlsym(nwebRenderHandle, "NWebRenderMain"));
153 if (funcNWebRenderMain == nullptr) {
154 APPSPAWN_LOGE("webviewspawn dlsym errno: %{public}d", errno);
155 return -1;
156 }
157 AppSpawnEnvClear(content, client);
158 APPSPAWN_LOGI("RunChildProcessorNweb %{public}s", renderStr.c_str());
159 funcNWebRenderMain(renderStr.c_str());
160 return 0;
161 }
162
GetOhosAdptGlueSrcLibPath()163 static std::string GetOhosAdptGlueSrcLibPath()
164 {
165 #ifdef webview_arm64
166 const std::string ARK_WEB_CORE_HAP_LIB_PATH =
167 "/system/lib64/libohos_adapter_glue_source.z.so";
168 #elif webview_x86_64
169 const std::string ARK_WEB_CORE_HAP_LIB_PATH = "";
170 #else
171 const std::string ARK_WEB_CORE_HAP_LIB_PATH =
172 "/system/lib/libohos_adapter_glue_source.z.so";
173 #endif
174 return ARK_WEB_CORE_HAP_LIB_PATH;
175 }
176
GetArkWebEngineLibPath()177 static std::string GetArkWebEngineLibPath()
178 {
179 char bundleName[PATH_MAX] = {0};
180 GetParameter("persist.arkwebcore.package_name", "", bundleName, PATH_MAX);
181 if (strlen(bundleName) == 0) {
182 APPSPAWN_LOGE("Fail to get persist.arkwebcore.package_name, empty");
183 return "";
184 }
185 #ifdef webview_arm64
186 const std::string ARK_WEB_CORE_HAP_LIB_PATH =
187 "/data/app/el1/bundle/public/" + std::string(bundleName) + "/libs/arm64";
188 #elif webview_x86_64
189 const std::string ARK_WEB_CORE_HAP_LIB_PATH = "";
190 #else
191 const std::string ARK_WEB_CORE_HAP_LIB_PATH =
192 "/data/app/el1/bundle/public/" + std::string(bundleName) + "/libs/arm";
193 #endif
194 return ARK_WEB_CORE_HAP_LIB_PATH;
195 }
196
PreLoadArkWebEngineLib()197 static void PreLoadArkWebEngineLib()
198 {
199 Dl_namespace dlns;
200 Dl_namespace ndkns;
201 dlns_init(&dlns, "nweb_ns");
202 const std::string arkWebEngineLibPath = GetArkWebEngineLibPath();
203 if (arkWebEngineLibPath.empty()) {
204 return;
205 }
206 dlns_create(&dlns, arkWebEngineLibPath.c_str());
207 dlns_get("ndk", &ndkns);
208 dlns_inherit(&dlns, &ndkns, "allow_all_shared_libs");
209 void *webEngineHandle = dlopen_ns(&dlns, ARK_WEB_ENGINE_LIB_NAME.c_str(), RTLD_NOW | RTLD_GLOBAL);
210 if (!webEngineHandle) {
211 APPSPAWN_LOGE("Fail to dlopen libarkweb_engine.so, errno: %{public}d", errno);
212 }
213 }
214
PreLoadOHOSAdptGlueSrcLib()215 static void PreLoadOHOSAdptGlueSrcLib()
216 {
217 const std::string ohosAdptGlueSrcLibPath = GetOhosAdptGlueSrcLibPath();
218 if (ohosAdptGlueSrcLibPath.empty()) {
219 return;
220 }
221 void *ohosAdptGlueSrcHandle = dlopen(ohosAdptGlueSrcLibPath.c_str(), RTLD_NOW | RTLD_GLOBAL);
222 if (!ohosAdptGlueSrcHandle) {
223 APPSPAWN_LOGE("Fail to dlopen libohos_adapter_glue_source.z.so, errno: %{public}d", errno);
224 }
225 }
226
227 #ifndef arkweb_preload
GetSysParamPreLoadMode()228 static int GetSysParamPreLoadMode()
229 {
230 const int BUFFER_LEN = 8;
231 char preLoadMode[BUFFER_LEN] = {0};
232 GetParameter("const.startup.nwebspawn.preloadMode", "0", preLoadMode, BUFFER_LEN);
233 int ret = std::atoi(preLoadMode);
234 return ret;
235 }
236 #endif
237
PreLoadNwebSpawn(AppSpawnMgr * content)238 APPSPAWN_STATIC int PreLoadNwebSpawn(AppSpawnMgr *content)
239 {
240 APPSPAWN_LOGI("PreLoadNwebSpawn %{public}d", IsNWebSpawnMode(content));
241 if (!IsNWebSpawnMode(content)) {
242 return 0;
243 }
244 // register
245 RegChildLooper(&content->content, RunChildProcessor);
246
247 // preload render lib
248 #ifdef arkweb_preload
249 int preloadMode = RenderPreLoadMode::PRELOAD_FULL;
250 #else
251 int preloadMode = GetSysParamPreLoadMode();
252 #endif
253 APPSPAWN_LOGI("NwebSpawn preload render lib mode: %{public}d", preloadMode);
254 if (preloadMode == PRELOAD_PARTIAL) {
255 PreLoadOHOSAdptGlueSrcLib();
256 }
257 if (preloadMode == PRELOAD_FULL) {
258 PreLoadArkWebEngineLib();
259 PreLoadOHOSAdptGlueSrcLib();
260 }
261
262 return 0;
263 }
264
MODULE_CONSTRUCTOR(void)265 MODULE_CONSTRUCTOR(void)
266 {
267 APPSPAWN_LOGI("Load nweb module ...");
268 AddPreloadHook(HOOK_PRIO_HIGHEST, PreLoadNwebSpawn);
269 }
270