• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 <dlfcn.h>
17 
18 #include <algorithm>
19 #include <ctime>
20 #include <map>
21 #include <mutex>
22 #include <string>
23 
24 #ifdef __MUSL__
25 #include <dlfcn_ext.h>
26 #include <cerrno>
27 #include <sys/mman.h>
28 #endif
29 
30 #include "appspawn_service.h"
31 #include "appspawn_adapter.h"
32 struct RenderProcessNode {
RenderProcessNodeRenderProcessNode33     RenderProcessNode(time_t now, int exit):recordTime_(now), exitStatus_(exit) {}
34     time_t recordTime_;
35     int exitStatus_;
36 };
37 
38 namespace {
39     constexpr int32_t RENDER_PROCESS_MAX_NUM = 16;
40     std::map<int32_t, RenderProcessNode> g_renderProcessMap;
41     void *g_nwebHandle = nullptr;
42     std::mutex g_mutex;
43 }
44 
45 #ifdef __MUSL__
LoadWithRelroFile(const std::string & lib,const std::string & nsName,const std::string & nsPath)46 void *LoadWithRelroFile(const std::string &lib, const std::string &nsName,
47                         const std::string &nsPath)
48 {
49 #ifdef webview_arm64
50     const std::string nwebRelroPath =
51         "/data/misc/shared_relro/libwebviewchromium64.relro";
52     size_t nwebReservedSize = 1 * 1024 * 1024 * 1024;
53 #else
54     const std::string nwebRelroPath =
55         "/data/misc/shared_relro/libwebviewchromium32.relro";
56     size_t nwebReservedSize = 130 * 1024 * 1024;
57 #endif
58     if (unlink(nwebRelroPath.c_str()) != 0 && errno != ENOENT) {
59         APPSPAWN_LOGI("LoadWithRelroFile unlink failed");
60     }
61     int relroFd =
62         open(nwebRelroPath.c_str(), O_RDWR | O_TRUNC | O_CLOEXEC | O_CREAT,
63             S_IRUSR | S_IRGRP | S_IROTH);
64     if (relroFd < 0) {
65         int tmpNo = errno;
66         APPSPAWN_LOGE("LoadWithRelroFile open failed, error=[%s]", strerror(tmpNo));
67         return nullptr;
68     }
69     void *nwebReservedAddress = mmap(NULL, nwebReservedSize, PROT_NONE,
70                                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
71     if (nwebReservedAddress == MAP_FAILED) {
72         close(relroFd);
73         int tmpNo = errno;
74         APPSPAWN_LOGE("LoadWithRelroFile mmap failed, error=[%s]", strerror(tmpNo));
75         return nullptr;
76     }
77     Dl_namespace dlns;
78     dlns_init(&dlns, nsName.c_str());
79     dlns_create(&dlns, nsPath.c_str());
80     dl_extinfo extinfo = {
81         .flag = DL_EXT_WRITE_RELRO | DL_EXT_RESERVED_ADDRESS_RECURSIVE |
82                 DL_EXT_RESERVED_ADDRESS,
83         .relro_fd = relroFd,
84         .reserved_addr = nwebReservedAddress,
85         .reserved_size = nwebReservedSize,
86     };
87     void *result =
88         dlopen_ns_ext(&dlns, lib.c_str(), RTLD_NOW | RTLD_GLOBAL, &extinfo);
89     close(relroFd);
90     return result;
91 }
92 #endif
93 
LoadExtendLib(AppSpawnContent * content)94 void LoadExtendLib(AppSpawnContent *content)
95 {
96 #if defined(webview_arm64)
97     const std::string loadLibDir = "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm64";
98 #elif defined(webview_x86_64)
99     const std::string loadLibDir = "/data/app/el1/bundle/public/com.ohos.nweb/libs/x86_64";
100 #else
101     const std::string loadLibDir = "/data/app/el1/bundle/public/com.ohos.nweb/libs/arm";
102 #endif
103 
104 #ifdef __MUSL__
105     Dl_namespace dlns;
106     dlns_init(&dlns, "nweb_ns");
107     dlns_create(&dlns, loadLibDir.c_str());
108 #if defined(webview_x86_64)
109     void *handle = dlopen_ns(&dlns, "libweb_engine.so", RTLD_NOW | RTLD_GLOBAL);
110 #else
111     void *handle = LoadWithRelroFile("libweb_engine.so", "nweb_ns", loadLibDir);
112     if (handle == nullptr) {
113         APPSPAWN_LOGE("dlopen_ns_ext failed, fallback to dlopen_ns");
114         handle = dlopen_ns(&dlns, "libweb_engine.so", RTLD_NOW | RTLD_GLOBAL);
115     }
116 #endif
117 #else
118     const std::string engineLibDir = loadLibDir + "/libweb_engine.so";
119     void *handle = dlopen(engineLibDir.c_str(), RTLD_NOW | RTLD_GLOBAL);
120 #endif
121     if (handle == nullptr) {
122         APPSPAWN_LOGE("Fail to dlopen libweb_engine.so, [%s]", dlerror());
123     } else {
124         APPSPAWN_LOGI("Success to dlopen libweb_engine.so");
125     }
126 
127 #ifdef __MUSL__
128     g_nwebHandle = dlopen_ns(&dlns, "libnweb_render.so", RTLD_NOW | RTLD_GLOBAL);
129 #else
130     const std::string renderLibDir = loadLibDir + "/libnweb_render.so";
131     g_nwebHandle = dlopen(renderLibDir.c_str(), RTLD_NOW | RTLD_GLOBAL);
132 #endif
133     if (g_nwebHandle == nullptr) {
134         APPSPAWN_LOGE("Fail to dlopen libnweb_render.so, [%s]", dlerror());
135     } else {
136         APPSPAWN_LOGI("Success to dlopen libnweb_render.so");
137     }
138 }
139 
RunChildProcessor(AppSpawnContent * content,AppSpawnClient * client)140 void RunChildProcessor(AppSpawnContent *content, AppSpawnClient *client)
141 {
142     AppSpawnClientExt *appProperty = reinterpret_cast<AppSpawnClientExt *>(client);
143     using FuncType = void (*)(const char *cmd);
144 
145     FuncType funcNWebRenderMain = reinterpret_cast<FuncType>(dlsym(g_nwebHandle, "NWebRenderMain"));
146     if (funcNWebRenderMain == nullptr) {
147         APPSPAWN_LOGI("webviewspawn dlsym ERROR=%s", dlerror());
148         return;
149     }
150 
151     funcNWebRenderMain(appProperty->property.renderCmd);
152 }
153 
DumpRenderProcessExitedMap()154 static void DumpRenderProcessExitedMap()
155 {
156     APPSPAWN_LOGI("dump render process exited array:");
157 
158     for (auto& it : g_renderProcessMap) {
159         APPSPAWN_LOGV("[pid, time, exitedStatus] = [%d, %ld, %d]",
160             it.first, it.second.recordTime_, it.second.exitStatus_);
161     }
162 }
163 
RecordRenderProcessExitedStatus(pid_t pid,int status)164 void RecordRenderProcessExitedStatus(pid_t pid, int status)
165 {
166     std::lock_guard<std::mutex> lock(g_mutex);
167     if (g_renderProcessMap.size() < RENDER_PROCESS_MAX_NUM) {
168         RenderProcessNode node(time(nullptr), status);
169         g_renderProcessMap.insert({pid, node});
170         return;
171     }
172 
173     APPSPAWN_LOGV("render process map size reach max, need to erase oldest data.");
174     DumpRenderProcessExitedMap();
175     auto oldestData = std::min_element(g_renderProcessMap.begin(), g_renderProcessMap.end(),
176         [](const std::pair<int32_t, RenderProcessNode>& left, const std::pair<int32_t, RenderProcessNode>& right) {
177             return left.second.recordTime_ < right.second.recordTime_;
178         });
179 
180     g_renderProcessMap.erase(oldestData);
181     RenderProcessNode node(time(nullptr), status);
182     g_renderProcessMap.insert({pid, node});
183     DumpRenderProcessExitedMap();
184 }
185 
GetRenderProcessTerminationStatus(int32_t pid,int * status)186 int GetRenderProcessTerminationStatus(int32_t pid, int *status)
187 {
188     if (status == nullptr) {
189         return -1;
190     }
191 
192     std::lock_guard<std::mutex> lock(g_mutex);
193     auto it = g_renderProcessMap.find(pid);
194     if (it != g_renderProcessMap.end()) {
195         *status = it->second.exitStatus_;
196         g_renderProcessMap.erase(it);
197         return 0;
198     }
199 
200     APPSPAWN_LOGE("not find pid[%d] in render process exited map", pid);
201     DumpRenderProcessExitedMap();
202     return -1;
203 }
204