• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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_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 
59 #if defined(WINDOWS_PLATFORM)
60 constexpr char ARK_DEBUGGER_LIB_PATH[] = "libark_debugger.dll";
61 #elif defined(MAC_PLATFORM)
62 constexpr char ARK_DEBUGGER_LIB_PATH[] = "libark_debugger.dylib";
63 #else
64 #error "Unsupported platform"
65 #endif
66 
PrintVmLog(int32_t,int32_t,const char *,const char *,const char * message)67 int32_t PrintVmLog(int32_t, int32_t, const char*, const char*, const char *message)
68 {
69     HILOG_DEBUG("ArkLog: %{public}s", message);
70     return 0;
71 }
72 
73 template<typename T, size_t N>
ArraySize(T (&)[N])74 inline constexpr size_t ArraySize(T (&)[N]) noexcept
75 {
76     return N;
77 }
78 
79 struct DebuggerTask {
80     void OnPostTask(std::function<void()> &&task);
81 
82     static void HandleTask(const uv_async_t *req);
83 
84     uv_async_t onPostTaskSignal {};
85     std::function<void()> func;
86 };
87 
88 class SimulatorImpl : public Simulator {
89 public:
90     SimulatorImpl() = default;
91     ~SimulatorImpl();
92 
93     bool Initialize(const Options &options);
94 
95     int64_t StartAbility(
96         const std::string &abilitySrcPath, TerminateCallback callback, const std::string &abilityName = "") override;
97     void TerminateAbility(int64_t abilityId) override;
98     void UpdateConfiguration(const AppExecFwk::Configuration &config) override;
99     void SetMockList(const std::map<std::string, std::string> &mockList) override;
100     void SetHostResolveBufferTracker(ResolveBufferTrackerCallback cb) override;
101 private:
102     bool OnInit();
103     void Run();
104     napi_value LoadScript(const std::string &srcPath);
105     void InitResourceMgr();
106     void InitJsAbilityContext(napi_env env, napi_value instanceValue);
107     void DispatchStartLifecycle(napi_value instanceValue);
108     std::unique_ptr<NativeReference> CreateJsWindowStage(const std::shared_ptr<Rosen::WindowScene> &windowScene);
109     napi_value CreateJsWant(napi_env env);
110     bool LoadAbilityStage(uint8_t *buffer, size_t len);
111     void InitJsAbilityStageContext(napi_value instanceValue);
112     napi_value CreateJsLaunchParam(napi_env env);
113     bool ParseBundleAndModuleInfo();
114     bool ParseAbilityInfo(const std::string &abilitySrcPath, const std::string &abilityName = "");
115     bool LoadRuntimeEnv(napi_env env, napi_value globalObject);
116     static napi_value RequireNapi(napi_env env, napi_callback_info info);
117     inline void SetHostResolveBufferTracker();
118 
119     panda::ecmascript::EcmaVM *CreateJSVM();
120     Options options_;
121     std::string abilityPath_;
122     panda::ecmascript::EcmaVM *vm_ = nullptr;
123     DebuggerTask debuggerTask_;
124     napi_env nativeEngine_ = nullptr;
125 
126     int64_t currentId_ = 0;
127     std::unordered_map<int64_t, std::shared_ptr<NativeReference>> abilities_;
128     std::unordered_map<int64_t, std::shared_ptr<Rosen::WindowScene>> windowScenes_;
129     std::unordered_map<int64_t, std::shared_ptr<NativeReference>> jsWindowStages_;
130     std::unordered_map<int64_t, std::shared_ptr<NativeReference>> jsContexts_;
131     std::shared_ptr<Global::Resource::ResourceManager> resourceMgr_;
132     std::shared_ptr<AbilityContext> context_;
133     std::shared_ptr<NativeReference> abilityStage_;
134     std::shared_ptr<AbilityStageContext> stageContext_;
135     std::shared_ptr<NativeReference> jsStageContext_;
136     std::shared_ptr<AppExecFwk::ApplicationInfo> appInfo_;
137     std::shared_ptr<AppExecFwk::HapModuleInfo> moduleInfo_;
138     std::shared_ptr<AppExecFwk::AbilityInfo> abilityInfo_;
139     CallbackTypePostTask postTask_ = nullptr;
140 };
141 
HandleTask(const uv_async_t * req)142 void DebuggerTask::HandleTask(const uv_async_t *req)
143 {
144     auto *debuggerTask = reinterpret_cast<DebuggerTask*>(req->data);
145     if (debuggerTask == nullptr) {
146         HILOG_ERROR("HandleTask debuggerTask is null");
147         return;
148     }
149     debuggerTask->func();
150 }
151 
OnPostTask(std::function<void ()> && task)152 void DebuggerTask::OnPostTask(std::function<void()> &&task)
153 {
154     if (uv_is_active((uv_handle_t*)&onPostTaskSignal)) {
155         func = std::move(task);
156         onPostTaskSignal.data = static_cast<void*>(this);
157         uv_async_send(&onPostTaskSignal);
158     }
159 }
160 
~SimulatorImpl()161 SimulatorImpl::~SimulatorImpl()
162 {
163     if (nativeEngine_) {
164         uv_close(reinterpret_cast<uv_handle_t*>(&debuggerTask_.onPostTaskSignal), nullptr);
165         uv_loop_t* uvLoop = nullptr;
166         napi_get_uv_event_loop(nativeEngine_, &uvLoop);
167         if (uvLoop != nullptr) {
168             uv_work_t work;
169             uv_queue_work(uvLoop, &work, [](uv_work_t*) {}, [](uv_work_t *work, int32_t status) {
170                 HILOG_ERROR("Simulator stop uv loop");
171                 uv_stop(work->loop);
172             });
173         }
174     }
175 
176     panda::JSNApi::StopDebugger(vm_);
177 
178     abilities_.clear();
179     nativeEngine_ = nullptr;
180     panda::JSNApi::DestroyJSVM(vm_);
181     vm_ = nullptr;
182 }
183 
Initialize(const Options & options)184 bool SimulatorImpl::Initialize(const Options &options)
185 {
186     if (nativeEngine_) {
187         HILOG_ERROR("Simulator is already initialized");
188         return true;
189     }
190 
191     options_ = options;
192     postTask_ = options.postTask;
193     if (!OnInit()) {
194         return false;
195     }
196 
197     uv_loop_t* uvLoop = nullptr;
198     napi_get_uv_event_loop(nativeEngine_, &uvLoop);
199     if (uvLoop == nullptr) {
200         return false;
201     }
202 
203     uv_async_init(uvLoop, &debuggerTask_.onPostTaskSignal,
204         reinterpret_cast<uv_async_cb>(DebuggerTask::HandleTask));
205 
206     Run();
207     return true;
208 }
209 
CallObjectMethod(napi_env env,napi_value obj,const char * name,napi_value const * argv,size_t argc)210 void CallObjectMethod(napi_env env, napi_value obj, const char *name, napi_value const *argv, size_t argc)
211 {
212     if (obj == nullptr) {
213         HILOG_ERROR("%{public}s, Failed to get Ability object", __func__);
214         return;
215     }
216     napi_value methodOnCreate = nullptr;
217     napi_get_named_property(env, obj, name, &methodOnCreate);
218     if (methodOnCreate == nullptr) {
219         HILOG_ERROR("Failed to get '%{public}s' from Ability object", name);
220         return;
221     }
222     napi_status status = napi_call_function(env, obj, methodOnCreate, argc, argv, nullptr);
223     if (status != napi_ok) {
224         HILOG_ERROR("Failed to napi call function");
225     }
226 }
227 
LoadScript(const std::string & srcPath)228 napi_value SimulatorImpl::LoadScript(const std::string &srcPath)
229 {
230     panda::Local<panda::ObjectRef> objRef = panda::JSNApi::GetExportObject(vm_, srcPath, "default");
231     if (objRef->IsNull()) {
232         HILOG_ERROR("Get export object failed");
233         return nullptr;
234     }
235 
236     auto obj = ArkNativeEngine::ArkValueToNapiValue(nativeEngine_, objRef);
237     napi_value instanceValue = nullptr;
238     napi_new_instance(nativeEngine_, obj, 0, nullptr, &instanceValue);
239     return instanceValue;
240 }
241 
ParseBundleAndModuleInfo()242 bool SimulatorImpl::ParseBundleAndModuleInfo()
243 {
244     AppExecFwk::BundleContainer::GetInstance().LoadBundleInfos(options_.moduleJsonBuffer);
245     appInfo_ = AppExecFwk::BundleContainer::GetInstance().GetApplicationInfo();
246     if (appInfo_ == nullptr) {
247         HILOG_ERROR("appinfo parse failed.");
248         return false;
249     }
250     nlohmann::json appInfoJson;
251     to_json(appInfoJson, *appInfo_);
252     std::cout << "appinfo : " << appInfoJson.dump() << std::endl;
253 
254     options_.bundleName = appInfo_->bundleName;
255     options_.compatibleVersion = appInfo_->apiCompatibleVersion;
256     options_.installationFree = (appInfo_->bundleType == AppExecFwk::BundleType::ATOMIC_SERVICE ? true : false);
257     options_.targetVersion = appInfo_->apiTargetVersion;
258     options_.releaseType = appInfo_->apiReleaseType;
259     options_.compileMode = "esmodule";
260 
261     if (appInfo_->moduleInfos.empty()) {
262         HILOG_ERROR("module name is not exist");
263         return false;
264     }
265     options_.moduleName = appInfo_->moduleInfos[0].moduleName;
266     std::cout << "module name is " << options_.moduleName << std::endl;
267 
268     moduleInfo_ = AppExecFwk::BundleContainer::GetInstance().GetHapModuleInfo(options_.moduleName);
269     if (moduleInfo_ == nullptr) {
270         HILOG_ERROR("module info parse failed.");
271         return false;
272     }
273     nlohmann::json moduleInfoJson;
274     to_json(moduleInfoJson, *moduleInfo_);
275     std::cout << "moduleInfo : " << moduleInfoJson.dump() << std::endl;
276 
277     options_.pageProfile = moduleInfo_->pages;
278     options_.enablePartialUpdate = true;
279     for (auto iter : moduleInfo_->metadata) {
280         if (iter.name == "ArkTSPartialUpdate" && iter.value == "false") {
281             options_.enablePartialUpdate = false;
282             break;
283         }
284     }
285     return true;
286 }
287 
ParseAbilityInfo(const std::string & abilitySrcPath,const std::string & abilityName)288 bool SimulatorImpl::ParseAbilityInfo(const std::string &abilitySrcPath, const std::string &abilityName)
289 {
290     if (!abilityName.empty()) {
291         abilityInfo_ = AppExecFwk::BundleContainer::GetInstance().GetAbilityInfo(options_.moduleName, abilityName);
292     } else {
293         auto path = abilitySrcPath;
294         path.erase(path.rfind("."));
295         auto abilityNameFromPath = path.substr(path.rfind('/') + 1, path.length());
296         abilityInfo_ = AppExecFwk::BundleContainer::GetInstance().GetAbilityInfo(
297             options_.moduleName, abilityNameFromPath);
298     }
299 
300     if (abilityInfo_ == nullptr) {
301         HILOG_ERROR("ability info parse failed.");
302         return false;
303     }
304     nlohmann::json json;
305     to_json(json, *abilityInfo_);
306     std::cout << "abilityInfo : " << json.dump() << std::endl;
307 
308     options_.labelId = abilityInfo_->labelId;
309     return true;
310 }
311 
StartAbility(const std::string & abilitySrcPath,TerminateCallback callback,const std::string & abilityName)312 int64_t SimulatorImpl::StartAbility(
313     const std::string &abilitySrcPath, TerminateCallback callback, const std::string &abilityName)
314 {
315     if (!ParseAbilityInfo(abilitySrcPath, abilityName)) {
316         return -1;
317     }
318 
319     if (stageContext_ == nullptr) {
320         stageContext_ = std::make_shared<AbilityStageContext>();
321         stageContext_->SetOptions(options_);
322         stageContext_->SetConfiguration(options_.configuration);
323         stageContext_->SetApplicationInfo(appInfo_);
324         stageContext_->SetHapModuleInfo(moduleInfo_);
325     }
326 
327     std::ifstream stream(options_.modulePath, std::ios::ate | std::ios::binary);
328     if (!stream.is_open()) {
329         HILOG_ERROR("Failed to open: %{public}s", options_.modulePath.c_str());
330         return -1;
331     }
332 
333     size_t len = stream.tellg();
334     std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(len);
335     stream.seekg(0);
336     stream.read(reinterpret_cast<char*>(buffer.get()), len);
337     stream.close();
338 
339     auto buf = buffer.release();
340     if (!LoadAbilityStage(buf, len)) {
341         HILOG_ERROR("Load ability stage failed.");
342         return -1;
343     }
344 
345     abilityPath_ = BUNDLE_INSTALL_PATH + options_.moduleName + "/" + abilitySrcPath;
346     if (!reinterpret_cast<NativeEngine*>(nativeEngine_)->RunScriptBuffer(abilityPath_, buf, len, false)) {
347         HILOG_ERROR("Failed to run script: %{public}s", abilityPath_.c_str());
348         return -1;
349     }
350 
351     napi_value instanceValue = LoadScript(abilityPath_);
352     if (instanceValue == nullptr) {
353         HILOG_ERROR("Failed to create object instance");
354         return -1;
355     }
356 
357     ++currentId_;
358     InitResourceMgr();
359     InitJsAbilityContext(nativeEngine_, instanceValue);
360     DispatchStartLifecycle(instanceValue);
361     napi_ref ref = nullptr;
362     napi_create_reference(nativeEngine_, instanceValue, 1, &ref);
363     abilities_.emplace(currentId_, std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref)));
364     return currentId_;
365 }
366 
LoadAbilityStage(uint8_t * buffer,size_t len)367 bool SimulatorImpl::LoadAbilityStage(uint8_t *buffer, size_t len)
368 {
369     if (moduleInfo_ == nullptr) {
370         HILOG_ERROR("moduleInfo is nullptr");
371         return false;
372     }
373 
374     if (moduleInfo_->srcEntrance.empty()) {
375         HILOG_DEBUG("module src path is empty.");
376         return true;
377     }
378 
379     if (nativeEngine_ == nullptr) {
380         HILOG_ERROR("nativeEngine_ is nullptr");
381         return false;
382     }
383     std::string srcEntrance = moduleInfo_->srcEntrance;
384     srcEntrance.erase(srcEntrance.rfind("."));
385     srcEntrance.append(".abc");
386     srcEntrance = srcEntrance.substr(srcEntrance.find('/') + 1, srcEntrance.length());
387 
388     auto moduleSrcPath = BUNDLE_INSTALL_PATH + options_.moduleName + "/" + srcEntrance;
389     HILOG_DEBUG("moduleSrcPath is %{public}s", moduleSrcPath.c_str());
390     if (!reinterpret_cast<NativeEngine*>(nativeEngine_)->RunScriptBuffer(moduleSrcPath, buffer, len, false)) {
391         HILOG_ERROR("Failed to run ability stage script: %{public}s", moduleSrcPath.c_str());
392         return false;
393     }
394 
395     napi_value instanceValue = LoadScript(moduleSrcPath);
396     if (instanceValue == nullptr) {
397         HILOG_ERROR("Failed to create ability stage instance");
398         return false;
399     }
400 
401     InitJsAbilityStageContext(instanceValue);
402     CallObjectMethod(nativeEngine_, instanceValue, "onCreate", nullptr, 0);
403 
404     napi_value wantArgv[] = {
405         CreateJsWant(nativeEngine_)
406     };
407     CallObjectMethod(nativeEngine_, instanceValue, "onAcceptWant", wantArgv, ArraySize(wantArgv));
408     napi_ref ref = nullptr;
409     napi_create_reference(nativeEngine_, instanceValue, 1, &ref);
410     abilityStage_ = std::shared_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref));
411     return true;
412 }
413 
InitJsAbilityStageContext(napi_value obj)414 void SimulatorImpl::InitJsAbilityStageContext(napi_value obj)
415 {
416     napi_value contextObj = CreateJsAbilityStageContext(nativeEngine_, stageContext_);
417     if (contextObj == nullptr) {
418         HILOG_ERROR("contextObj is nullptr");
419         return;
420     }
421 
422     jsStageContext_ = std::shared_ptr<NativeReference>(
423         JsRuntime::LoadSystemModuleByEngine(nativeEngine_, "application.AbilityStageContext", &contextObj, 1));
424     if (jsStageContext_ == nullptr) {
425         HILOG_ERROR("Failed to get LoadSystemModuleByEngine");
426         return;
427     }
428 
429     contextObj = jsStageContext_->GetNapiValue();
430     if (contextObj == nullptr) {
431         HILOG_ERROR("contextObj is nullptr.");
432         return;
433     }
434 
435     if (obj == nullptr) {
436         HILOG_ERROR("obj is nullptr");
437         return;
438     }
439     napi_set_named_property(nativeEngine_, obj, "context", contextObj);
440 }
441 
TerminateAbility(int64_t abilityId)442 void SimulatorImpl::TerminateAbility(int64_t abilityId)
443 {
444     if (abilityId == 0 && abilities_.begin() != abilities_.end()) {
445         TerminateAbility(abilities_.begin()->first);
446         return;
447     }
448 
449     auto it = abilities_.find(abilityId);
450     if (it == abilities_.end()) {
451         return;
452     }
453 
454     std::shared_ptr<NativeReference> ref = it->second;
455     abilities_.erase(it);
456 
457     auto instanceValue = ref->GetNapiValue();
458     if (instanceValue == nullptr) {
459         return;
460     }
461 
462     CallObjectMethod(nativeEngine_, instanceValue, "onBackground", nullptr, 0);
463     CallObjectMethod(nativeEngine_, instanceValue, "onWindowStageDestroy", nullptr, 0);
464     CallObjectMethod(nativeEngine_, instanceValue, "onDestroy", nullptr, 0);
465 
466     auto windowSceneIter = windowScenes_.find(abilityId);
467     if (windowSceneIter != windowScenes_.end()) {
468         windowScenes_.erase(windowSceneIter);
469     }
470 
471     auto windowStageIter = jsWindowStages_.find(abilityId);
472     if (windowStageIter != jsWindowStages_.end()) {
473         jsWindowStages_.erase(windowStageIter);
474     }
475 
476     auto jsContextIter = jsContexts_.find(abilityId);
477     if (jsContextIter != jsContexts_.end()) {
478         jsContexts_.erase(jsContextIter);
479     }
480 }
481 
UpdateConfiguration(const AppExecFwk::Configuration & config)482 void SimulatorImpl::UpdateConfiguration(const AppExecFwk::Configuration &config)
483 {
484     HILOG_DEBUG("called.");
485     if (abilityStage_ == nullptr) {
486         HILOG_ERROR("abilityStage_ is nullptr");
487         return;
488     }
489 
490     auto configuration = std::make_shared<AppExecFwk::Configuration>(config);
491     if (configuration == nullptr) {
492         return;
493     }
494 
495     if (stageContext_) {
496         stageContext_->SetConfiguration(configuration);
497     }
498 
499     napi_value configArgv[] = {
500         CreateJsConfiguration(nativeEngine_, config)
501     };
502 
503     auto abilityStage = abilityStage_->GetNapiValue();
504     if (abilityStage == nullptr) {
505         HILOG_ERROR("abilityStage is nullptr");
506         return;
507     }
508     CallObjectMethod(nativeEngine_, abilityStage, "onConfigurationUpdated", configArgv, ArraySize(configArgv));
509     CallObjectMethod(nativeEngine_, abilityStage, "onConfigurationUpdate", configArgv, ArraySize(configArgv));
510     JsAbilityStageContext::ConfigurationUpdated(nativeEngine_, jsStageContext_, configuration);
511 
512     for (auto iter = abilities_.begin(); iter != abilities_.end(); iter++) {
513         auto ability = iter->second->GetNapiValue();
514         if (ability == nullptr) {
515             HILOG_ERROR("ability is nullptr");
516             continue;
517         }
518 
519         CallObjectMethod(nativeEngine_, ability, "onConfigurationUpdated", configArgv, ArraySize(configArgv));
520         CallObjectMethod(nativeEngine_, ability, "onConfigurationUpdate", configArgv, ArraySize(configArgv));
521         JsAbilityContext::ConfigurationUpdated(nativeEngine_, iter->second, configuration);
522     }
523 }
524 
SetMockList(const std::map<std::string,std::string> & mockList)525 void SimulatorImpl::SetMockList(const std::map<std::string, std::string> &mockList)
526 {
527     HILOG_DEBUG("called. mockList size: %{public}zu", mockList.size());
528     panda::JSNApi::SetMockModuleList(vm_, mockList);
529 }
530 
InitResourceMgr()531 void SimulatorImpl::InitResourceMgr()
532 {
533     HILOG_DEBUG("called.");
534     resourceMgr_ = std::shared_ptr<Global::Resource::ResourceManager>(Global::Resource::CreateResourceManager());
535     if (resourceMgr_ == nullptr) {
536         HILOG_ERROR("resourceMgr is nullptr");
537         return;
538     }
539 
540     if (!resourceMgr_->AddResource(options_.resourcePath.c_str())) {
541         HILOG_ERROR("Add resource failed.");
542     }
543     HILOG_DEBUG("Add resource success.");
544 }
545 
InitJsAbilityContext(napi_env env,napi_value obj)546 void SimulatorImpl::InitJsAbilityContext(napi_env env, napi_value obj)
547 {
548     if (context_ == nullptr) {
549         context_ = std::make_shared<AbilityContext>();
550         context_->SetSimulator(static_cast<Simulator*>(this));
551         context_->SetOptions(options_);
552         context_->SetAbilityStageContext(stageContext_);
553         context_->SetResourceManager(resourceMgr_);
554         context_->SetAbilityInfo(abilityInfo_);
555     }
556     napi_value contextObj = CreateJsAbilityContext(nativeEngine_, context_);
557     auto systemModule = std::shared_ptr<NativeReference>(
558         JsRuntime::LoadSystemModuleByEngine(nativeEngine_, "application.AbilityContext", &contextObj, 1));
559     if (systemModule == nullptr) {
560         HILOG_ERROR("systemModule is nullptr.");
561         return;
562     }
563     contextObj = systemModule->GetNapiValue();
564     if (contextObj == nullptr) {
565         HILOG_ERROR("contextObj is nullptr.");
566         return;
567     }
568 
569     if (obj == nullptr) {
570         HILOG_ERROR("obj is nullptr");
571         return;
572     }
573     napi_set_named_property(env, obj, "context", contextObj);
574     jsContexts_.emplace(currentId_, systemModule);
575 }
576 
CreateJsWant(napi_env env)577 napi_value SimulatorImpl::CreateJsWant(napi_env env)
578 {
579     napi_value objValue = nullptr;
580     napi_create_object(env, &objValue);
581     napi_set_named_property(env, objValue, "deviceId", CreateJsValue(env, std::string("")));
582     napi_set_named_property(env, objValue, "bundleName", CreateJsValue(env, options_.bundleName));
583     if (abilityInfo_) {
584         napi_set_named_property(env, objValue, "abilityName", CreateJsValue(env, abilityInfo_->name));
585     }
586     napi_set_named_property(env, objValue, "moduleName", CreateJsValue(env, options_.moduleName));
587 
588     napi_set_named_property(env, objValue, "uri", CreateJsValue(env, std::string("")));
589     napi_set_named_property(env, objValue, "type", CreateJsValue(env, std::string("")));
590     napi_set_named_property(env, objValue, "flags", CreateJsValue(env, 0));
591     napi_set_named_property(env, objValue, "type", CreateJsValue(env, std::string("")));
592     napi_value object = nullptr;
593     napi_create_object(env, &object);
594     napi_set_named_property(env, objValue, "parameters", object);
595     napi_value array = nullptr;
596     napi_create_array_with_length(env, 0, &array);
597     napi_set_named_property(env, objValue, "entities", array);
598     return objValue;
599 }
600 
CreateJsLaunchParam(napi_env env)601 napi_value SimulatorImpl::CreateJsLaunchParam(napi_env env)
602 {
603     napi_value objValue = nullptr;
604     napi_create_object(env, &objValue);
605     napi_set_named_property(env, objValue, "launchReason", CreateJsValue(env, AAFwk::LAUNCHREASON_UNKNOWN));
606     napi_set_named_property(env, objValue, "lastExitReason", CreateJsValue(env, AAFwk::LASTEXITREASON_UNKNOWN));
607     return objValue;
608 }
609 
DispatchStartLifecycle(napi_value instanceValue)610 void SimulatorImpl::DispatchStartLifecycle(napi_value instanceValue)
611 {
612     napi_value wantArgv[] = {
613         CreateJsWant(nativeEngine_),
614         CreateJsLaunchParam(nativeEngine_)
615     };
616     CallObjectMethod(nativeEngine_, instanceValue, "onCreate", wantArgv, ArraySize(wantArgv));
617     auto windowScene = std::make_shared<Rosen::WindowScene>();
618     if (windowScene == nullptr) {
619         return;
620     }
621     sptr<Rosen::IWindowLifeCycle> listener = nullptr;
622     windowScene->Init(-1, context_, listener);
623     auto jsWindowStage = CreateJsWindowStage(windowScene);
624     if (jsWindowStage == nullptr) {
625         return;
626     }
627     napi_value argv[] = { jsWindowStage->GetNapiValue() };
628     CallObjectMethod(nativeEngine_, instanceValue, "onWindowStageCreate", argv, ArraySize(argv));
629 
630     CallObjectMethod(nativeEngine_, instanceValue, "onForeground", nullptr, 0);
631 
632     windowScenes_.emplace(currentId_, windowScene);
633     jsWindowStages_.emplace(currentId_, std::shared_ptr<NativeReference>(jsWindowStage.release()));
634 }
635 
CreateJsWindowStage(const std::shared_ptr<Rosen::WindowScene> & windowScene)636 std::unique_ptr<NativeReference> SimulatorImpl::CreateJsWindowStage(
637     const std::shared_ptr<Rosen::WindowScene> &windowScene)
638 {
639     napi_value jsWindowStage = Rosen::CreateJsWindowStage(nativeEngine_, windowScene);
640     if (jsWindowStage == nullptr) {
641         HILOG_ERROR("Failed to create jsWindowSatge object");
642         return nullptr;
643     }
644     return JsRuntime::LoadSystemModuleByEngine(nativeEngine_, "application.WindowStage", &jsWindowStage, 1);
645 }
646 
CreateJSVM()647 panda::ecmascript::EcmaVM *SimulatorImpl::CreateJSVM()
648 {
649     panda::RuntimeOption pandaOption;
650     pandaOption.SetArkProperties(DEFAULT_ARK_PROPERTIES);
651     pandaOption.SetGcThreadNum(DEFAULT_GC_THREAD_NUM);
652     pandaOption.SetLongPauseTime(DEFAULT_LONG_PAUSE_TIME);
653     pandaOption.SetGcType(panda::RuntimeOption::GC_TYPE::GEN_GC);
654     pandaOption.SetGcPoolSize(DEFAULT_GC_POOL_SIZE);
655     pandaOption.SetLogLevel(panda::RuntimeOption::LOG_LEVEL::FOLLOW);
656     pandaOption.SetLogBufPrint(PrintVmLog);
657     pandaOption.SetEnableAsmInterpreter(true);
658     pandaOption.SetAsmOpcodeDisableRange("");
659     return panda::JSNApi::CreateJSVM(pandaOption);
660 }
661 
OnInit()662 bool SimulatorImpl::OnInit()
663 {
664     if (!ParseBundleAndModuleInfo()) {
665         HILOG_ERROR("parse bundle and module info failed.");
666         return false;
667     }
668 
669     vm_ = CreateJSVM();
670     if (vm_ == nullptr) {
671         return false;
672     }
673 
674     panda::JSNApi::DebugOption debugOption = {ARK_DEBUGGER_LIB_PATH, (options_.debugPort != 0), options_.debugPort};
675     panda::JSNApi::StartDebugger(vm_, debugOption, 0,
676         std::bind(&DebuggerTask::OnPostTask, &debuggerTask_, std::placeholders::_1));
677 
678     auto nativeEngine = new (std::nothrow) ArkNativeEngine(vm_, nullptr);
679     if (nativeEngine == nullptr) {
680         HILOG_ERROR("nativeEngine is nullptr");
681         return false;
682     }
683     napi_env env = reinterpret_cast<napi_env>(nativeEngine);
684 
685     napi_value globalObj;
686     napi_get_global(env, &globalObj);
687     if (globalObj == nullptr) {
688         delete nativeEngine;
689         HILOG_ERROR("Failed to get global object");
690         return false;
691     }
692 
693     if (!LoadRuntimeEnv(env, globalObj)) {
694         delete nativeEngine;
695         HILOG_ERROR("Load runtime env failed.");
696         return false;
697     }
698 
699     panda::JSNApi::SetBundle(vm_, false);
700     panda::JSNApi::SetBundleName(vm_, options_.bundleName);
701     panda::JSNApi::SetModuleName(vm_, options_.moduleName);
702     panda::JSNApi::SetAssetPath(vm_, options_.modulePath);
703 
704     nativeEngine_ = env;
705     return true;
706 }
707 
RequireNapi(napi_env env,napi_callback_info info)708 napi_value SimulatorImpl::RequireNapi(napi_env env, napi_callback_info info)
709 {
710     napi_value globalObj;
711     napi_get_global(env, &globalObj);
712     napi_value requireNapi = nullptr;
713     napi_get_named_property(env, globalObj, "requireNapiPreview", &requireNapi);
714     size_t argc = ARGC_MAX_COUNT;
715     napi_value argv[ARGC_MAX_COUNT] = {nullptr};
716     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
717     napi_value result = nullptr;
718     napi_call_function(env, CreateJsUndefined(env), requireNapi, argc, argv, &result);
719     if (!CheckTypeForNapiValue(env, result, napi_undefined)) {
720         return result;
721     }
722     napi_value mockRequireNapi = nullptr;
723     napi_get_named_property(env, globalObj, "mockRequireNapi", &mockRequireNapi);
724     napi_call_function(env, CreateJsUndefined(env), mockRequireNapi, argc, argv, &result);
725     return result;
726 }
727 
LoadRuntimeEnv(napi_env env,napi_value globalObj)728 bool SimulatorImpl::LoadRuntimeEnv(napi_env env, napi_value globalObj)
729 {
730     JsSysModule::Console::InitConsoleModule(env);
731     auto ret = JsSysModule::Timer::RegisterTime(env);
732     if (!ret) {
733         HILOG_ERROR("Register timer failed");
734     }
735     napi_value object = nullptr;
736     napi_create_object(env, &object);
737     napi_set_named_property(env, globalObj, "group", object);
738 
739     uintptr_t bufferStart = reinterpret_cast<uintptr_t>(_binary_jsMockSystemPlugin_abc_start);
740     uintptr_t bufferEnd = reinterpret_cast<uintptr_t>(_binary_jsMockSystemPlugin_abc_end);
741     const uint8_t *buffer = reinterpret_cast<const uint8_t*>(bufferStart);
742     size_t size = bufferEnd - bufferStart;
743     panda::JSNApi::Execute(vm_, buffer, size, "_GLOBAL::func_main_0");
744 
745     napi_value mockRequireNapi = nullptr;
746     napi_get_named_property(env, globalObj, "requireNapi", &mockRequireNapi);
747     napi_set_named_property(env, globalObj, "mockRequireNapi", mockRequireNapi);
748     auto* moduleManager = reinterpret_cast<NativeEngine*>(env)->GetModuleManager();
749     if (moduleManager != nullptr) {
750         HILOG_ERROR("moduleManager SetPreviewSearchPath: %{public}s", options_.containerSdkPath.c_str());
751         moduleManager->SetPreviewSearchPath(options_.containerSdkPath);
752     }
753 
754     std::string fileSeparator = "/";
755     auto pos = options_.containerSdkPath.find(fileSeparator);
756     if (pos == std::string::npos) {
757         fileSeparator = "\\";
758     }
759 
760     std::string fileName = options_.containerSdkPath + fileSeparator + "apiMock" + fileSeparator + "jsMockHmos.abc";
761     HILOG_DEBUG("file name: %{public}s", fileName.c_str());
762     if (!fileName.empty() && AbilityStageContext::Access(fileName)) {
763         panda::JSNApi::Execute(vm_, fileName, "_GLOBAL::func_main_0");
764     }
765 
766     const char *moduleName = "SimulatorImpl";
767     BindNativeFunction(env, globalObj, "requireNapi", moduleName, SimulatorImpl::RequireNapi);
768     return true;
769 }
770 
Run()771 void SimulatorImpl::Run()
772 {
773     uv_loop_t* uvLoop = nullptr;
774     napi_get_uv_event_loop(nativeEngine_, &uvLoop);
775     if (uvLoop != nullptr) {
776         uv_run(uvLoop, UV_RUN_NOWAIT);
777     }
778 
779     if (postTask_ != nullptr) {
780         postTask_([this]() { Run(); }, 0);
781     }
782 }
783 }
784 
Create(const Options & options)785 std::unique_ptr<Simulator> Simulator::Create(const Options &options)
786 {
787     auto simulator = std::make_unique<SimulatorImpl>();
788     if (simulator->Initialize(options)) {
789         return simulator;
790     }
791     return nullptr;
792 }
793 
SetHostResolveBufferTracker(ResolveBufferTrackerCallback cb)794 void SimulatorImpl::SetHostResolveBufferTracker(ResolveBufferTrackerCallback cb)
795 {
796     if (vm_ == nullptr || cb == nullptr) {
797         HILOG_ERROR("Params invalid.");
798         return;
799     }
800     panda::JSNApi::SetHostResolveBufferTracker(vm_, cb);
801 }
802 } // namespace AbilityRuntime
803 } // namespace OHOS
804