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