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