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