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