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