1 /*
2 * Copyright (c) 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 "js_worker.h"
17
18 #include <cerrno>
19 #include <climits>
20 #include <cstdlib>
21 #include <fstream>
22 #include <vector>
23 #include <unistd.h>
24
25 #include "connect_server_manager.h"
26 #ifdef SUPPORT_GRAPHICS
27 #include "core/common/container_scope.h"
28 #endif
29 #include "hilog_wrapper.h"
30 #include "js_console_log.h"
31 #include "js_runtime_utils.h"
32 #include "native_engine/impl/ark/ark_native_engine.h"
33
34 #ifdef SUPPORT_GRAPHICS
35 using OHOS::Ace::ContainerScope;
36 #endif
37
38 namespace OHOS {
39 namespace AbilityRuntime {
40 namespace {
41 constexpr int64_t ASSET_FILE_MAX_SIZE = 32 * 1024 * 1024;
42 const std::string BUNDLE_NAME_FLAG = "@bundle:";
43 #ifdef APP_USE_ARM
44 constexpr char ARK_DEBUGGER_LIB_PATH[] = "/system/lib/libark_debugger.z.so";
45 #else
46 constexpr char ARK_DEBUGGER_LIB_PATH[] = "/system/lib64/libark_debugger.z.so";
47 #endif
48
49 bool g_debugMode = false;
50
InitWorkerFunc(NativeEngine * nativeEngine)51 void InitWorkerFunc(NativeEngine* nativeEngine)
52 {
53 HILOG_INFO("InitWorkerFunc called");
54 if (nativeEngine == nullptr) {
55 HILOG_ERROR("Input nativeEngine is nullptr");
56 return;
57 }
58
59 NativeObject* globalObj = ConvertNativeValueTo<NativeObject>(nativeEngine->GetGlobal());
60 if (globalObj == nullptr) {
61 HILOG_ERROR("Failed to get global object");
62 return;
63 }
64
65 InitConsoleLogModule(*nativeEngine, *globalObj);
66
67 if (g_debugMode) {
68 auto instanceId = gettid();
69 std::string instanceName = "workerThread_" + std::to_string(instanceId);
70 bool needBreakPoint = ConnectServerManager::Get().AddInstance(instanceId, instanceName);
71 auto arkNativeEngine = static_cast<ArkNativeEngine*>(nativeEngine);
72 auto vm = const_cast<EcmaVM*>(arkNativeEngine->GetEcmaVm());
73 auto workerPostTask = [nativeEngine](std::function<void()>&& callback) {
74 nativeEngine->CallDebuggerPostTaskFunc(std::move(callback));
75 };
76 panda::JSNApi::StartDebugger(ARK_DEBUGGER_LIB_PATH, vm, needBreakPoint, instanceId, workerPostTask);
77 }
78 }
79
OffWorkerFunc(NativeEngine * nativeEngine)80 void OffWorkerFunc(NativeEngine* nativeEngine)
81 {
82 HILOG_INFO("OffWorkerFunc called");
83 if (nativeEngine == nullptr) {
84 HILOG_ERROR("Input nativeEngine is nullptr");
85 return;
86 }
87
88 if (g_debugMode) {
89 auto instanceId = gettid();
90 ConnectServerManager::Get().RemoveInstance(instanceId);
91 auto arkNativeEngine = static_cast<ArkNativeEngine*>(nativeEngine);
92 auto vm = const_cast<EcmaVM*>(arkNativeEngine->GetEcmaVm());
93 panda::JSNApi::StopDebugger(vm);
94 }
95 }
96
ReadAssetData(const std::string & filePath,std::vector<uint8_t> & content,bool isDebugVersion)97 bool ReadAssetData(const std::string& filePath, std::vector<uint8_t>& content, bool isDebugVersion)
98 {
99 char path[PATH_MAX];
100 if (realpath(filePath.c_str(), path) == nullptr) {
101 HILOG_ERROR("ReadAssetData realpath(%{private}s) failed, errno = %{public}d", filePath.c_str(), errno);
102 return false;
103 }
104
105 std::ifstream stream(path, std::ios::binary | std::ios::ate);
106 if (!stream.is_open()) {
107 HILOG_ERROR("ReadAssetData failed to open file %{private}s", filePath.c_str());
108 return false;
109 }
110
111 auto fileLen = stream.tellg();
112 if (!isDebugVersion && fileLen > ASSET_FILE_MAX_SIZE) {
113 HILOG_ERROR("ReadAssetData failed, file is too large");
114 return false;
115 }
116
117 content.resize(fileLen);
118
119 stream.seekg(0);
120 stream.read(reinterpret_cast<char*>(content.data()), content.size());
121 return true;
122 }
123
124 struct AssetHelper final {
AssetHelperOHOS::AbilityRuntime::__anonf1715a6d0111::AssetHelper125 explicit AssetHelper(const std::string& codePath, bool isDebugVersion, bool isBundle)
126 : codePath_(codePath), isDebugVersion_(isDebugVersion), isBundle_(isBundle)
127 {
128 if (!codePath_.empty() && codePath.back() != '/') {
129 codePath_.append("/");
130 }
131 }
132
NormalizedFileNameOHOS::AbilityRuntime::__anonf1715a6d0111::AssetHelper133 std::string NormalizedFileName(const std::string& fileName) const
134 {
135 std::string normalizedFilePath;
136 size_t index = 0;
137 index = fileName.find_last_of(".");
138 // 1.1 end with file name
139 // 1.2 end with file name and file type
140 if (index == std::string::npos) {
141 HILOG_DEBUG("uri end without file type");
142 normalizedFilePath = fileName + ".abc";
143 } else {
144 HILOG_DEBUG("uri end with file type");
145 normalizedFilePath = fileName.substr(0, index) + ".abc";
146 }
147 return normalizedFilePath;
148 }
149
operator ()OHOS::AbilityRuntime::__anonf1715a6d0111::AssetHelper150 void operator()(const std::string& uri, std::vector<uint8_t>& content, std::string &ami) const
151 {
152 if (uri.empty()) {
153 HILOG_ERROR("Uri is empty.");
154 return;
155 }
156
157 HILOG_INFO("RegisterAssetFunc called, uri: %{private}s", uri.c_str());
158 std::string realPath;
159 std::string filePath;
160
161 // 1. compilemode is jsbundle
162 // 2. compilemode is esmodule
163 if (isBundle_) {
164 // 1.1 start with @bundle:bundlename/modulename
165 // 1.2 start with /modulename
166 // 1.3 start with modulename
167 HILOG_DEBUG("The application is packaged using jsbundle mode.");
168 if (uri.find(BUNDLE_NAME_FLAG) == 0) {
169 size_t index = 0;
170 HILOG_DEBUG("uri start with @bundle:");
171 index = uri.find_first_of("/");
172 realPath = uri.substr(index + 1);
173 } else if (uri.find_first_of("/") == 0) {
174 HILOG_DEBUG("uri start with /modulename");
175 realPath = uri.substr(1);
176 } else {
177 HILOG_DEBUG("uri start with modulename");
178 realPath = uri;
179 }
180
181 filePath = NormalizedFileName(realPath);
182 ami = codePath_ + filePath;
183 HILOG_DEBUG("Get asset, ami: %{private}s", ami.c_str());
184 if (!ReadAssetData(ami, content, isDebugVersion_)) {
185 HILOG_ERROR("Get asset content failed.");
186 return;
187 }
188 } else {
189 // 2.1 start with @bundle:bundlename/modulename
190 // 2.2 start with /modulename
191 // 2.3 start with modulename
192 HILOG_DEBUG("The application is packaged using esmodule mode.");
193 if (uri.find(BUNDLE_NAME_FLAG) == 0) {
194 HILOG_DEBUG("uri start with @bundle:");
195 size_t fileNamePos = uri.find_last_of("/");
196 realPath = uri.substr(fileNamePos + 1);
197 if (realPath.find_last_of(".") != std::string::npos) {
198 ami = NormalizedFileName(uri);
199 } else {
200 ami = uri;
201 }
202 HILOG_DEBUG("Get asset, ami: %{private}s", ami.c_str());
203 return;
204 } else if (uri.find_first_of("/") == 0) {
205 HILOG_DEBUG("uri start with /modulename");
206 realPath = uri.substr(1);
207 } else {
208 HILOG_DEBUG("uri start with modulename");
209 realPath = uri;
210 }
211
212 filePath = NormalizedFileName(realPath);
213 ami = codePath_ + filePath;
214 HILOG_DEBUG("Get asset, ami: %{private}s", ami.c_str());
215 }
216 }
217
218 std::string codePath_;
219 bool isDebugVersion_ = false;
220 bool isBundle_ = false;
221 };
222
GetContainerId()223 int32_t GetContainerId()
224 {
225 #ifdef SUPPORT_GRAPHICS
226 int32_t scopeId = ContainerScope::CurrentId();
227 return scopeId;
228 #else
229 constexpr int32_t containerScopeDefaultId = 0;
230 return containerScopeDefaultId;
231 #endif
232 }
UpdateContainerScope(int32_t id)233 void UpdateContainerScope(int32_t id)
234 {
235 #ifdef SUPPORT_GRAPHICS
236 ContainerScope::UpdateCurrent(id);
237 #endif
238 }
RestoreContainerScope(int32_t id)239 void RestoreContainerScope(int32_t id)
240 {
241 #ifdef SUPPORT_GRAPHICS
242 ContainerScope::UpdateCurrent(-1);
243 #endif
244 }
245 }
246
InitWorkerModule(NativeEngine & engine,const std::string & codePath,bool isDebugVersion,bool isBundle)247 void InitWorkerModule(NativeEngine& engine, const std::string& codePath, bool isDebugVersion, bool isBundle)
248 {
249 engine.SetInitWorkerFunc(InitWorkerFunc);
250 engine.SetOffWorkerFunc(OffWorkerFunc);
251 engine.SetGetAssetFunc(AssetHelper(codePath, isDebugVersion, isBundle));
252
253 engine.SetGetContainerScopeIdFunc(GetContainerId);
254 engine.SetInitContainerScopeFunc(UpdateContainerScope);
255 engine.SetFinishContainerScopeFunc(RestoreContainerScope);
256 }
257
StartDebuggerInWorkerModule()258 void StartDebuggerInWorkerModule()
259 {
260 g_debugMode = true;
261 }
262 } // namespace AbilityRuntime
263 } // namespace OHOS