1 /*
2 * Copyright (c) 2022-2025 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 "simulator.h"
17
18 #include <condition_variable>
19 #include <fstream>
20 #include <functional>
21 #include <mutex>
22 #include <thread>
23 #include <unordered_map>
24
25 #include "ability_context.h"
26 #include "ability_stage_context.h"
27 #include "bundle_container.h"
28 #include "console.h"
29 #include "declarative_module_preloader.h"
30 #include "hilog_tag_wrapper.h"
31 #include "js_ability_context.h"
32 #include "js_ability_stage_context.h"
33 #include "js_console_log.h"
34 #include "js_data_converter.h"
35 #include "js_module_searcher.h"
36 #include "js_runtime.h"
37 #include "js_runtime_utils.h"
38 #include "js_timer.h"
39 #include "js_window_stage.h"
40 #include "json_serializer.h"
41 #include "JsMockUtil.h"
42 #include "launch_param.h"
43 #include "native_engine/impl/ark/ark_native_engine.h"
44 #include "res_config.h"
45 #include "resource_manager_helper.h"
46 #include "resource_manager.h"
47 #include "window_scene.h"
48 #include "sys_timer.h"
49 #include "source_map.h"
50
51
52 namespace OHOS {
53 namespace AbilityRuntime {
54 namespace {
55 constexpr int64_t DEFAULT_GC_POOL_SIZE = 0x10000000; // 256MB
56 constexpr int32_t DEFAULT_ARK_PROPERTIES = -1;
57 constexpr size_t DEFAULT_GC_THREAD_NUM = 7;
58 constexpr size_t DEFAULT_LONG_PAUSE_TIME = 40;
59
60 constexpr char BUNDLE_INSTALL_PATH[] = "/data/storage/el1/bundle/";
61 constexpr char MERGE_ABC_PATH[] = "/ets/modules.abc";
62 constexpr char SOURCE_MAPS_PATH[] = "/ets/sourceMaps.map";
63 const std::string PACKAGE_NAME = "packageName";
64 const std::string BUNDLE_NAME = "bundleName";
65 const std::string MODULE_NAME = "moduleName";
66 const std::string VERSION = "version";
67 const std::string ENTRY_PATH = "entryPath";
68 const std::string IS_SO = "isSO";
69 const std::string DEPENDENCY_ALIAS = "dependencyAlias";
70
71 #if defined(WINDOWS_PLATFORM)
72 constexpr char ARK_DEBUGGER_LIB_PATH[] = "libark_inspector.dll";
73 #elif defined(MAC_PLATFORM)
74 constexpr char ARK_DEBUGGER_LIB_PATH[] = "libark_inspector.dylib";
75 #else
76 #error "Unsupported platform"
77 #endif
78
PrintVmLog(int32_t,int32_t,const char *,const char *,const char * message)79 int32_t PrintVmLog(int32_t, int32_t, const char*, const char*, const char *message)
80 {
81 TAG_LOGD(AAFwkTag::ABILITY_SIM, "ArkLog:%{public}s", message);
82 return 0;
83 }
84
85 template<typename T, size_t N>
ArraySize(T (&)[N])86 inline constexpr size_t ArraySize(T (&)[N]) noexcept
87 {
88 return N;
89 }
90
91 struct DebuggerTask {
92 void OnPostTask(std::function<void()> &&task);
93
94 static void HandleTask(const uv_async_t *req);
95
96 uv_async_t onPostTaskSignal {};
97 std::function<void()> func;
98 };
99
100 class SimulatorImpl : public Simulator, public std::enable_shared_from_this<SimulatorImpl> {
101 public:
102 SimulatorImpl() = default;
103 ~SimulatorImpl();
104
105 bool Initialize(const Options &options);
106
107 int64_t StartAbility(
108 const std::string &abilitySrcPath, TerminateCallback callback, const std::string &abilityName = "") override;
109 void TerminateAbility(int64_t abilityId) override;
110 void UpdateConfiguration(const AppExecFwk::Configuration &config) override;
111 void SetMockList(const std::map<std::string, std::string> &mockList) override;
112 void SetHostResolveBufferTracker(ResolveBufferTrackerCallback cb) override;
113 private:
114 bool OnInit();
115 void Run();
116 napi_value LoadScript(const std::string &srcPath);
117 void InitResourceMgr();
118 void InitJsAbilityContext(napi_env env, napi_value instanceValue);
119 void DispatchStartLifecycle(napi_value instanceValue);
120 std::unique_ptr<NativeReference> CreateJsWindowStage(const std::shared_ptr<Rosen::WindowScene> &windowScene);
121 napi_value CreateJsWant(napi_env env);
122 bool LoadAbilityStage(uint8_t *buffer, size_t len);
123 void InitJsAbilityStageContext(napi_value instanceValue);
124 napi_value CreateJsLaunchParam(napi_env env);
125 bool ParseBundleAndModuleInfo();
126 bool ParseAbilityInfo(const std::string &abilitySrcPath, const std::string &abilityName = "");
127 bool LoadRuntimeEnv(napi_env env, napi_value globalObject);
128 static napi_value RequireNapi(napi_env env, napi_callback_info info);
129 inline void SetHostResolveBufferTracker();
130 void LoadJsMock(const std::string &fileName);
131 void ReportJsError(napi_value obj);
132 std::string GetNativeStrFromJsTaggedObj(napi_value obj, const char* key);
133 void CreateStageContext();
134 std::string ReadSourceMap();
135
136 panda::ecmascript::EcmaVM *CreateJSVM();
137 Options options_;
138 std::string abilityPath_;
139 panda::ecmascript::EcmaVM *vm_ = nullptr;
140 DebuggerTask debuggerTask_;
141 napi_env nativeEngine_ = nullptr;
142 TerminateCallback terminateCallback_;
143 bool isOhmUrl_ = false;
144
145 int64_t currentId_ = 0;
146 std::unordered_map<int64_t, std::shared_ptr<NativeReference>> abilities_;
147 std::unordered_map<int64_t, std::shared_ptr<Rosen::WindowScene>> windowScenes_;
148 std::unordered_map<int64_t, std::shared_ptr<NativeReference>> jsWindowStages_;
149 std::unordered_map<int64_t, std::shared_ptr<NativeReference>> jsContexts_;
150 std::shared_ptr<Global::Resource::ResourceManager> resourceMgr_;
151 std::shared_ptr<AbilityContext> context_;
152 std::shared_ptr<NativeReference> abilityStage_;
153 std::shared_ptr<AbilityStageContext> stageContext_;
154 std::shared_ptr<NativeReference> jsStageContext_;
155 std::shared_ptr<AppExecFwk::ApplicationInfo> appInfo_;
156 std::shared_ptr<AppExecFwk::HapModuleInfo> moduleInfo_;
157 std::shared_ptr<AppExecFwk::AbilityInfo> abilityInfo_;
158 std::shared_ptr<JsEnv::SourceMap> sourceMapPtr_;
159 CallbackTypePostTask postTask_ = nullptr;
160 void GetPkgContextInfoListMap(const std::map<std::string, std::string> &contextInfoMap,
161 std::map<std::string, std::vector<std::vector<std::string>>> &pkgContextInfoMap,
162 std::map<std::string, std::string> &pkgAliasMap);
163 void GetPkgContextInfoListInner(nlohmann::json &itemObject, std::vector<std::string> &items,
164 std::map<std::string, std::string> &pkgAliasMap, std::string &pkgName);
165 };
166
HandleTask(const uv_async_t * req)167 void DebuggerTask::HandleTask(const uv_async_t *req)
168 {
169 auto *debuggerTask = reinterpret_cast<DebuggerTask*>(req->data);
170 if (debuggerTask == nullptr) {
171 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null HandleTask debuggerTask");
172 return;
173 }
174 debuggerTask->func();
175 }
176
OnPostTask(std::function<void ()> && task)177 void DebuggerTask::OnPostTask(std::function<void()> &&task)
178 {
179 if (uv_is_active((uv_handle_t*)&onPostTaskSignal)) {
180 func = std::move(task);
181 onPostTaskSignal.data = static_cast<void*>(this);
182 uv_async_send(&onPostTaskSignal);
183 }
184 }
185
~SimulatorImpl()186 SimulatorImpl::~SimulatorImpl()
187 {
188 if (context_ != nullptr) {
189 context_->Unbind();
190 }
191 if (stageContext_ != nullptr) {
192 stageContext_->Unbind();
193 }
194 if (nativeEngine_) {
195 uv_close(reinterpret_cast<uv_handle_t*>(&debuggerTask_.onPostTaskSignal), nullptr);
196 uv_loop_t* uvLoop = nullptr;
197 napi_get_uv_event_loop(nativeEngine_, &uvLoop);
198 if (uvLoop != nullptr) {
199 uv_work_t work;
200 uv_queue_work(uvLoop, &work, [](uv_work_t*) {}, [](uv_work_t *work, int32_t status) {
201 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Simulator stop uv loop");
202 uv_stop(work->loop);
203 });
204 }
205 }
206
207 panda::JSNApi::StopDebugger(vm_);
208
209 abilities_.clear();
210 nativeEngine_ = nullptr;
211 panda::JSNApi::DestroyJSVM(vm_);
212 vm_ = nullptr;
213 }
214
Initialize(const Options & options)215 bool SimulatorImpl::Initialize(const Options &options)
216 {
217 if (nativeEngine_) {
218 TAG_LOGE(AAFwkTag::ABILITY_SIM, "initialized");
219 return true;
220 }
221
222 options_ = options;
223 sourceMapPtr_ = std::make_shared<JsEnv::SourceMap>();
224 auto content = ReadSourceMap();
225 sourceMapPtr_->SplitSourceMap(content);
226
227 postTask_ = options.postTask;
228 if (!OnInit()) {
229 return false;
230 }
231
232 uv_loop_t* uvLoop = nullptr;
233 napi_get_uv_event_loop(nativeEngine_, &uvLoop);
234 if (uvLoop == nullptr) {
235 return false;
236 }
237
238 uv_async_init(uvLoop, &debuggerTask_.onPostTaskSignal,
239 reinterpret_cast<uv_async_cb>(DebuggerTask::HandleTask));
240
241 Run();
242 return true;
243 }
244
CallObjectMethod(napi_env env,napi_value obj,const char * name,napi_value const * argv,size_t argc)245 void CallObjectMethod(napi_env env, napi_value obj, const char *name, napi_value const *argv, size_t argc)
246 {
247 if (obj == nullptr) {
248 TAG_LOGE(AAFwkTag::ABILITY_SIM, "get Ability object failed");
249 return;
250 }
251 napi_value methodOnCreate = nullptr;
252 napi_get_named_property(env, obj, name, &methodOnCreate);
253 if (methodOnCreate == nullptr) {
254 TAG_LOGE(AAFwkTag::ABILITY_SIM, "get '%{public}s' failed", name);
255 return;
256 }
257 napi_status status = napi_call_function(env, obj, methodOnCreate, argc, argv, nullptr);
258 if (status != napi_ok) {
259 TAG_LOGE(AAFwkTag::ABILITY_SIM, "napi call function failed");
260 }
261 }
262
LoadScript(const std::string & srcPath)263 napi_value SimulatorImpl::LoadScript(const std::string &srcPath)
264 {
265 panda::Local<panda::ObjectRef> objRef;
266 if (isOhmUrl_) {
267 objRef = panda::JSNApi::GetExportObjectFromOhmUrl(vm_, srcPath, "default");
268 } else {
269 objRef = panda::JSNApi::GetExportObject(vm_, srcPath, "default");
270 }
271
272 if (objRef->IsNull()) {
273 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Get export object failed");
274 return nullptr;
275 }
276
277 auto obj = ArkNativeEngine::ArkValueToNapiValue(nativeEngine_, objRef);
278 napi_value instanceValue = nullptr;
279 napi_new_instance(nativeEngine_, obj, 0, nullptr, &instanceValue);
280 return instanceValue;
281 }
282
ParseBundleAndModuleInfo()283 bool SimulatorImpl::ParseBundleAndModuleInfo()
284 {
285 AppExecFwk::BundleContainer::GetInstance().LoadBundleInfos(options_.moduleJsonBuffer, options_.resourcePath);
286 appInfo_ = AppExecFwk::BundleContainer::GetInstance().GetApplicationInfo();
287 if (appInfo_ == nullptr) {
288 TAG_LOGE(AAFwkTag::ABILITY_SIM, "appinfo parse failed");
289 return false;
290 }
291 nlohmann::json appInfoJson;
292 to_json(appInfoJson, *appInfo_);
293 std::cout << "appinfo : " << appInfoJson.dump() << std::endl;
294
295 AppExecFwk::BundleContainer::GetInstance().LoadDependencyHspInfo(appInfo_->bundleName, options_.dependencyHspInfos);
296 AppExecFwk::BundleContainer::GetInstance().SetBundleCodeDir(options_.previewPath);
297
298 options_.bundleName = appInfo_->bundleName;
299 options_.compatibleVersion = appInfo_->apiCompatibleVersion;
300 options_.installationFree = (appInfo_->bundleType == AppExecFwk::BundleType::ATOMIC_SERVICE ? true : false);
301 options_.targetVersion = appInfo_->apiTargetVersion;
302 options_.releaseType = appInfo_->apiReleaseType;
303 options_.compileMode = "esmodule";
304
305 if (appInfo_->moduleInfos.empty()) {
306 TAG_LOGE(AAFwkTag::ABILITY_SIM, "module name not exist");
307 return false;
308 }
309 options_.moduleName = appInfo_->moduleInfos[0].moduleName;
310 std::cout << "module name is " << options_.moduleName << std::endl;
311
312 moduleInfo_ = AppExecFwk::BundleContainer::GetInstance().GetHapModuleInfo(options_.moduleName);
313 if (moduleInfo_ == nullptr) {
314 TAG_LOGE(AAFwkTag::ABILITY_SIM, "module info parse failed");
315 return false;
316 }
317 nlohmann::json moduleInfoJson;
318 to_json(moduleInfoJson, *moduleInfo_);
319 std::cout << "moduleInfo : " << moduleInfoJson.dump() << std::endl;
320
321 options_.pageProfile = moduleInfo_->pages;
322 options_.enablePartialUpdate = true;
323 for (auto iter : moduleInfo_->metadata) {
324 if (iter.name == "ArkTSPartialUpdate" && iter.value == "false") {
325 options_.enablePartialUpdate = false;
326 break;
327 }
328 }
329 return true;
330 }
331
ParseAbilityInfo(const std::string & abilitySrcPath,const std::string & abilityName)332 bool SimulatorImpl::ParseAbilityInfo(const std::string &abilitySrcPath, const std::string &abilityName)
333 {
334 if (!abilityName.empty()) {
335 abilityInfo_ = AppExecFwk::BundleContainer::GetInstance().GetAbilityInfo(options_.moduleName, abilityName);
336 } else {
337 auto path = abilitySrcPath;
338 path.erase(path.rfind("."));
339 auto abilityNameFromPath = path.substr(path.rfind('/') + 1, path.length());
340 abilityInfo_ = AppExecFwk::BundleContainer::GetInstance().GetAbilityInfo(
341 options_.moduleName, abilityNameFromPath);
342 }
343
344 if (abilityInfo_ == nullptr) {
345 TAG_LOGE(AAFwkTag::ABILITY_SIM, "ability info parse failed");
346 return false;
347 }
348 nlohmann::json json;
349 to_json(json, *abilityInfo_);
350 std::cout << "abilityInfo : " << json.dump() << std::endl;
351
352 options_.labelId = abilityInfo_->labelId;
353 return true;
354 }
355
StartAbility(const std::string & abilitySrcPath,TerminateCallback callback,const std::string & abilityName)356 int64_t SimulatorImpl::StartAbility(
357 const std::string &abilitySrcPath, TerminateCallback callback, const std::string &abilityName)
358 {
359 if (!ParseAbilityInfo(abilitySrcPath, abilityName)) {
360 return -1;
361 }
362
363 CreateStageContext();
364 std::ifstream stream(options_.modulePath, std::ios::ate | std::ios::binary);
365 if (!stream.is_open()) {
366 TAG_LOGE(AAFwkTag::ABILITY_SIM, "open:%{public}s failed", options_.modulePath.c_str());
367 return -1;
368 }
369
370 size_t len = stream.tellg();
371 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(len);
372 stream.seekg(0);
373 stream.read(reinterpret_cast<char*>(buffer.get()), len);
374 stream.close();
375
376 auto buf = buffer.release();
377 if (!LoadAbilityStage(buf, len)) {
378 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Load ability stage failed");
379 return -1;
380 }
381
382 isOhmUrl_ = panda::JSNApi::IsOhmUrl(abilitySrcPath);
383 napi_value instanceValue = nullptr;
384 if (isOhmUrl_) {
385 std::string srcFilename = "";
386 srcFilename = BUNDLE_INSTALL_PATH + options_.moduleName + MERGE_ABC_PATH;
387 if (!panda::JSNApi::ExecuteSecureWithOhmUrl(vm_, buf, len, srcFilename, abilitySrcPath)) {
388 return -1;
389 }
390 instanceValue = LoadScript(abilitySrcPath);
391 } else {
392 abilityPath_ = BUNDLE_INSTALL_PATH + options_.moduleName + "/" + abilitySrcPath;
393 if (!reinterpret_cast<NativeEngine*>(nativeEngine_)->RunScriptBuffer(abilityPath_, buf, len, false)) {
394 TAG_LOGE(AAFwkTag::ABILITY_SIM, "run script:%{public}s failed", abilityPath_.c_str());
395 return -1;
396 }
397 instanceValue = LoadScript(abilityPath_);
398 }
399
400 if (instanceValue == nullptr) {
401 TAG_LOGE(AAFwkTag::ABILITY_SIM, "create object instance failed");
402 return -1;
403 }
404
405 ++currentId_;
406 terminateCallback_ = callback;
407 InitResourceMgr();
408 InitJsAbilityContext(nativeEngine_, instanceValue);
409 DispatchStartLifecycle(instanceValue);
410 napi_ref ref = nullptr;
411 napi_create_reference(nativeEngine_, instanceValue, 1, &ref);
412 abilities_.emplace(currentId_, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
413 return currentId_;
414 }
415
LoadAbilityStage(uint8_t * buffer,size_t len)416 bool SimulatorImpl::LoadAbilityStage(uint8_t *buffer, size_t len)
417 {
418 if (moduleInfo_ == nullptr) {
419 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null moduleInfo");
420 return false;
421 }
422
423 if (moduleInfo_->srcEntrance.empty()) {
424 TAG_LOGD(AAFwkTag::ABILITY_SIM, "module src path empty");
425 return true;
426 }
427
428 if (nativeEngine_ == nullptr) {
429 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null nativeEngine_");
430 return false;
431 }
432 std::string srcEntrance = moduleInfo_->srcEntrance;
433 srcEntrance.erase(srcEntrance.rfind("."));
434 srcEntrance.append(".abc");
435 srcEntrance = srcEntrance.substr(srcEntrance.find('/') + 1, srcEntrance.length());
436
437 auto moduleSrcPath = BUNDLE_INSTALL_PATH + options_.moduleName + "/" + srcEntrance;
438 TAG_LOGD(AAFwkTag::ABILITY_SIM, "moduleSrcPath is %{public}s", moduleSrcPath.c_str());
439 if (!reinterpret_cast<NativeEngine*>(nativeEngine_)->RunScriptBuffer(moduleSrcPath, buffer, len, false)) {
440 TAG_LOGE(AAFwkTag::ABILITY_SIM, "run ability stage script:%{public}s failed", moduleSrcPath.c_str());
441 return false;
442 }
443
444 napi_value instanceValue = LoadScript(moduleSrcPath);
445 if (instanceValue == nullptr) {
446 TAG_LOGE(AAFwkTag::ABILITY_SIM, "create ability stage instance failed");
447 return false;
448 }
449
450 InitJsAbilityStageContext(instanceValue);
451 CallObjectMethod(nativeEngine_, instanceValue, "onCreate", nullptr, 0);
452
453 napi_value wantArgv[] = {
454 CreateJsWant(nativeEngine_)
455 };
456 CallObjectMethod(nativeEngine_, instanceValue, "onAcceptWant", wantArgv, ArraySize(wantArgv));
457 napi_ref ref = nullptr;
458 napi_create_reference(nativeEngine_, instanceValue, 1, &ref);
459 abilityStage_ = std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref));
460 return true;
461 }
462
InitJsAbilityStageContext(napi_value obj)463 void SimulatorImpl::InitJsAbilityStageContext(napi_value obj)
464 {
465 napi_value contextObj = CreateJsAbilityStageContext(nativeEngine_, stageContext_);
466 if (contextObj == nullptr) {
467 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null contextObj");
468 return;
469 }
470
471 jsStageContext_ = std::shared_ptr<NativeReference>(
472 JsRuntime::LoadSystemModuleByEngine(nativeEngine_, "application.AbilityStageContext", &contextObj, 1));
473 if (jsStageContext_ == nullptr) {
474 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null get LoadSystemModuleByEngine failed");
475 return;
476 }
477
478 contextObj = jsStageContext_->GetNapiValue();
479 if (contextObj == nullptr) {
480 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null contextObj");
481 return;
482 }
483
484 if (obj == nullptr) {
485 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null obj");
486 return;
487 }
488
489 auto workContext = new (std::nothrow) std::weak_ptr<AbilityStageContext>(stageContext_);
490 auto status = napi_wrap(nativeEngine_, contextObj, workContext,
491 [](napi_env, void *data, void*) {
492 TAG_LOGD(AAFwkTag::ABILITY_SIM, "finalizer for weak_ptr ui ability context");
493 delete static_cast<std::weak_ptr<AbilityStageContext> *>(data);
494 },
495 nullptr, nullptr);
496 if (status != napi_ok) {
497 TAG_LOGW(AAFwkTag::ABILITY_SIM, "wrap ability context failed: %{public}d", status);
498 delete workContext;
499 return;
500 }
501
502 JsRuntime jsRuntime;
503 stageContext_->Bind(jsRuntime, jsStageContext_.get());
504 napi_set_named_property(nativeEngine_, obj, "context", contextObj);
505 }
506
TerminateAbility(int64_t abilityId)507 void SimulatorImpl::TerminateAbility(int64_t abilityId)
508 {
509 if (abilityId == 0 && abilities_.begin() != abilities_.end()) {
510 TerminateAbility(abilities_.begin()->first);
511 return;
512 }
513
514 auto it = abilities_.find(abilityId);
515 if (it == abilities_.end()) {
516 return;
517 }
518
519 std::shared_ptr<NativeReference> ref = it->second;
520 abilities_.erase(it);
521
522 auto instanceValue = ref->GetNapiValue();
523 if (instanceValue == nullptr) {
524 return;
525 }
526
527 CallObjectMethod(nativeEngine_, instanceValue, "onBackground", nullptr, 0);
528 CallObjectMethod(nativeEngine_, instanceValue, "onWindowStageDestroy", nullptr, 0);
529 CallObjectMethod(nativeEngine_, instanceValue, "onDestroy", nullptr, 0);
530
531 auto windowSceneIter = windowScenes_.find(abilityId);
532 if (windowSceneIter != windowScenes_.end()) {
533 windowScenes_.erase(windowSceneIter);
534 }
535
536 auto windowStageIter = jsWindowStages_.find(abilityId);
537 if (windowStageIter != jsWindowStages_.end()) {
538 jsWindowStages_.erase(windowStageIter);
539 }
540
541 auto jsContextIter = jsContexts_.find(abilityId);
542 if (jsContextIter != jsContexts_.end()) {
543 jsContexts_.erase(jsContextIter);
544 }
545 }
546
UpdateConfiguration(const AppExecFwk::Configuration & config)547 void SimulatorImpl::UpdateConfiguration(const AppExecFwk::Configuration &config)
548 {
549 TAG_LOGD(AAFwkTag::ABILITY_SIM, "called");
550 if (abilityStage_ == nullptr) {
551 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null abilityStage_");
552 return;
553 }
554
555 auto configuration = std::make_shared<AppExecFwk::Configuration>(config);
556 if (configuration == nullptr) {
557 return;
558 }
559
560 if (stageContext_) {
561 stageContext_->SetConfiguration(configuration);
562 }
563
564 napi_value configArgv[] = {
565 CreateJsConfiguration(nativeEngine_, config)
566 };
567
568 auto abilityStage = abilityStage_->GetNapiValue();
569 if (abilityStage == nullptr) {
570 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null abilityStage");
571 return;
572 }
573 CallObjectMethod(nativeEngine_, abilityStage, "onConfigurationUpdated", configArgv, ArraySize(configArgv));
574 CallObjectMethod(nativeEngine_, abilityStage, "onConfigurationUpdate", configArgv, ArraySize(configArgv));
575 JsAbilityStageContext::ConfigurationUpdated(nativeEngine_, jsStageContext_, configuration);
576
577 for (auto iter = abilities_.begin(); iter != abilities_.end(); iter++) {
578 auto ability = iter->second->GetNapiValue();
579 if (ability == nullptr) {
580 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null ability");
581 continue;
582 }
583
584 CallObjectMethod(nativeEngine_, ability, "onConfigurationUpdated", configArgv, ArraySize(configArgv));
585 CallObjectMethod(nativeEngine_, ability, "onConfigurationUpdate", configArgv, ArraySize(configArgv));
586 JsAbilityContext::ConfigurationUpdated(nativeEngine_, iter->second, configuration);
587 }
588 }
589
SetMockList(const std::map<std::string,std::string> & mockList)590 void SimulatorImpl::SetMockList(const std::map<std::string, std::string> &mockList)
591 {
592 TAG_LOGD(AAFwkTag::ABILITY_SIM, "called. mockList size: %{public}zu", mockList.size());
593 panda::JSNApi::SetMockModuleList(vm_, mockList);
594 }
595
InitResourceMgr()596 void SimulatorImpl::InitResourceMgr()
597 {
598 TAG_LOGD(AAFwkTag::ABILITY_SIM, "called");
599 resourceMgr_ = std::shared_ptr<Global::Resource::ResourceManager>(Global::Resource::CreateResourceManager());
600 if (resourceMgr_ == nullptr) {
601 TAG_LOGE(AAFwkTag::ABILITY_SIM, "resourceMgr");
602 return;
603 }
604
605 if (!resourceMgr_->AddResource(options_.resourcePath.c_str())) {
606 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Add app resource failed");
607 }
608 ResourceManagerHelper::GetInstance().Init(options_);
609 ResourceManagerHelper::GetInstance().AddSystemResource(resourceMgr_);
610 std::unique_ptr<Global::Resource::ResConfig> resConfig(Global::Resource::CreateResConfig());
611 if (resConfig == nullptr) {
612 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null resConfig");
613 return;
614 }
615 ResourceManagerHelper::GetInstance().GetResConfig(*resConfig);
616 resourceMgr_->UpdateResConfig(*resConfig);
617 }
618
InitJsAbilityContext(napi_env env,napi_value obj)619 void SimulatorImpl::InitJsAbilityContext(napi_env env, napi_value obj)
620 {
621 if (context_ == nullptr) {
622 context_ = std::make_shared<AbilityContext>();
623 context_->SetSimulator(static_cast<Simulator*>(this));
624 context_->SetOptions(options_);
625 context_->SetAbilityStageContext(stageContext_);
626 context_->SetResourceManager(resourceMgr_);
627 context_->SetAbilityInfo(abilityInfo_);
628 }
629 napi_value contextObj = CreateJsAbilityContext(nativeEngine_, context_);
630 auto systemModule = std::shared_ptr<NativeReference>(
631 JsRuntime::LoadSystemModuleByEngine(nativeEngine_, "application.AbilityContext", &contextObj, 1));
632 if (systemModule == nullptr) {
633 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null systemModule");
634 return;
635 }
636 contextObj = systemModule->GetNapiValue();
637 if (contextObj == nullptr) {
638 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null contextObj");
639 return;
640 }
641
642 if (obj == nullptr) {
643 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null obj");
644 return;
645 }
646
647 auto workContext = new (std::nothrow) std::weak_ptr<AbilityContext>(context_);
648 auto status = napi_wrap(nativeEngine_, contextObj, workContext,
649 [](napi_env, void *data, void*) {
650 TAG_LOGD(AAFwkTag::ABILITY_SIM, "finalizer for weak_ptr ui ability context");
651 delete static_cast<std::weak_ptr<AbilityContext> *>(data);
652 },
653 nullptr, nullptr);
654 if (status != napi_ok) {
655 TAG_LOGW(AAFwkTag::ABILITY_SIM, "wrap ability context failed: %{public}d", status);
656 delete workContext;
657 return;
658 }
659
660 JsRuntime jsRuntime;
661 context_->Bind(jsRuntime, systemModule.get());
662 napi_set_named_property(env, obj, "context", contextObj);
663 jsContexts_.emplace(currentId_, systemModule);
664 }
665
CreateJsWant(napi_env env)666 napi_value SimulatorImpl::CreateJsWant(napi_env env)
667 {
668 napi_value objValue = nullptr;
669 napi_create_object(env, &objValue);
670 napi_set_named_property(env, objValue, "deviceId", CreateJsValue(env, std::string("")));
671 napi_set_named_property(env, objValue, "bundleName", CreateJsValue(env, options_.bundleName));
672 if (abilityInfo_) {
673 napi_set_named_property(env, objValue, "abilityName", CreateJsValue(env, abilityInfo_->name));
674 }
675 napi_set_named_property(env, objValue, "moduleName", CreateJsValue(env, options_.moduleName));
676
677 napi_set_named_property(env, objValue, "uri", CreateJsValue(env, std::string("")));
678 napi_set_named_property(env, objValue, "type", CreateJsValue(env, std::string("")));
679 napi_set_named_property(env, objValue, "flags", CreateJsValue(env, 0));
680 napi_set_named_property(env, objValue, "type", CreateJsValue(env, std::string("")));
681 napi_value object = nullptr;
682 napi_create_object(env, &object);
683 napi_set_named_property(env, objValue, "parameters", object);
684 napi_value array = nullptr;
685 napi_create_array_with_length(env, 0, &array);
686 napi_set_named_property(env, objValue, "entities", array);
687 return objValue;
688 }
689
CreateJsLaunchParam(napi_env env)690 napi_value SimulatorImpl::CreateJsLaunchParam(napi_env env)
691 {
692 napi_value objValue = nullptr;
693 napi_create_object(env, &objValue);
694 napi_set_named_property(env, objValue, "launchReason", CreateJsValue(env, AAFwk::LAUNCHREASON_UNKNOWN));
695 napi_set_named_property(env, objValue, "lastExitReason", CreateJsValue(env, AAFwk::LASTEXITREASON_UNKNOWN));
696 napi_set_named_property(env, objValue, "lastExitMessage", CreateJsValue(env, std::string("")));
697 return objValue;
698 }
699
DispatchStartLifecycle(napi_value instanceValue)700 void SimulatorImpl::DispatchStartLifecycle(napi_value instanceValue)
701 {
702 napi_value wantArgv[] = {
703 CreateJsWant(nativeEngine_),
704 CreateJsLaunchParam(nativeEngine_)
705 };
706 CallObjectMethod(nativeEngine_, instanceValue, "onCreate", wantArgv, ArraySize(wantArgv));
707 auto windowScene = std::make_shared<Rosen::WindowScene>();
708 if (windowScene == nullptr) {
709 return;
710 }
711 sptr<Rosen::IWindowLifeCycle> listener = nullptr;
712 windowScene->Init(-1, context_, listener);
713 auto jsWindowStage = CreateJsWindowStage(windowScene);
714 if (jsWindowStage == nullptr) {
715 return;
716 }
717 napi_value argv[] = { jsWindowStage->GetNapiValue() };
718 CallObjectMethod(nativeEngine_, instanceValue, "onWindowStageCreate", argv, ArraySize(argv));
719
720 CallObjectMethod(nativeEngine_, instanceValue, "onForeground", nullptr, 0);
721
722 windowScenes_.emplace(currentId_, windowScene);
723 jsWindowStages_.emplace(currentId_, std::shared_ptr<NativeReference>(jsWindowStage.release()));
724 }
725
CreateJsWindowStage(const std::shared_ptr<Rosen::WindowScene> & windowScene)726 std::unique_ptr<NativeReference> SimulatorImpl::CreateJsWindowStage(
727 const std::shared_ptr<Rosen::WindowScene> &windowScene)
728 {
729 napi_value jsWindowStage = Rosen::CreateJsWindowStage(nativeEngine_, windowScene);
730 if (jsWindowStage == nullptr) {
731 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null jsWindowSatge");
732 return nullptr;
733 }
734 return JsRuntime::LoadSystemModuleByEngine(nativeEngine_, "application.WindowStage", &jsWindowStage, 1);
735 }
736
CreateJSVM()737 panda::ecmascript::EcmaVM *SimulatorImpl::CreateJSVM()
738 {
739 panda::RuntimeOption pandaOption;
740 pandaOption.SetArkProperties(DEFAULT_ARK_PROPERTIES);
741 pandaOption.SetGcThreadNum(DEFAULT_GC_THREAD_NUM);
742 pandaOption.SetLongPauseTime(DEFAULT_LONG_PAUSE_TIME);
743 pandaOption.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
744 pandaOption.SetGcPoolSize(DEFAULT_GC_POOL_SIZE);
745 pandaOption.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::FOLLOW);
746 pandaOption.SetLogBufPrint(PrintVmLog);
747 pandaOption.SetEnableAsmInterpreter(true);
748 pandaOption.SetAsmOpcodeDisableRange("");
749 return panda::JSNApi::CreateJSVM(pandaOption);
750 }
751
ReadSourceMap()752 std::string SimulatorImpl::ReadSourceMap()
753 {
754 std::string normalizedPath = options_.modulePath;
755 TAG_LOGD(AAFwkTag::ABILITY_SIM, "modulePath:%{public}s", normalizedPath.c_str());
756 std::replace(normalizedPath.begin(), normalizedPath.end(), '\\', '/');
757 auto sourceMapPath = std::regex_replace(normalizedPath, std::regex(MERGE_ABC_PATH), SOURCE_MAPS_PATH);
758 TAG_LOGD(AAFwkTag::ABILITY_SIM, "is mac sourceMapPath:%{public}s", sourceMapPath.c_str());
759
760 #if defined(WINDOWS_PLATFORM)
761 std::replace(sourceMapPath.begin(), sourceMapPath.end(), '/', '\\');
762 TAG_LOGD(AAFwkTag::ABILITY_SIM, "is windows sourceMapPath:%{public}s", sourceMapPath.c_str());
763 #endif
764 std::ifstream stream(sourceMapPath, std::ios::ate | std::ios::binary);
765 if (!stream.is_open()) {
766 TAG_LOGE(AAFwkTag::ABILITY_SIM, "open:%{public}s failed", sourceMapPath.c_str());
767 return "";
768 }
769
770 size_t len = stream.tellg();
771 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(len);
772 stream.seekg(0);
773 stream.read(reinterpret_cast<char*>(buffer.get()), len);
774 stream.close();
775 std::string content;
776 content.assign(reinterpret_cast<char*>(buffer.get()), len);
777 return content;
778 }
779
OnInit()780 bool SimulatorImpl::OnInit()
781 {
782 if (!ParseBundleAndModuleInfo()) {
783 TAG_LOGE(AAFwkTag::ABILITY_SIM, "failed");
784 return false;
785 }
786
787 vm_ = CreateJSVM();
788 if (vm_ == nullptr) {
789 return false;
790 }
791
792 panda::JSNApi::DebugOption debugOption = {ARK_DEBUGGER_LIB_PATH, (options_.debugPort != 0), options_.debugPort};
793 panda::JSNApi::StartDebugger(vm_, debugOption, 0, [this](std::function<void()> &&arg) {
794 debuggerTask_.OnPostTask(std::move(arg));
795 });
796
797 auto nativeEngine = new (std::nothrow) ArkNativeEngine(vm_, nullptr);
798 if (nativeEngine == nullptr) {
799 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null nativeEngine");
800 return false;
801 }
802 napi_env env = reinterpret_cast<napi_env>(nativeEngine);
803 auto uncaughtTask = [weak = weak_from_this()](napi_value value) {
804 TAG_LOGE(AAFwkTag::ABILITY_SIM, "uncaught exception");
805 auto self = weak.lock();
806 if (self == nullptr) {
807 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null SimulatorImpl");
808 return;
809 }
810 self->ReportJsError(value);
811 if (self->terminateCallback_ == nullptr) {
812 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null terminateCallback");
813 return;
814 }
815 self->terminateCallback_(self->currentId_);
816 };
817 nativeEngine->RegisterNapiUncaughtExceptionHandler(uncaughtTask);
818 Ace::DeclarativeModulePreloader::Preload(*nativeEngine);
819
820 napi_value globalObj;
821 napi_get_global(env, &globalObj);
822 if (globalObj == nullptr) {
823 delete nativeEngine;
824 TAG_LOGE(AAFwkTag::ABILITY_SIM, "null global object");
825 return false;
826 }
827
828 #if defined(PREVIEW)
829 ArkNativeEngine::SetCurrentPreviewenv(options_.enableFileOperation);
830 #endif
831
832 if (!LoadRuntimeEnv(env, globalObj)) {
833 delete nativeEngine;
834 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Load runtime env failed");
835 return false;
836 }
837
838 panda::JSNApi::SetBundle(vm_, false);
839 panda::JSNApi::SetBundleName(vm_, options_.bundleName);
840 panda::JSNApi::SetModuleName(vm_, options_.moduleName);
841 panda::JSNApi::SetAssetPath(vm_, options_.modulePath);
842 std::map<std::string, std::vector<std::vector<std::string>>> pkgContextInfoMap;
843 std::map<std::string, std::string> pkgAliasMap;
844 GetPkgContextInfoListMap(options_.pkgContextInfoJsonStringMap, pkgContextInfoMap, pkgAliasMap);
845 panda::JSNApi::SetpkgContextInfoList(vm_, pkgContextInfoMap);
846 panda::JSNApi::SetPkgAliasList(vm_, pkgAliasMap);
847 panda::JSNApi::SetPkgNameList(vm_, options_.packageNameList);
848
849 nativeEngine_ = env;
850 return true;
851 }
852
RequireNapi(napi_env env,napi_callback_info info)853 napi_value SimulatorImpl::RequireNapi(napi_env env, napi_callback_info info)
854 {
855 napi_value globalObj;
856 napi_get_global(env, &globalObj);
857 napi_value requireNapi = nullptr;
858 napi_get_named_property(env, globalObj, "requireNapiPreview", &requireNapi);
859 size_t argc = ARGC_MAX_COUNT;
860 napi_value argv[ARGC_MAX_COUNT] = {nullptr};
861 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
862 napi_value result = nullptr;
863 napi_call_function(env, CreateJsUndefined(env), requireNapi, argc, argv, &result);
864 if (!CheckTypeForNapiValue(env, result, napi_undefined)) {
865 return result;
866 }
867 napi_value mockRequireNapi = nullptr;
868 napi_get_named_property(env, globalObj, "mockRequireNapi", &mockRequireNapi);
869 napi_call_function(env, CreateJsUndefined(env), mockRequireNapi, argc, argv, &result);
870 return result;
871 }
872
LoadJsMock(const std::string & fileName)873 void SimulatorImpl::LoadJsMock(const std::string &fileName)
874 {
875 std::ifstream stream(fileName, std::ios::ate | std::ios::binary);
876 if (!stream.is_open()) {
877 TAG_LOGE(AAFwkTag::ABILITY_SIM, "open: %{public}s failed", fileName.c_str());
878 return;
879 }
880 size_t len = stream.tellg();
881 std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(len);
882 stream.seekg(0);
883 stream.read(reinterpret_cast<char*>(buffer.get()), len);
884 stream.close();
885 panda::JSNApi::Execute(vm_, buffer.get(), len, "_GLOBAL::func_main_0");
886 }
887
LoadRuntimeEnv(napi_env env,napi_value globalObj)888 bool SimulatorImpl::LoadRuntimeEnv(napi_env env, napi_value globalObj)
889 {
890 JsSysModule::Console::InitConsoleModule(env);
891 auto ret = JsSysModule::Timer::RegisterTime(env);
892 if (!ret) {
893 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Register timer failed");
894 }
895 napi_value object = nullptr;
896 napi_create_object(env, &object);
897 napi_set_named_property(env, globalObj, "group", object);
898
899 const OHOS::Ide::JsMockUtil::AbcInfo info = OHOS::Ide::JsMockUtil::GetAbcBufferInfo();
900 const uint8_t *buffer = info.buffer;
901 std::size_t size = info.bufferSize;
902 panda::JSNApi::Execute(vm_, buffer, size, "_GLOBAL::func_main_0");
903
904 napi_value mockRequireNapi = nullptr;
905 napi_get_named_property(env, globalObj, "requireNapi", &mockRequireNapi);
906 napi_set_named_property(env, globalObj, "mockRequireNapi", mockRequireNapi);
907 auto* moduleManager = reinterpret_cast<NativeEngine*>(env)->GetModuleManager();
908 if (moduleManager != nullptr) {
909 TAG_LOGE(
910 AAFwkTag::ABILITY_SIM, "moduleManager SetPreviewSearchPath: %{public}s", options_.containerSdkPath.c_str());
911 moduleManager->SetPreviewSearchPath(options_.containerSdkPath);
912 }
913
914 std::string fileSeparator = "/";
915 auto pos = options_.containerSdkPath.find(fileSeparator);
916 if (pos == std::string::npos) {
917 fileSeparator = "\\";
918 }
919
920 std::string fileName = options_.containerSdkPath + fileSeparator + "apiMock" + fileSeparator + "jsMockHmos.abc";
921 TAG_LOGD(AAFwkTag::ABILITY_SIM, "file name:%{public}s", fileName.c_str());
922 if (!fileName.empty() && AbilityStageContext::Access(fileName)) {
923 LoadJsMock(fileName);
924 }
925
926 const char *moduleName = "SimulatorImpl";
927 BindNativeFunction(env, globalObj, "requireNapi", moduleName, SimulatorImpl::RequireNapi);
928 return true;
929 }
930
Run()931 void SimulatorImpl::Run()
932 {
933 uv_loop_t* uvLoop = nullptr;
934 napi_get_uv_event_loop(nativeEngine_, &uvLoop);
935 if (uvLoop != nullptr) {
936 uv_run(uvLoop, UV_RUN_NOWAIT);
937 }
938
939 if (postTask_ != nullptr) {
940 postTask_([this]() { Run(); }, 0);
941 }
942 }
943 }
944
Create(const Options & options)945 std::shared_ptr<Simulator> Simulator::Create(const Options &options)
946 {
947 auto simulator = std::make_shared<SimulatorImpl>();
948 if (simulator->Initialize(options)) {
949 return simulator;
950 }
951 return nullptr;
952 }
953
SetHostResolveBufferTracker(ResolveBufferTrackerCallback cb)954 void SimulatorImpl::SetHostResolveBufferTracker(ResolveBufferTrackerCallback cb)
955 {
956 if (vm_ == nullptr || cb == nullptr) {
957 TAG_LOGE(AAFwkTag::ABILITY_SIM, "Params invalid");
958 return;
959 }
960 panda::JSNApi::SetHostResolveBufferTracker(vm_, cb);
961 }
962
GetPkgContextInfoListMap(const std::map<std::string,std::string> & contextInfoMap,std::map<std::string,std::vector<std::vector<std::string>>> & pkgContextInfoMap,std::map<std::string,std::string> & pkgAliasMap)963 void SimulatorImpl::GetPkgContextInfoListMap(const std::map<std::string, std::string> &contextInfoMap,
964 std::map<std::string, std::vector<std::vector<std::string>>> &pkgContextInfoMap,
965 std::map<std::string, std::string> &pkgAliasMap)
966 {
967 for (auto it = contextInfoMap.begin(); it != contextInfoMap.end(); it++) {
968 std::vector<std::vector<std::string>> pkgContextInfoList;
969 auto jsonObject = nlohmann::json::parse(it->second);
970 if (jsonObject.is_discarded()) {
971 TAG_LOGE(AAFwkTag::JSRUNTIME, "moduleName: %{public}s parse json error", it->first.c_str());
972 continue;
973 }
974 for (nlohmann::json::iterator jsonIt = jsonObject.begin(); jsonIt != jsonObject.end(); jsonIt++) {
975 std::vector<std::string> items;
976 items.emplace_back(jsonIt.key());
977 nlohmann::json itemObject = jsonIt.value();
978 std::string pkgName = "";
979 items.emplace_back(PACKAGE_NAME);
980 if (itemObject[PACKAGE_NAME].is_null() || !itemObject[PACKAGE_NAME].is_string()) {
981 items.emplace_back(pkgName);
982 } else {
983 pkgName = itemObject[PACKAGE_NAME].get<std::string>();
984 items.emplace_back(pkgName);
985 }
986
987 items.emplace_back(BUNDLE_NAME);
988 if (itemObject[BUNDLE_NAME].is_null() || !itemObject[BUNDLE_NAME].is_string()) {
989 items.emplace_back("");
990 } else {
991 items.emplace_back(itemObject[BUNDLE_NAME].get<std::string>());
992 }
993
994 items.emplace_back(MODULE_NAME);
995 if (itemObject[MODULE_NAME].is_null() || !itemObject[MODULE_NAME].is_string()) {
996 items.emplace_back("");
997 } else {
998 items.emplace_back(itemObject[MODULE_NAME].get<std::string>());
999 }
1000
1001 GetPkgContextInfoListInner(itemObject, items, pkgAliasMap, pkgName);
1002 pkgContextInfoList.emplace_back(items);
1003 }
1004 TAG_LOGI(AAFwkTag::JSRUNTIME, "moduleName: %{public}s parse json success", it->first.c_str());
1005 pkgContextInfoMap[it->first] = pkgContextInfoList;
1006 }
1007 }
1008
GetPkgContextInfoListInner(nlohmann::json & itemObject,std::vector<std::string> & items,std::map<std::string,std::string> & pkgAliasMap,std::string & pkgName)1009 void SimulatorImpl::GetPkgContextInfoListInner(nlohmann::json &itemObject, std::vector<std::string> &items,
1010 std::map<std::string, std::string> &pkgAliasMap, std::string &pkgName)
1011 {
1012 items.emplace_back(VERSION);
1013 if (itemObject[VERSION].is_null() || !itemObject[VERSION].is_string()) {
1014 items.emplace_back("");
1015 } else {
1016 items.emplace_back(itemObject[VERSION].get<std::string>());
1017 }
1018
1019 items.emplace_back(ENTRY_PATH);
1020 if (itemObject[ENTRY_PATH].is_null() || !itemObject[ENTRY_PATH].is_string()) {
1021 items.emplace_back("");
1022 } else {
1023 items.emplace_back(itemObject[ENTRY_PATH].get<std::string>());
1024 }
1025
1026 items.emplace_back(IS_SO);
1027 if (itemObject[IS_SO].is_null() || !itemObject[IS_SO].is_boolean()) {
1028 items.emplace_back("false");
1029 } else {
1030 bool isSo = itemObject[IS_SO].get<bool>();
1031 if (isSo) {
1032 items.emplace_back("true");
1033 } else {
1034 items.emplace_back("false");
1035 }
1036 }
1037 if (!itemObject[DEPENDENCY_ALIAS].is_null() && itemObject[DEPENDENCY_ALIAS].is_string()) {
1038 std::string pkgAlias = itemObject[DEPENDENCY_ALIAS].get<std::string>();
1039 if (!pkgAlias.empty()) {
1040 pkgAliasMap[pkgAlias] = pkgName;
1041 }
1042 }
1043 }
1044
GetNativeStrFromJsTaggedObj(napi_value obj,const char * key)1045 std::string SimulatorImpl::GetNativeStrFromJsTaggedObj(napi_value obj, const char* key)
1046 {
1047 if (obj == nullptr) {
1048 TAG_LOGE(AAFwkTag::ABILITY_SIM, "get value failed");
1049 return "";
1050 }
1051
1052 napi_value valueStr = nullptr;
1053 napi_get_named_property(nativeEngine_, obj, key, &valueStr);
1054 napi_valuetype valueType = napi_undefined;
1055 napi_typeof(nativeEngine_, valueStr, &valueType);
1056 if (valueType != napi_string) {
1057 TAG_LOGE(AAFwkTag::ABILITY_SIM, "convert value failed");
1058 return "";
1059 }
1060
1061 size_t valueStrBufLength = 0;
1062 napi_get_value_string_utf8(nativeEngine_, valueStr, nullptr, 0, &valueStrBufLength);
1063 auto valueCStr = std::make_unique<char[]>(valueStrBufLength + 1);
1064 size_t valueStrLength = 0;
1065 napi_get_value_string_utf8(nativeEngine_, valueStr, valueCStr.get(), valueStrBufLength + 1, &valueStrLength);
1066 std::string ret(valueCStr.get(), valueStrLength);
1067 TAG_LOGD(AAFwkTag::ABILITY_SIM, "GetNativeStrFromJsTaggedObj Success");
1068 return ret;
1069 }
1070
ReportJsError(napi_value obj)1071 void SimulatorImpl::ReportJsError(napi_value obj)
1072 {
1073 std::string errorMsg = GetNativeStrFromJsTaggedObj(obj, "message");
1074 std::string errorName = GetNativeStrFromJsTaggedObj(obj, "name");
1075 std::string errorStack = GetNativeStrFromJsTaggedObj(obj, "stack");
1076 std::string topStack = GetNativeStrFromJsTaggedObj(obj, "topstack");
1077 std::string summary = "Error name:" + errorName + "\n";
1078 summary += "Error message:" + errorMsg + "\n";
1079 bool hasProperty = false;
1080 napi_has_named_property(nativeEngine_, obj, "code", &hasProperty);
1081 if (hasProperty) {
1082 std::string errorCode = GetNativeStrFromJsTaggedObj(obj, "code");
1083 summary += "Error code:" + errorCode + "\n";
1084 }
1085 if (errorStack.empty()) {
1086 TAG_LOGE(AAFwkTag::ABILITY_SIM, "errorStack empty");
1087 return;
1088 }
1089 auto newErrorStack = sourceMapPtr_->TranslateBySourceMap(errorStack);
1090 summary += "Stacktrace:\n" + newErrorStack;
1091
1092 std::stringstream summaryBody(summary);
1093 std::string line;
1094 std::string formattedSummary;
1095 while (std::getline(summaryBody, line)) {
1096 formattedSummary += "[Simulator Log]" + line + "\n";
1097 }
1098
1099 TAG_LOGE(AAFwkTag::ABILITY_SIM, "summary:\n%{public}s", formattedSummary.c_str());
1100 }
1101
CreateStageContext()1102 void SimulatorImpl::CreateStageContext()
1103 {
1104 if (stageContext_ == nullptr) {
1105 stageContext_ = std::make_shared<AbilityStageContext>();
1106 stageContext_->SetOptions(options_);
1107 stageContext_->SetConfiguration(options_.configuration);
1108 stageContext_->SetApplicationInfo(appInfo_);
1109 stageContext_->SetHapModuleInfo(moduleInfo_);
1110 }
1111 }
1112 } // namespace AbilityRuntime
1113 } // namespace OHOS
1114