1 /*
2 * Copyright (c) 2022-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 "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 "bundle_mgr_helper.h"
26 #include "connect_server_manager.h"
27 #include "commonlibrary/c_utils/base/include/refbase.h"
28 #ifdef SUPPORT_GRAPHICS
29 #include "core/common/container_scope.h"
30 #endif
31 #include "declarative_module_preloader.h"
32 #include "extractor.h"
33 #include "foundation/bundlemanager/bundle_framework/interfaces/inner_api/appexecfwk_base/include/bundle_info.h"
34 #include "foundation/bundlemanager/bundle_framework/interfaces/inner_api/appexecfwk_core/include/bundlemgr/bundle_mgr_proxy.h"
35 #include "foundation/systemabilitymgr/samgr/interfaces/innerkits/samgr_proxy/include/iservice_registry.h"
36 #include "foundation/communication/ipc/interfaces/innerkits/ipc_core/include/iremote_object.h"
37 #include "singleton.h"
38 #include "system_ability_definition.h"
39 #include "hilog_wrapper.h"
40 #include "js_runtime_utils.h"
41 #include "native_engine/impl/ark/ark_native_engine.h"
42 #include "commonlibrary/ets_utils/js_sys_module/console/console.h"
43 #ifdef SUPPORT_GRAPHICS
44 using OHOS::Ace::ContainerScope;
45 #endif
46
47 namespace OHOS {
48 namespace AbilityRuntime {
49 namespace {
50 constexpr int64_t ASSET_FILE_MAX_SIZE = 32 * 1024 * 1024;
51 const std::string BUNDLE_NAME_FLAG = "@bundle:";
52 const std::string CACHE_DIRECTORY = "el2";
53 const int PATH_THREE = 3;
54 #ifdef APP_USE_ARM
55 constexpr char ARK_DEBUGGER_LIB_PATH[] = "/system/lib/libark_debugger.z.so";
56 #elif defined(APP_USE_X86_64)
57 constexpr char ARK_DEBUGGER_LIB_PATH[] = "/system/lib64/libark_debugger.z.so";
58 #else
59 constexpr char ARK_DEBUGGER_LIB_PATH[] = "/system/lib64/libark_debugger.z.so";
60 #endif
61
62 bool g_debugMode = false;
63 bool g_debugApp = false;
64 bool g_jsFramework = false;
65 std::mutex g_mutex;
66 }
67
InitWorkerFunc(NativeEngine * nativeEngine)68 void InitWorkerFunc(NativeEngine* nativeEngine)
69 {
70 HILOG_DEBUG("called");
71 if (nativeEngine == nullptr) {
72 HILOG_ERROR("Input nativeEngine is nullptr");
73 return;
74 }
75
76 napi_value globalObj = nullptr;
77 napi_get_global(reinterpret_cast<napi_env>(nativeEngine), &globalObj);
78 if (globalObj == nullptr) {
79 HILOG_ERROR("Failed to get global object");
80 return;
81 }
82
83 OHOS::JsSysModule::Console::InitConsoleModule(reinterpret_cast<napi_env>(nativeEngine));
84 OHOS::Ace::DeclarativeModulePreloader::PreloadWorker(*nativeEngine);
85
86 auto arkNativeEngine = static_cast<ArkNativeEngine*>(nativeEngine);
87 // load jsfwk
88 if (g_jsFramework && !arkNativeEngine->ExecuteJsBin("/system/etc/strip.native.min.abc")) {
89 HILOG_ERROR("Failed to load js framework!");
90 }
91
92 if (g_debugMode) {
93 auto instanceId = gettid();
94 std::string instanceName = "workerThread_" + std::to_string(instanceId);
95 bool needBreakPoint = ConnectServerManager::Get().AddInstance(instanceId, instanceName, true);
96 auto workerPostTask = [nativeEngine](std::function<void()>&& callback) {
97 nativeEngine->CallDebuggerPostTaskFunc(std::move(callback));
98 };
99 panda::JSNApi::DebugOption debugOption = {ARK_DEBUGGER_LIB_PATH, needBreakPoint};
100 auto vm = const_cast<EcmaVM*>(arkNativeEngine->GetEcmaVm());
101 ConnectServerManager::Get().StoreDebuggerInfo(
102 instanceId, reinterpret_cast<void*>(vm), debugOption, workerPostTask, g_debugApp);
103
104 panda::JSNApi::NotifyDebugMode(instanceId, vm, debugOption, instanceId, workerPostTask, g_debugApp);
105 }
106 }
107
OffWorkerFunc(NativeEngine * nativeEngine)108 void OffWorkerFunc(NativeEngine* nativeEngine)
109 {
110 HILOG_DEBUG("OffWorkerFunc called");
111 if (nativeEngine == nullptr) {
112 HILOG_ERROR("Input nativeEngine is nullptr");
113 return;
114 }
115
116 if (g_debugMode) {
117 auto instanceId = gettid();
118 ConnectServerManager::Get().RemoveInstance(instanceId);
119 auto arkNativeEngine = static_cast<ArkNativeEngine*>(nativeEngine);
120 auto vm = const_cast<EcmaVM*>(arkNativeEngine->GetEcmaVm());
121 panda::JSNApi::StopDebugger(vm);
122 }
123 }
124
125
126 using Extractor = AbilityBase::Extractor;
127 using ExtractorUtil = AbilityBase::ExtractorUtil;
128 using IBundleMgr = AppExecFwk::IBundleMgr;
129
NormalizedFileName(const std::string & fileName) const130 std::string AssetHelper::NormalizedFileName(const std::string& fileName) const
131 {
132 std::string normalizedFilePath;
133 size_t index = 0;
134 index = fileName.find_last_of(".");
135 // 1.1 end with file name
136 // 1.2 end with file name and file type
137 if (index == std::string::npos) {
138 HILOG_DEBUG("uri end without file type");
139 normalizedFilePath = fileName + ".abc";
140 } else {
141 HILOG_DEBUG("uri end with file type");
142 normalizedFilePath = fileName.substr(0, index) + ".abc";
143 }
144 return normalizedFilePath;
145 }
146
operator ()(const std::string & uri,std::vector<uint8_t> & content,std::string & ami)147 void AssetHelper::operator()(const std::string& uri, std::vector<uint8_t>& content, std::string &ami)
148 {
149 if (uri.empty() || workerInfo_ == nullptr) {
150 HILOG_ERROR("Uri is empty.");
151 return;
152 }
153
154 HILOG_DEBUG("RegisterAssetFunc called, uri: %{private}s", uri.c_str());
155 std::string realPath;
156 std::string filePath;
157
158 // 1. compilemode is jsbundle
159 // 2. compilemode is esmodule
160 if (workerInfo_->isBundle) {
161 // the @bundle:bundlename/modulename only exist in esmodule.
162 // 1.1 start with /modulename
163 // 1.2 start with ../
164 // 1.3 start with @namespace [not support]
165 // 1.4 start with modulename
166 HILOG_DEBUG("The application is packaged using jsbundle mode.");
167 if (uri.find_first_of("/") == 0) {
168 HILOG_DEBUG("uri start with /modulename");
169 realPath = uri.substr(1);
170 } else if (uri.find("../") == 0 && !workerInfo_->isStageModel) {
171 HILOG_DEBUG("uri start with ../");
172 realPath = uri.substr(PATH_THREE);
173 } else if (uri.find_first_of("@") == 0) {
174 HILOG_DEBUG("uri start with @namespace");
175 realPath = uri.substr(uri.find_first_of("/") + 1);
176 } else {
177 HILOG_DEBUG("uri start with modulename");
178 realPath = uri;
179 }
180
181 filePath = NormalizedFileName(realPath);
182 HILOG_INFO("filePath %{private}s", filePath.c_str());
183
184 if (!workerInfo_->isStageModel) {
185 GetAmi(ami, filePath);
186 } else {
187 ami = workerInfo_->codePath + filePath;
188 }
189
190 HILOG_DEBUG("Get asset, ami: %{private}s", ami.c_str());
191 if (ami.find(CACHE_DIRECTORY) != std::string::npos) {
192 if (!ReadAmiData(ami, content)) {
193 HILOG_ERROR("Get asset content by ami failed.");
194 }
195 } else if (!ReadFilePathData(filePath, content)) {
196 HILOG_ERROR("Get asset content by filepath failed.");
197 }
198 } else {
199 // 2.1 start with @bundle:bundlename/modulename
200 // 2.2 start with /modulename
201 // 2.3 start with @namespace
202 // 2.4 start with modulename
203 HILOG_DEBUG("The application is packaged using esmodule mode.");
204 if (uri.find(BUNDLE_NAME_FLAG) == 0) {
205 HILOG_DEBUG("uri start with @bundle:");
206 size_t fileNamePos = uri.find_last_of("/");
207 realPath = uri.substr(fileNamePos + 1);
208 if (realPath.find_last_of(".") != std::string::npos) {
209 ami = NormalizedFileName(uri);
210 } else {
211 ami = uri;
212 }
213 HILOG_DEBUG("Get asset, ami: %{private}s", ami.c_str());
214 return;
215 } else if (uri.find_first_of("/") == 0) {
216 HILOG_DEBUG("uri start with /modulename");
217 realPath = uri.substr(1);
218 } else if (uri.find_first_of("@") == 0) {
219 HILOG_DEBUG("uri start with @namespace");
220 realPath = workerInfo_->moduleName + uri;
221 } else {
222 HILOG_DEBUG("uri start with modulename");
223 realPath = uri;
224 }
225
226 filePath = NormalizedFileName(realPath);
227 ami = workerInfo_->codePath + filePath;
228 HILOG_DEBUG("Get asset, ami: %{private}s", ami.c_str());
229 if (ami.find(CACHE_DIRECTORY) != std::string::npos) {
230 if (!ReadAmiData(ami, content)) {
231 HILOG_ERROR("Get asset content by ami failed.");
232 }
233 } else if (!ReadFilePathData(filePath, content)) {
234 HILOG_ERROR("Get asset content by filepath failed.");
235 }
236 }
237 }
238
ReadAmiData(const std::string & ami,std::vector<uint8_t> & content) const239 bool AssetHelper::ReadAmiData(const std::string& ami, std::vector<uint8_t>& content) const
240 {
241 char path[PATH_MAX];
242 if (realpath(ami.c_str(), path) == nullptr) {
243 HILOG_ERROR("ReadAmiData realpath(%{private}s) failed, errno = %{public}d", ami.c_str(), errno);
244 return false;
245 }
246
247 std::ifstream stream(path, std::ios::binary | std::ios::ate);
248 if (!stream.is_open()) {
249 HILOG_ERROR("ReadAmiData failed to open file %{private}s", ami.c_str());
250 return false;
251 }
252
253 auto fileLen = stream.tellg();
254 if (!workerInfo_->isDebugVersion && fileLen > ASSET_FILE_MAX_SIZE) {
255 HILOG_ERROR("ReadAmiData failed, file is too large");
256 return false;
257 }
258
259 content.resize(fileLen);
260
261 stream.seekg(0);
262 stream.read(reinterpret_cast<char*>(content.data()), content.size());
263 return true;
264 }
265
ReadFilePathData(const std::string & filePath,std::vector<uint8_t> & content)266 bool AssetHelper::ReadFilePathData(const std::string& filePath, std::vector<uint8_t>& content)
267 {
268 auto bundleMgrHelper = DelayedSingleton<AppExecFwk::BundleMgrHelper>::GetInstance();
269 if (bundleMgrHelper == nullptr) {
270 HILOG_ERROR("The bundleMgrHelper is nullptr.");
271 return false;
272 }
273
274 AppExecFwk::BundleInfo bundleInfo;
275 auto getInfoResult = bundleMgrHelper->GetBundleInfoForSelf(
276 static_cast<int32_t>(AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_HAP_MODULE), bundleInfo);
277 if (getInfoResult != 0) {
278 HILOG_ERROR("GetBundleInfoForSelf failed.");
279 return false;
280 }
281 if (bundleInfo.hapModuleInfos.size() == 0) {
282 HILOG_ERROR("Get hapModuleInfo of bundleInfo failed.");
283 return false;
284 }
285
286 std::string newHapPath;
287 size_t pos = filePath.find('/');
288 if (!workerInfo_->isStageModel) {
289 newHapPath = workerInfo_->hapPath;
290 } else {
291 for (auto hapModuleInfo : bundleInfo.hapModuleInfos) {
292 if (hapModuleInfo.moduleName == filePath.substr(0, pos)) {
293 newHapPath = hapModuleInfo.hapPath;
294 break;
295 }
296 }
297 }
298 HILOG_DEBUG("HapPath: %{private}s", newHapPath.c_str());
299 bool newCreate = false;
300 std::string loadPath = ExtractorUtil::GetLoadFilePath(newHapPath);
301 std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(loadPath, newCreate);
302 if (extractor == nullptr) {
303 HILOG_ERROR("LoadPath %{private}s GetExtractor failed", loadPath.c_str());
304 return false;
305 }
306 std::unique_ptr<uint8_t[]> dataPtr = nullptr;
307 std::string realfilePath;
308 size_t fileLen = 0;
309 if (!workerInfo_->isStageModel) {
310 bool flag = false;
311 for (const auto& basePath : workerInfo_->assetBasePathStr) {
312 realfilePath = basePath + filePath;
313 HILOG_DEBUG("realfilePath: %{private}s", realfilePath.c_str());
314 if (extractor->ExtractToBufByName(realfilePath, dataPtr, fileLen)) {
315 flag = true;
316 break;
317 }
318 }
319 if (!flag) {
320 HILOG_ERROR("ExtractToBufByName error");
321 return flag;
322 }
323 } else {
324 realfilePath = filePath.substr(pos + 1);
325 HILOG_DEBUG("realfilePath: %{private}s", realfilePath.c_str());
326 if (!extractor->ExtractToBufByName(realfilePath, dataPtr, fileLen)) {
327 HILOG_ERROR("get mergeAbc fileBuffer failed");
328 return false;
329 }
330 }
331
332 if (!workerInfo_->isDebugVersion && fileLen > ASSET_FILE_MAX_SIZE) {
333 HILOG_ERROR("ReadFilePathData failed, file is too large");
334 return false;
335 }
336 content.assign(dataPtr.get(), dataPtr.get() + fileLen);
337 return true;
338 }
339
GetAmi(std::string & ami,const std::string & filePath)340 void AssetHelper::GetAmi(std::string& ami, const std::string& filePath)
341 {
342 size_t slashPos = filePath.find_last_of("/");
343 std::string fileName = filePath.substr(slashPos + 1);
344 std::string path = filePath.substr(0, slashPos + 1);
345
346 std::string loadPath = ExtractorUtil::GetLoadFilePath(workerInfo_->hapPath);
347 bool newCreate = false;
348 std::shared_ptr<Extractor> extractor = ExtractorUtil::GetExtractor(loadPath, newCreate);
349 if (extractor == nullptr) {
350 HILOG_ERROR("loadPath %{private}s GetExtractor failed", loadPath.c_str());
351 return;
352 }
353 std::vector<std::string> files;
354 for (const auto& basePath : workerInfo_->assetBasePathStr) {
355 std::string assetPath = basePath + path;
356 HILOG_INFO("assetPath: %{private}s", assetPath.c_str());
357 bool res = extractor->IsDirExist(assetPath);
358 if (!res) {
359 continue;
360 }
361 res = extractor->GetFileList(assetPath, files);
362 if (!res) {
363 continue;
364 }
365 }
366
367 std::string targetFilePath;
368 bool flag = false;
369 for (const auto& file : files) {
370 size_t filePos = file.find_last_of("/");
371 if (filePos != std::string::npos) {
372 if (file.substr(filePos + 1) == fileName) {
373 targetFilePath = path + fileName;
374 flag = true;
375 break;
376 }
377 }
378 }
379
380 HILOG_INFO("targetFilePath %{public}s", targetFilePath.c_str());
381
382 if (!flag) {
383 HILOG_ERROR("get targetFilePath failed!");
384 return;
385 }
386
387 for (const auto& basePath : workerInfo_->assetBasePathStr) {
388 std::string filePathName = basePath + targetFilePath;
389 bool hasFile = extractor->HasEntry(filePathName);
390 if (hasFile) {
391 ami = workerInfo_->hapPath + "/" + filePathName;
392 return;
393 }
394 }
395 }
396
GetContainerId()397 int32_t GetContainerId()
398 {
399 #ifdef SUPPORT_GRAPHICS
400 int32_t scopeId = ContainerScope::CurrentId();
401 return scopeId;
402 #else
403 constexpr int32_t containerScopeDefaultId = 0;
404 return containerScopeDefaultId;
405 #endif
406 }
UpdateContainerScope(int32_t id)407 void UpdateContainerScope(int32_t id)
408 {
409 #ifdef SUPPORT_GRAPHICS
410 ContainerScope::UpdateCurrent(id);
411 #endif
412 }
RestoreContainerScope(int32_t id)413 void RestoreContainerScope(int32_t id)
414 {
415 #ifdef SUPPORT_GRAPHICS
416 ContainerScope::UpdateCurrent(-1);
417 #endif
418 }
419
StartDebuggerInWorkerModule()420 void StartDebuggerInWorkerModule()
421 {
422 g_debugMode = true;
423 }
424
SetDebuggerApp(bool isDebugApp)425 void SetDebuggerApp(bool isDebugApp)
426 {
427 g_debugApp = isDebugApp;
428 }
429
SetJsFramework()430 void SetJsFramework()
431 {
432 g_jsFramework = true;
433 }
434 } // namespace AbilityRuntime
435 } // namespace OHOS
436