• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "js_environment.h"
17 
18 #include <chrono>
19 
20 #include "console.h"
21 #include "ffrt.h"
22 #include "hilog_tag_wrapper.h"
23 #include "js_environment_impl.h"
24 #include "native_engine/impl/ark/ark_native_engine.h"
25 #include "uncaught_exception_callback.h"
26 
27 namespace OHOS {
28 namespace JsEnv {
29 namespace {
30 static const std::string DEBUGGER = "@Debugger";
31 static const std::string NOT_INIT = "SourceMap is not initialized yet \n";
32 }
33 
ConvertProfilerType(JsEnvironment::PROFILERTYPE type)34 static panda::DFXJSNApi::ProfilerType ConvertProfilerType(JsEnvironment::PROFILERTYPE type)
35 {
36     if (type == JsEnvironment::PROFILERTYPE::PROFILERTYPE_CPU) {
37         return panda::DFXJSNApi::ProfilerType::CPU_PROFILER;
38     } else {
39         return panda::DFXJSNApi::ProfilerType::HEAP_PROFILER;
40     }
41 }
42 
JsEnvironment(std::unique_ptr<JsEnvironmentImpl> impl)43 JsEnvironment::JsEnvironment(std::unique_ptr<JsEnvironmentImpl> impl) : impl_(std::move(impl))
44 {}
45 
~JsEnvironment()46 JsEnvironment::~JsEnvironment()
47 {
48     TAG_LOGD(AAFwkTag::JSENV, "called");
49 
50     if (engine_ != nullptr) {
51         delete engine_;
52         engine_ = nullptr;
53     }
54 
55     if (vm_ != nullptr) {
56         panda::JSNApi::DestroyJSVM(vm_);
57         vm_ = nullptr;
58     }
59 }
60 
Initialize(const panda::RuntimeOption & pandaOption,void * jsEngine)61 bool JsEnvironment::Initialize(const panda::RuntimeOption& pandaOption, void* jsEngine)
62 {
63     TAG_LOGD(AAFwkTag::JSENV, "Js environment initialize");
64     vm_ = panda::JSNApi::CreateJSVM(pandaOption);
65     if (vm_ == nullptr) {
66         TAG_LOGE(AAFwkTag::JSENV, "Create vm failed");
67         return false;
68     }
69 
70     engine_ = new ArkNativeEngine(vm_, jsEngine);
71     return true;
72 }
73 
InitTimerModule()74 void JsEnvironment::InitTimerModule()
75 {
76     if (engine_ == nullptr) {
77         TAG_LOGE(AAFwkTag::JSENV, "Invalid native engine");
78         return;
79     }
80 
81     if (impl_ != nullptr) {
82         impl_->InitTimerModule(engine_);
83     }
84 }
85 
InitWorkerModule(std::shared_ptr<WorkerInfo> workerInfo)86 void JsEnvironment::InitWorkerModule(std::shared_ptr<WorkerInfo> workerInfo)
87 {
88     if (engine_ == nullptr) {
89         TAG_LOGE(AAFwkTag::JSENV, "Invalid native engine");
90         return;
91     }
92 
93     if (impl_ != nullptr) {
94         impl_->InitWorkerModule(engine_, workerInfo);
95     }
96 }
97 
InitSyscapModule()98 void JsEnvironment::InitSyscapModule()
99 {
100     if (impl_ != nullptr) {
101         impl_->InitSyscapModule();
102     }
103 }
104 
PostTask(const std::function<void ()> & task,const std::string & name,int64_t delayTime)105 void JsEnvironment::PostTask(const std::function<void()>& task, const std::string& name, int64_t delayTime)
106 {
107     if (impl_ != nullptr) {
108         impl_->PostTask(task, name, delayTime);
109     }
110 }
111 
PostSyncTask(const std::function<void ()> & task,const std::string & name)112 void JsEnvironment::PostSyncTask(const std::function<void()>& task, const std::string& name)
113 {
114     if (impl_ != nullptr) {
115         impl_->PostSyncTask(task, name);
116     }
117 }
118 
RemoveTask(const std::string & name)119 void JsEnvironment::RemoveTask(const std::string& name)
120 {
121     if (impl_ != nullptr) {
122         impl_->RemoveTask(name);
123     }
124 }
125 
InitSourceMap(const std::shared_ptr<JsEnv::SourceMapOperator> operatorObj)126 void JsEnvironment::InitSourceMap(const std::shared_ptr<JsEnv::SourceMapOperator> operatorObj)
127 {
128     sourceMapOperator_ = operatorObj;
129     if (engine_ == nullptr) {
130         TAG_LOGE(AAFwkTag::JSENV, "Invalid Native Engine");
131         return;
132     }
133 
134     if (sourceMapOperator_ != nullptr && sourceMapOperator_->GetHasFile()) {
135         sourceMapOperator_->InitSourceMap();
136     } else {
137         sourceMapOperator_->SetInitStatus(InitStatus::EXECUTED_SUCCESSFULLY);
138     }
139 
140     auto translateBySourceMapFunc = [&](const std::string& rawStack) -> std::string {
141         if (sourceMapOperator_ != nullptr && sourceMapOperator_->GetInitStatus()) {
142             return sourceMapOperator_->TranslateBySourceMap(rawStack);
143         } else {
144             return NOT_INIT + rawStack;
145         }
146     };
147     engine_->RegisterTranslateBySourceMap(translateBySourceMapFunc);
148 
149     auto translateUrlBySourceMapFunc = [&](std::string& url, int& line, int& column, std::string& packageName) -> bool {
150         if (sourceMapOperator_ != nullptr && sourceMapOperator_->GetInitStatus()) {
151             return sourceMapOperator_->TranslateUrlPositionBySourceMap(url, line, column, packageName);
152         }
153         return false;
154     };
155     engine_->RegisterSourceMapTranslateCallback(translateUrlBySourceMapFunc);
156 }
157 
RegisterUncaughtExceptionHandler(const JsEnv::UncaughtExceptionInfo & uncaughtExceptionInfo)158 void JsEnvironment::RegisterUncaughtExceptionHandler(const JsEnv::UncaughtExceptionInfo& uncaughtExceptionInfo)
159 {
160     if (engine_ == nullptr) {
161         TAG_LOGE(AAFwkTag::JSENV, "Invalid Native Engine");
162         return;
163     }
164 
165     engine_->RegisterNapiUncaughtExceptionHandler(NapiUncaughtExceptionCallback(uncaughtExceptionInfo.uncaughtTask,
166         sourceMapOperator_, reinterpret_cast<napi_env>(engine_)));
167 }
168 
LoadScript(const std::string & path,std::vector<uint8_t> * buffer,bool isBundle)169 bool JsEnvironment::LoadScript(const std::string& path, std::vector<uint8_t>* buffer, bool isBundle)
170 {
171     if (engine_ == nullptr) {
172         TAG_LOGE(AAFwkTag::JSENV, "Invalid Native Engine");
173         return false;
174     }
175 
176     if (buffer == nullptr) {
177         return engine_->RunScriptPath(path.c_str());
178     }
179     auto start = std::chrono::high_resolution_clock::now();
180     bool ret = engine_->RunScriptBuffer(path.c_str(), *buffer, isBundle) != nullptr;
181     auto end = std::chrono::high_resolution_clock::now();
182     auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
183     TAG_LOGI(AAFwkTag::JSENV, "timing: %{public}lld", duration_ms);
184     return ret;
185 }
186 
StartDebugger(std::string & option,uint32_t socketFd,bool isDebugApp)187 bool JsEnvironment::StartDebugger(
188     std::string& option, uint32_t socketFd, bool isDebugApp)
189 {
190     TAG_LOGD(AAFwkTag::JSENV, "call");
191     if (vm_ == nullptr) {
192         TAG_LOGE(AAFwkTag::JSENV, "Invalid vm");
193         return false;
194     }
195     int32_t identifierId = ParseHdcRegisterOption(option);
196     if (identifierId == -1) {
197         TAG_LOGE(AAFwkTag::JSENV, "Abnormal parsing of tid results");
198         return false;
199     }
200     debugMode_ = panda::JSNApi::StartDebuggerForSocketPair(identifierId, socketFd);
201     return debugMode_;
202 }
203 
StopDebugger()204 void JsEnvironment::StopDebugger()
205 {
206     if (vm_ == nullptr) {
207         TAG_LOGE(AAFwkTag::JSENV, "Invalid vm");
208         return;
209     }
210 
211     (void)panda::JSNApi::StopDebugger(vm_);
212 }
213 
StopDebugger(std::string & option)214 void JsEnvironment::StopDebugger(std::string& option)
215 {
216     int32_t identifierId = ParseHdcRegisterOption(option);
217     if (identifierId == -1) {
218         TAG_LOGE(AAFwkTag::JSENV, "Abnormal parsing of tid results");
219         return;
220     }
221     panda::JSNApi::StopDebugger(identifierId);
222 }
223 
InitConsoleModule()224 void JsEnvironment::InitConsoleModule()
225 {
226     if (engine_ == nullptr) {
227         TAG_LOGE(AAFwkTag::JSENV, "Invalid Native Engine");
228         return;
229     }
230 
231     if (impl_ != nullptr) {
232         impl_->InitConsoleModule(engine_);
233     }
234 }
235 
InitLoop(bool isStage)236 bool JsEnvironment::InitLoop(bool isStage)
237 {
238     if (engine_ == nullptr) {
239         TAG_LOGE(AAFwkTag::JSENV, "Invalid Native Engine");
240         return false;
241     }
242 
243     if (impl_ != nullptr) {
244         impl_->InitLoop(engine_, isStage);
245     }
246     return true;
247 }
248 
DeInitLoop()249 void JsEnvironment::DeInitLoop()
250 {
251     if (engine_ == nullptr) {
252         TAG_LOGE(AAFwkTag::JSENV, "Invalid Native Engine");
253         return;
254     }
255 
256     if (impl_ != nullptr) {
257         impl_->DeInitLoop(engine_);
258     }
259 }
260 
LoadScript(const std::string & path,uint8_t * buffer,size_t len,bool isBundle)261 bool JsEnvironment::LoadScript(const std::string& path, uint8_t* buffer, size_t len, bool isBundle)
262 {
263     if (engine_ == nullptr) {
264         TAG_LOGE(AAFwkTag::JSENV, "Invalid Native Engine");
265         return false;
266     }
267 
268     auto start = std::chrono::high_resolution_clock::now();
269     bool ret = engine_->RunScriptBuffer(path, buffer, len, isBundle);
270     auto end = std::chrono::high_resolution_clock::now();
271     auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
272     TAG_LOGI(AAFwkTag::JSENV, "timing: %{public}lld", duration_ms);
273 
274     return ret;
275 }
276 
StartProfiler(const char * libraryPath,uint32_t instanceId,PROFILERTYPE profiler,int32_t interval,int tid,bool isDebugApp)277 void JsEnvironment::StartProfiler(const char* libraryPath, uint32_t instanceId, PROFILERTYPE profiler,
278     int32_t interval, int tid, bool isDebugApp)
279 {
280     if (vm_ == nullptr) {
281         TAG_LOGE(AAFwkTag::JSENV, "Invalid vm");
282         return;
283     }
284 
285     auto debuggerPostTask = [weak = weak_from_this()](std::function<void()>&& task) {
286         auto jsEnv = weak.lock();
287         if (jsEnv == nullptr) {
288             TAG_LOGE(AAFwkTag::JSENV, "JsEnv is invalid");
289             return;
290         }
291         jsEnv->PostTask(task, "JsEnvironment::StartProfiler");
292     };
293 
294     panda::DFXJSNApi::ProfilerOption option;
295     option.libraryPath = libraryPath;
296     option.profilerType = ConvertProfilerType(profiler);
297     option.interval = interval;
298 
299     panda::DFXJSNApi::StartProfiler(vm_, option, tid, instanceId, debuggerPostTask, isDebugApp);
300 }
301 
DestroyHeapProfiler()302 void JsEnvironment::DestroyHeapProfiler()
303 {
304     if (vm_ == nullptr) {
305         TAG_LOGE(AAFwkTag::JSENV, "Invalid vm");
306         return;
307     }
308     panda::DFXJSNApi::DestroyHeapProfiler(vm_);
309 }
310 
GetHeapPrepare()311 void JsEnvironment::GetHeapPrepare()
312 {
313     if (vm_ == nullptr) {
314         TAG_LOGE(AAFwkTag::JSENV, "Invalid vm");
315         return;
316     }
317     panda::DFXJSNApi::GetHeapPrepare(vm_);
318 }
319 
SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate> moduleCheckerDelegate)320 void JsEnvironment::SetModuleLoadChecker(const std::shared_ptr<ModuleCheckerDelegate> moduleCheckerDelegate)
321 {
322     if (engine_ == nullptr) {
323         TAG_LOGE(AAFwkTag::JSENV, "Invalid native engine");
324         return;
325     }
326 
327     engine_->SetModuleLoadChecker(moduleCheckerDelegate);
328 }
329 
ReInitJsEnvImpl(std::unique_ptr<JsEnvironmentImpl> impl)330 void JsEnvironment::ReInitJsEnvImpl(std::unique_ptr<JsEnvironmentImpl> impl)
331 {
332     TAG_LOGD(AAFwkTag::JSENV, "ReInit jsenv impl.");
333     impl_ = std::move(impl);
334 }
335 
SetRequestAotCallback(const RequestAotCallback & cb)336 void JsEnvironment::SetRequestAotCallback(const RequestAotCallback& cb)
337 {
338     if (vm_ == nullptr) {
339         TAG_LOGE(AAFwkTag::JSENV, "Invalid vm");
340         return;
341     }
342 
343     panda::JSNApi::SetRequestAotCallback(vm_, cb);
344 }
345 
SetDeviceDisconnectCallback(const std::function<bool ()> & cb)346 void JsEnvironment::SetDeviceDisconnectCallback(const std::function<bool()> &cb)
347 {
348     panda::JSNApi::SetDeviceDisconnectCallback(vm_, std::move(cb));
349 }
350 
GetDebuggerPostTask()351 DebuggerPostTask JsEnvironment::GetDebuggerPostTask()
352 {
353     auto debuggerPostTask = [weak = weak_from_this()](std::function<void()>&& task) {
354         auto jsEnv = weak.lock();
355         if (jsEnv == nullptr) {
356             TAG_LOGE(AAFwkTag::JSENV, "JsEnv is invalid");
357             return;
358         }
359         jsEnv->PostTask(task, "JsEnvironment:GetDebuggerPostTask");
360     };
361     return debuggerPostTask;
362 }
363 
NotifyDebugMode(int tid,const char * libraryPath,uint32_t instanceId,bool debug,bool debugMode)364 void JsEnvironment::NotifyDebugMode(
365     int tid, const char* libraryPath, uint32_t instanceId, bool debug, bool debugMode)
366 {
367     if (vm_ == nullptr) {
368         TAG_LOGE(AAFwkTag::JSENV, "Invalid vm");
369         return;
370     }
371     panda::JSNApi::DebugOption debugOption = {libraryPath, debug ? debugMode : false};
372     auto debuggerPostTask = [weak = weak_from_this()](std::function<void()>&& task) {
373         auto jsEnv = weak.lock();
374         if (jsEnv == nullptr) {
375             TAG_LOGE(AAFwkTag::JSENV, "JsEnv is invalid");
376             return;
377         }
378         jsEnv->PostTask(task, "JsEnvironment:NotifyDebugMode");
379     };
380     panda::JSNApi::NotifyDebugMode(tid, vm_, debugOption, instanceId, debuggerPostTask, debug);
381 }
382 
ParseHdcRegisterOption(std::string & option)383 int32_t JsEnvironment::ParseHdcRegisterOption(std::string& option)
384 {
385     TAG_LOGD(AAFwkTag::JSENV, "Start");
386     std::size_t pos = option.find_first_of(":");
387     if (pos == std::string::npos) {
388         return -1;
389     }
390     std::string idStr = option.substr(pos + 1);
391     pos = idStr.find(DEBUGGER);
392     if (pos == std::string::npos) {
393         return -1;
394     }
395     idStr = idStr.substr(0, pos);
396     pos = idStr.find("@");
397     if (pos != std::string::npos) {
398         idStr = idStr.substr(pos + 1);
399     }
400     return std::atoi(idStr.c_str());
401 }
402 
GetDebugMode() const403 bool JsEnvironment::GetDebugMode() const
404 {
405     return debugMode_;
406 }
407 } // namespace JsEnv
408 } // namespace OHOS
409