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