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