1 /*
2 * Copyright (c) 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 "cj_environment.h"
17
18 #include <string>
19 #include <filesystem>
20 #include <mutex>
21 #include "cj_hilog.h"
22 #include "cj_invoker.h"
23 #ifdef __OHOS__
24 #include <dlfcn.h>
25 #endif
26 #include "dynamic_loader.h"
27 #ifdef WITH_EVENT_HANDLER
28 #include "event_handler.h"
29 #endif
30
31 #ifdef APP_USE_ARM64
32 #define APP_LIB_NAME "arm64"
33 #elif defined(APP_USE_ARM)
34 #define APP_LIB_NAME "arm"
35 #elif defined(APP_USE_X86_64)
36 #define APP_LIB_NAME "x86_64"
37 #elif defined(NAPI_TARGET_ARM64)
38 #define APP_LIB_NAME "arm64"
39 #else
40 #error unsupported platform
41 #endif
42
43 namespace {
44 const std::string SANDBOX_LIB_PATH = "/data/storage/el1/bundle/libs/" APP_LIB_NAME;
45 const std::string CJ_RT_PATH = SANDBOX_LIB_PATH + "/runtime";
46 const std::string CJ_LIB_PATH = SANDBOX_LIB_PATH + "/ohos";
47 const std::string CJ_SYSLIB_PATH = "/system/lib64:/system/lib64/platformsdk";
48 const std::string CJ_CHIPSDK_PATH = "/system/lib64/chipset-pub-sdk";
49 const std::string CJ_SDK_PATH = "/system/lib64/platformsdk/cjsdk";
50 } // namespace
51
52 namespace OHOS {
53 namespace {
54 const char DEBUGGER_LIBNAME[] = "libcj_debugger.z.so";
55 const char DEBUGGER_SYMBOL_NAME[] = "StartDebuggerServer";
56 const char INIT_CJRUNTIME_SYMBOL_NAME[] = "InitCJRuntime";
57 const char INIT_UISCHEDULER_SYMBOL_NAME[] = "InitUIScheduler";
58 const char RUN_UISCHEDULER_SYMBOL_NAME[] = "RunUIScheduler";
59 const char FINI_CJRUNTIME_SYMBOL_NAME[] = "FiniCJRuntime";
60 const char INIT_CJLIBRARY_SYMBOL_NAME[] = "InitCJLibrary";
61 const char REGISTER_EVENTHANDLER_CALLBACKS_NAME[] = "RegisterEventHandlerCallbacks";
62 const char REGISTER_ARKVM_SYMBOL_NAME[] = "RegisterArkVMInRuntime";
63 const char REGISTER_STACKINFO_CALLBACKS_NAME[] = "RegisterStackInfoCallbacks";
64
65 using InitCJRuntimeType = int(*)(const struct RuntimeParam*);;
66 using InitUISchedulerType = void*(*)();
67 using RunUISchedulerType = int(*)(unsigned long long);
68 using FiniCJRuntimeType = int(*)();
69 using InitCJLibraryType = int(*)(const char*);
70 using RegisterEventHandlerType = void(*)(PostTaskType, HasHigherPriorityType);
71 using RegisterArkVMType = void(*)(unsigned long long);
72 using RegisterStackInfoType = void(*)(UpdateStackInfoFuncType);
73
74 #ifdef __OHOS__
75 const char REGISTER_UNCAUGHT_EXCEPTION_NAME[] = "RegisterUncaughtExceptionHandler";
76 using RegisterUncaughtExceptionType = void (*)(const CJUncaughtExceptionInfo& handle);
77 #endif
78
79 #ifdef WITH_EVENT_HANDLER
80 static std::shared_ptr<AppExecFwk::EventHandler> g_handler = nullptr;
81 #endif
82
LoadSymbolInitCJRuntime(void * handle,CJRuntimeAPI & apis)83 bool LoadSymbolInitCJRuntime(void* handle, CJRuntimeAPI& apis)
84 {
85 auto symbol = DynamicFindSymbol(handle, INIT_CJRUNTIME_SYMBOL_NAME);
86 if (symbol == nullptr) {
87 LOGE("runtime api not found: %{public}s", INIT_CJRUNTIME_SYMBOL_NAME);
88 return false;
89 }
90 apis.InitCJRuntime = reinterpret_cast<InitCJRuntimeType>(symbol);
91 return true;
92 }
93
LoadSymbolInitUIScheduler(void * handle,CJRuntimeAPI & apis)94 bool LoadSymbolInitUIScheduler(void* handle, CJRuntimeAPI& apis)
95 {
96 auto symbol = DynamicFindSymbol(handle, INIT_UISCHEDULER_SYMBOL_NAME);
97 if (symbol == nullptr) {
98 LOGE("runtime api not found: %{public}s", INIT_UISCHEDULER_SYMBOL_NAME);
99 return false;
100 }
101 apis.InitUIScheduler = reinterpret_cast<InitUISchedulerType>(symbol);
102 return true;
103 }
104
LoadSymbolRunUIScheduler(void * handle,CJRuntimeAPI & apis)105 bool LoadSymbolRunUIScheduler(void* handle, CJRuntimeAPI& apis)
106 {
107 auto symbol = DynamicFindSymbol(handle, RUN_UISCHEDULER_SYMBOL_NAME);
108 if (symbol == nullptr) {
109 LOGE("runtime api not found: %{public}s", RUN_UISCHEDULER_SYMBOL_NAME);
110 return false;
111 }
112 apis.RunUIScheduler = reinterpret_cast<RunUISchedulerType>(symbol);
113 return true;
114 }
115
LoadSymbolFiniCJRuntime(void * handle,CJRuntimeAPI & apis)116 bool LoadSymbolFiniCJRuntime(void* handle, CJRuntimeAPI& apis)
117 {
118 auto symbol = DynamicFindSymbol(handle, FINI_CJRUNTIME_SYMBOL_NAME);
119 if (symbol == nullptr) {
120 LOGE("runtime api not found: %{public}s", FINI_CJRUNTIME_SYMBOL_NAME);
121 return false;
122 }
123 apis.FiniCJRuntime = reinterpret_cast<FiniCJRuntimeType>(symbol);
124 return true;
125 }
126
LoadSymbolInitCJLibrary(void * handle,CJRuntimeAPI & apis)127 bool LoadSymbolInitCJLibrary(void* handle, CJRuntimeAPI& apis)
128 {
129 auto symbol = DynamicFindSymbol(handle, INIT_CJLIBRARY_SYMBOL_NAME);
130 if (symbol == nullptr) {
131 LOGE("runtime api not found: %{public}s", INIT_CJLIBRARY_SYMBOL_NAME);
132 return false;
133 }
134 apis.InitCJLibrary = reinterpret_cast<InitCJLibraryType>(symbol);
135 return true;
136 }
137
LoadSymbolRegisterEventHandlerCallbacks(void * handle,CJRuntimeAPI & apis)138 bool LoadSymbolRegisterEventHandlerCallbacks(void* handle, CJRuntimeAPI& apis)
139 {
140 auto symbol = DynamicFindSymbol(handle, REGISTER_EVENTHANDLER_CALLBACKS_NAME);
141 if (symbol == nullptr) {
142 LOGE("runtime api not found: %{public}s", REGISTER_EVENTHANDLER_CALLBACKS_NAME);
143 return false;
144 }
145 apis.RegisterEventHandlerCallbacks = reinterpret_cast<RegisterEventHandlerType>(symbol);
146 return true;
147 }
148
LoadSymbolRegisterStackInfoCallbacks(void * handle,CJRuntimeAPI & apis)149 bool LoadSymbolRegisterStackInfoCallbacks(void* handle, CJRuntimeAPI& apis)
150 {
151 auto symbol = DynamicFindSymbol(handle, REGISTER_STACKINFO_CALLBACKS_NAME);
152 if (symbol == nullptr) {
153 LOGE("runtime api not found: %{public}s", REGISTER_STACKINFO_CALLBACKS_NAME);
154 // return true for compatible.
155 apis.RegisterStackInfoCallbacks = nullptr;
156 return true;
157 }
158 apis.RegisterStackInfoCallbacks = reinterpret_cast<RegisterStackInfoType>(symbol);
159 return true;
160 }
161
LoadSymbolRegisterArkVM(void * handle,CJRuntimeAPI & apis)162 bool LoadSymbolRegisterArkVM(void* handle, CJRuntimeAPI& apis)
163 {
164 auto symbol = DynamicFindSymbol(handle, REGISTER_ARKVM_SYMBOL_NAME);
165 if (symbol == nullptr) {
166 LOGE("runtime api not found: %{public}s", REGISTER_ARKVM_SYMBOL_NAME);
167 // return true for compatible.
168 apis.RegisterArkVMInRuntime = nullptr;
169 return true;
170 }
171 apis.RegisterArkVMInRuntime = reinterpret_cast<RegisterArkVMType>(symbol);
172 return true;
173 }
174
175 #ifdef __OHOS__
LoadSymbolRegisterCJUncaughtExceptionHandler(void * handle,CJRuntimeAPI & apis)176 bool LoadSymbolRegisterCJUncaughtExceptionHandler(void* handle, CJRuntimeAPI& apis)
177 {
178 auto symbol = DynamicFindSymbol(handle, REGISTER_UNCAUGHT_EXCEPTION_NAME);
179 if (symbol == nullptr) {
180 LOGE("runtime api not found: %{public}s", REGISTER_UNCAUGHT_EXCEPTION_NAME);
181 return false;
182 }
183 apis.RegisterCJUncaughtExceptionHandler = reinterpret_cast<RegisterUncaughtExceptionType>(symbol);
184 return true;
185 }
186 #endif
187
PostTaskWrapper(void * func)188 bool PostTaskWrapper(void* func)
189 {
190 return CJEnvironment::GetInstance()->PostTask(reinterpret_cast<TaskFuncType>(func));
191 }
192
HasHigherPriorityTaskWrapper()193 bool HasHigherPriorityTaskWrapper()
194 {
195 return CJEnvironment::GetInstance()->HasHigherPriorityTask();
196 }
197
198 CJEnvironment* instance_ = nullptr;
199 } // namespace
200
201 const char *CJEnvironment::cjAppNSName = "cj_app";
202 const char *CJEnvironment::cjSDKNSName = "cj_app_sdk";
203 const char *CJEnvironment::cjSysNSName = "cj_system";
204 const char *CJEnvironment::cjChipSDKNSName = "cj_chipsdk";
205 const char *CJEnvironment::cjNewAppNSName = "moduleNs_default";
206 const char *CJEnvironment::cjNewSDKNSName = "cj_rom_sdk";
207 const char *CJEnvironment::cjNewSysNSName = "default";
208 const char *CJEnvironment::cjNDKNSName = "ndk";
209
210 #ifdef WITH_EVENT_HANDLER
GetGHandler()211 static std::shared_ptr<AppExecFwk::EventHandler>GetGHandler()
212 {
213 if (g_handler == nullptr) {
214 g_handler = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
215 }
216 return g_handler;
217 }
218 #endif
219
InitSpawnEnv()220 void CJEnvironment::InitSpawnEnv()
221 {
222 #ifdef WITH_EVENT_HANDLER
223 GetGHandler();
224 #endif
225 instance_ = new CJEnvironment(NSMode::SINK);
226 instance_->PreloadLibs();
227 }
228
PreloadLibs()229 void CJEnvironment::PreloadLibs()
230 {
231 LOGI("start Preloadlibs");
232 auto lib = LoadCJLibrary(SDK, "libohos.ability.so");
233 if (lib) {
234 preloadLibs_.emplace_back(lib);
235 }
236 lib = LoadCJLibrary(SDK, "libohos.component.so");
237 if (lib) {
238 preloadLibs_.emplace_back(lib);
239 }
240 lib = LoadCJLibrary(SDK, "libohos.window.so");
241 if (lib) {
242 preloadLibs_.emplace_back(lib);
243 }
244 }
245
SetAppPath(const std::string & appPath)246 void CJEnvironment::SetAppPath(const std::string& appPath)
247 {
248 static bool isInited = false;
249 static std::mutex initMutex;
250 std::lock_guard<std::mutex> lock(initMutex);
251 if (isInited) {
252 return;
253 }
254 auto mode = DetectAppNSMode();
255 if (instance_) {
256 if (instance_->nsMode_ == mode) {
257 instance_->InitCJNS(appPath);
258 return;
259 }
260 delete instance_;
261 }
262 instance_ = new CJEnvironment(mode);
263 instance_->InitCJNS(appPath);
264 isInited = true;
265 }
266
CJEnvironment(NSMode mode)267 CJEnvironment::CJEnvironment(NSMode mode) : nsMode_(mode)
268 {
269 InitRuntimeNS();
270 LoadRuntimeApis();
271 }
272
~CJEnvironment()273 CJEnvironment::~CJEnvironment()
274 {
275 StopRuntime();
276
277 delete lazyApis_;
278
279 for (auto lib : preloadLibs_) {
280 dlclose(lib);
281 }
282 }
283
GetInstance()284 CJEnvironment* CJEnvironment::GetInstance()
285 {
286 return instance_;
287 }
288
RegisterCangjieCallback()289 bool CJEnvironment::RegisterCangjieCallback()
290 {
291 constexpr char CANGJIE_DEBUGGER_LIB_PATH[] = "libark_connect_inspector.z.so";
292 auto handlerConnectServerSo = LoadCJLibrary(CJEnvironment::SYSTEM, CANGJIE_DEBUGGER_LIB_PATH);
293 if (handlerConnectServerSo == nullptr) {
294 LOGE("null handlerConnectServerSo: %{public}s", dlerror());
295 return false;
296 }
297 using SendMsgCB = const std::function<void(const std::string& message)>;
298 using SetCangjieCallback = void(*)(const std::function<void(const std::string& message, SendMsgCB)>);
299 using CangjieCallback = void(*)(const std::string& message, SendMsgCB);
300 auto setCangjieCallback = reinterpret_cast<SetCangjieCallback>(
301 DynamicFindSymbol(handlerConnectServerSo, "SetCangjieCallback"));
302 if (setCangjieCallback == nullptr) {
303 LOGE("null setCangjieCallback: %{public}s", dlerror());
304 return false;
305 }
306 #define RTLIB_NAME "libcangjie-runtime.so"
307 auto dso = LoadCJLibrary(CJEnvironment::SDK, RTLIB_NAME);
308 if (!dso) {
309 LOGE("load library failed: %{public}s", RTLIB_NAME);
310 return false;
311 }
312 LOGE("load libcangjie-runtime.so success");
313 #define PROFILERAGENT "ProfilerAgent"
314 CangjieCallback cangjieCallback = reinterpret_cast<CangjieCallback>(DynamicFindSymbol(dso, PROFILERAGENT));
315 if (cangjieCallback == nullptr) {
316 dlclose(handlerConnectServerSo);
317 handlerConnectServerSo = nullptr;
318 LOGE("runtime api not found: %{public}s", PROFILERAGENT);
319 return false;
320 }
321 LOGE("find runtime api success");
322 setCangjieCallback(cangjieCallback);
323 dlclose(handlerConnectServerSo);
324 handlerConnectServerSo = nullptr;
325 return true;
326 }
327
LoadRuntimeApis()328 bool CJEnvironment::LoadRuntimeApis()
329 {
330 if (isRuntimeApiLoaded) {
331 return true;
332 }
333 lazyApis_ = new CJRuntimeAPI();
334 #ifdef __WINDOWS__
335 #define RTLIB_NAME "libcangjie-runtime.dll"
336 #else
337 #define RTLIB_NAME "libcangjie-runtime.so"
338 #endif
339 #ifdef __OHOS__
340 Dl_namespace ns;
341 dlns_get(nsMode_ == NSMode::APP ? cjSDKNSName : cjNewSDKNSName, &ns);
342 std::string runtimeLibName = "libcangjie-runtime";
343 runtimeLibName += ".so";
344 auto dso = DynamicLoadLibrary(&ns, runtimeLibName.c_str(), 1);
345 #else
346 auto dso = DynamicLoadLibrary(RTLIB_NAME, 1);
347 #endif
348 if (!dso) {
349 LOGE("load library failed: %{public}s", RTLIB_NAME);
350 return false;
351 }
352 #undef RTLIB_NAME
353 preloadLibs_.emplace_back(dso);
354 if (!LoadSymbolInitCJRuntime(dso, *lazyApis_) ||
355 !LoadSymbolInitUIScheduler(dso, *lazyApis_) ||
356 !LoadSymbolRunUIScheduler(dso, *lazyApis_) ||
357 !LoadSymbolFiniCJRuntime(dso, *lazyApis_) ||
358 !LoadSymbolInitCJLibrary(dso, *lazyApis_) ||
359 !LoadSymbolRegisterEventHandlerCallbacks(dso, *lazyApis_) ||
360 !LoadSymbolRegisterStackInfoCallbacks(dso, *lazyApis_) ||
361 !LoadSymbolRegisterArkVM(dso, *lazyApis_)) {
362 LOGE("load symbol failed");
363 DynamicFreeLibrary(dso);
364 return false;
365 }
366 #ifdef __OHOS__
367 if (!LoadSymbolRegisterCJUncaughtExceptionHandler(dso, *lazyApis_)) {
368 LOGE("load symbol RegisterCJUncaughtExceptionHandler failed");
369 DynamicFreeLibrary(dso);
370 return false;
371 }
372 #endif
373 isRuntimeApiLoaded = true;
374 return true;
375 }
376
RegisterArkVMInRuntime(unsigned long long externalVM)377 void CJEnvironment::RegisterArkVMInRuntime(unsigned long long externalVM)
378 {
379 if (lazyApis_->RegisterArkVMInRuntime == nullptr) {
380 return;
381 }
382 lazyApis_->RegisterArkVMInRuntime(externalVM);
383 }
384
RegisterStackInfoCallbacks(UpdateStackInfoFuncType uFunc)385 void CJEnvironment::RegisterStackInfoCallbacks(UpdateStackInfoFuncType uFunc)
386 {
387 if (lazyApis_->RegisterStackInfoCallbacks == nullptr) {
388 return;
389 }
390 lazyApis_->RegisterStackInfoCallbacks(uFunc);
391 }
392
RegisterCJUncaughtExceptionHandler(const CJUncaughtExceptionInfo & handle)393 void CJEnvironment::RegisterCJUncaughtExceptionHandler(const CJUncaughtExceptionInfo& handle)
394 {
395 lazyApis_->RegisterCJUncaughtExceptionHandler(handle);
396 }
397
PostTask(TaskFuncType task)398 bool CJEnvironment::PostTask(TaskFuncType task)
399 {
400 #ifdef WITH_EVENT_HANDLER
401 if (task == nullptr) {
402 LOGE("null task could not be posted");
403 return false;
404 }
405
406 bool postDone = GetGHandler()->PostTask(task, "spawn-main-task-from-cj", 0, AppExecFwk::EventQueue::Priority::HIGH);
407 if (!postDone) {
408 LOGE("event handler support cj ui scheduler");
409 return false;
410 }
411 return true;
412 #endif
413 return true;
414 }
415
HasHigherPriorityTask()416 bool CJEnvironment::HasHigherPriorityTask()
417 {
418 #ifdef WITH_EVENT_HANDLER
419 return GetGHandler()->HasPreferEvent(static_cast<int>(AppExecFwk::EventQueue::Priority::HIGH));
420 #endif
421 return false;
422 }
423
InitCJChipSDKNS(const std::string & path)424 void CJEnvironment::InitCJChipSDKNS(const std::string& path)
425 {
426 #ifdef __OHOS__
427 LOGI("InitCJChipSDKNS: %{public}s", path.c_str());
428 Dl_namespace chip_sdk;
429 DynamicInitNamespace(&chip_sdk, nullptr, path.c_str(), CJEnvironment::cjChipSDKNSName);
430
431 Dl_namespace cjnative;
432 Dl_namespace current;
433 dlns_get(nullptr, ¤t);
434 dlns_get(CJEnvironment::cjNDKNSName, &cjnative);
435 dlns_inherit(&chip_sdk, &cjnative, "allow_all_shared_libs");
436 dlns_inherit(&chip_sdk, ¤t, "allow_all_shared_libs");
437 #endif
438 }
439
InitNewCJChipSDKNS(const std::string & path)440 void CJEnvironment::InitNewCJChipSDKNS(const std::string& path)
441 {
442 #ifdef __OHOS__
443 LOGI("InitCJChipSDKNS: %{public}s", path.c_str());
444 Dl_namespace chip_sdk;
445 DynamicInitNewNamespace(&chip_sdk, path.c_str(), CJEnvironment::cjChipSDKNSName);
446 #endif
447 }
448
449 // Init app namespace
InitCJAppNS(const std::string & path)450 void CJEnvironment::InitCJAppNS(const std::string& path)
451 {
452 #ifdef __OHOS__
453 LOGI("InitCJAppNS: %{public}s", path.c_str());
454 Dl_namespace cjnative;
455 Dl_namespace sdk;
456 Dl_namespace ns;
457 Dl_namespace current;
458 DynamicInitNamespace(&ns, nullptr, path.c_str(), CJEnvironment::cjAppNSName);
459 dlns_get(CJEnvironment::cjNDKNSName, &cjnative);
460 dlns_get(nullptr, ¤t);
461 dlns_get(cjSDKNSName, &sdk);
462 dlns_inherit(&ns, &cjnative, "allow_all_shared_libs");
463 dlns_inherit(&cjnative, ¤t, "allow_all_shared_libs");
464 dlns_inherit(¤t, &cjnative, "allow_all_shared_libs");
465 dlns_inherit(&ns, &sdk, "allow_all_shared_libs");
466 #endif
467 }
468
InitNewCJAppNS(const std::string & path)469 void CJEnvironment::InitNewCJAppNS(const std::string& path)
470 {
471 #ifdef __OHOS__
472 LOGI("InitCJAppNS: %{public}s", path.c_str());
473 Dl_namespace ns;
474 DynamicInitNewNamespace(&ns, path.c_str(), CJEnvironment::cjNewAppNSName);
475 Dl_namespace sdk;
476 if (nsMode_ == NSMode::APP) {
477 Dl_namespace chip_sdk;
478 dlns_get(CJEnvironment::cjSDKNSName, &sdk);
479 dlns_get(CJEnvironment::cjChipSDKNSName, &chip_sdk);
480 dlns_inherit(&ns, &chip_sdk, "libssl_openssl.z.so");
481 } else {
482 dlns_get(CJEnvironment::cjNewSDKNSName, &sdk);
483 }
484 dlns_inherit(&ns, &sdk, "allow_all_shared_libs");
485 #endif
486 }
487
488 // Init cj sdk namespace
InitCJSDKNS(const std::string & path)489 void CJEnvironment::InitCJSDKNS(const std::string& path)
490 {
491 #ifdef __OHOS__
492 LOGI("InitCJSDKNS: %{public}s", path.c_str());
493 Dl_namespace ns;
494 DynamicInitNewNamespace(&ns, path.c_str(), cjSDKNSName);
495 #endif
496 }
497
InitNewCJSDKNS(const std::string & path)498 void CJEnvironment::InitNewCJSDKNS(const std::string& path)
499 {
500 #ifdef __OHOS__
501 LOGI("InitCJSDKNS: %{public}s", path.c_str());
502 Dl_namespace ns;
503 DynamicInitNewNamespace(&ns, path.c_str(), cjNewSDKNSName);
504 #endif
505 }
506
507 // Init cj system namespace
InitCJSysNS(const std::string & path)508 void CJEnvironment::InitCJSysNS(const std::string& path)
509 {
510 #ifdef __OHOS__
511 LOGI("InitCJSysNS: %{public}s", path.c_str());
512 Dl_namespace cj_sdk;
513 Dl_namespace cjnative;
514 Dl_namespace ns;
515 dlns_get(cjSDKNSName, &cj_sdk);
516 DynamicInitNamespace(&ns, &cj_sdk, path.c_str(), cjSysNSName);
517 dlns_get(CJEnvironment::cjNDKNSName, &cjnative);
518 dlns_inherit(&ns, &cjnative, "allow_all_shared_libs");
519 #endif
520 }
521
StartRuntime()522 bool CJEnvironment::StartRuntime()
523 {
524 if (isRuntimeStarted_) {
525 return true;
526 }
527
528 if (!LoadRuntimeApis()) {
529 LOGE("LoadRuntimeApis failed");
530 return false;
531 }
532
533 RuntimeParam rtParams {
534 .heapParam = {
535 .regionSize = 64,
536 .heapSize = 256 * 1024,
537 .exemptionThreshold= 0.8,
538 .heapUtilization = 0.8,
539 .heapGrowth = 0.15,
540 .allocationRate = 0,
541 .allocationWaitTime = 0,
542 },
543 .gcParam = {
544 .gcThreshold = 0,
545 .garbageThreshold = 0,
546 .gcInterval = 0,
547 .backupGCInterval = 0,
548 .gcThreads = 0,
549 },
550 .logParam = {
551 .logLevel = RTLOG_ERROR,
552 },
553 .coParam = {
554 .thStackSize = 2 * 1024,
555 .coStackSize = 2 * 1024,
556 .processorNum = 8,
557 }
558 };
559
560 auto status = lazyApis_->InitCJRuntime(&rtParams);
561 if (status != E_OK) {
562 LOGE("init cj runtime failed: %{public}d", status);
563 return false;
564 }
565
566 lazyApis_->RegisterEventHandlerCallbacks(PostTaskWrapper, HasHigherPriorityTaskWrapper);
567
568 isRuntimeStarted_ = true;
569 return true;
570 }
571
StopRuntime()572 void CJEnvironment::StopRuntime()
573 {
574 if (!isRuntimeStarted_) {
575 return;
576 }
577
578 if (isUISchedulerStarted_) {
579 StopUIScheduler();
580 }
581
582 auto code = lazyApis_->FiniCJRuntime();
583 if (code == E_OK) {
584 isRuntimeStarted_ = false;
585 }
586 }
587
StartUIScheduler()588 bool CJEnvironment::StartUIScheduler()
589 {
590 if (isUISchedulerStarted_) {
591 return true;
592 }
593
594 uiScheduler_ = lazyApis_->InitUIScheduler();
595 if (!uiScheduler_) {
596 LOGE("init cj ui scheduler failed");
597 return false;
598 }
599
600 isUISchedulerStarted_ = true;
601 return true;
602 }
603
StopUIScheduler()604 void CJEnvironment::StopUIScheduler()
605 {
606 isUISchedulerStarted_ = false;
607 }
608
LoadCJLibrary(const char * dlName)609 void* CJEnvironment::LoadCJLibrary(const char* dlName)
610 {
611 if (!StartRuntime()) {
612 LOGE("StartRuntime failed");
613 return nullptr;
614 }
615 auto handle = LoadCJLibrary(APP, dlName);
616 if (!handle) {
617 LOGE("load cj library failed: %{public}s", DynamicGetError());
618 return nullptr;
619 }
620
621 LOGI("LoadCJLibrary InitCJLibrary: %{public}s", dlName);
622 auto status = lazyApis_->InitCJLibrary(dlName);
623 if (status != E_OK) {
624 LOGE("InitCJLibrary failed: %{public}s", dlName);
625 UnLoadCJLibrary(handle);
626 return nullptr;
627 }
628 CJEnvironment::RegisterCangjieCallback();
629 isLoadCJLibrary_ = true;
630 return handle;
631 }
632
LoadCJLibrary(OHOS::CJEnvironment::LibraryKind kind,const char * dlName)633 void* CJEnvironment::LoadCJLibrary(OHOS::CJEnvironment::LibraryKind kind, const char* dlName)
634 {
635 #ifdef __OHOS__
636 Dl_namespace ns;
637 switch (kind) {
638 case APP:
639 dlns_get(CJEnvironment::cjNewAppNSName, &ns);
640 break;
641 case SYSTEM:
642 dlns_get(CJEnvironment::cjNewSysNSName, &ns);
643 break;
644 case SDK:
645 dlns_get(nsMode_ == NSMode::APP ? CJEnvironment::cjSDKNSName : CJEnvironment::cjNewSDKNSName, &ns);
646 break;
647 }
648 auto handle = DynamicLoadLibrary(&ns, dlName, 0);
649 #else
650 auto handle = DynamicLoadLibrary(dlName, 1);
651 #endif
652 if (!handle) {
653 LOGE("load cj library failed: %{public}s", DynamicGetError());
654 return nullptr;
655 }
656 isLoadCJLibrary_ = true;
657 return handle;
658 }
659
CheckLoadCJLibrary()660 bool CJEnvironment::CheckLoadCJLibrary()
661 {
662 return isLoadCJLibrary_;
663 }
664
UnLoadCJLibrary(void * handle)665 void CJEnvironment::UnLoadCJLibrary(void* handle)
666 {
667 DynamicFreeLibrary(handle);
668 }
669
GetSymbol(void * dso,const char * symbol)670 void* CJEnvironment::GetSymbol(void* dso, const char* symbol)
671 {
672 return DynamicFindSymbol(dso, symbol);
673 }
674
StartDebugger()675 bool CJEnvironment::StartDebugger()
676 {
677 #ifdef __OHOS__
678 Dl_namespace ns;
679 dlns_get(CJEnvironment::cjNewSysNSName, &ns);
680 auto handle = DynamicLoadLibrary(&ns, DEBUGGER_LIBNAME, 0);
681 #else
682 auto handle = DynamicLoadLibrary(DEBUGGER_LIBNAME, 0);
683 #endif
684 if (!handle) {
685 LOGE("failed to load library: %{public}s", DEBUGGER_LIBNAME);
686 return false;
687 }
688 auto symbol = DynamicFindSymbol(handle, DEBUGGER_SYMBOL_NAME);
689 if (!symbol) {
690 LOGE("failed to find symbol: %{public}s", DEBUGGER_SYMBOL_NAME);
691 DynamicFreeLibrary(handle);
692 return false;
693 }
694 auto func = reinterpret_cast<bool (*)(int, const std::string&)>(symbol);
695 std::string name = "PandaDebugger";
696 func(0, name);
697 return true;
698 }
699
DetectAppNSMode()700 CJEnvironment::NSMode CJEnvironment::DetectAppNSMode()
701 {
702 std::filesystem::path runtimePath(CJ_RT_PATH + "/libcangjie-runtime.so");
703 if (std::filesystem::exists(runtimePath)) {
704 return NSMode::APP;
705 } else {
706 return NSMode::SINK;
707 }
708 }
709
InitRuntimeNS()710 void CJEnvironment::InitRuntimeNS()
711 {
712 #ifdef __OHOS__
713 if (nsMode_ == NSMode::APP) {
714 InitNewCJChipSDKNS(CJ_CHIPSDK_PATH);
715 InitCJSDKNS(CJ_RT_PATH + ":" + CJ_LIB_PATH);
716 } else {
717 InitNewCJSDKNS(CJ_SDK_PATH);
718 }
719 #endif
720 }
721
InitCJNS(const std::string & appPath)722 void CJEnvironment::InitCJNS(const std::string& appPath)
723 {
724 #ifdef __OHOS__
725 InitNewCJAppNS(appPath.empty() ? SANDBOX_LIB_PATH : appPath);
726 #endif
727 StartRuntime();
728 StartUIScheduler();
729 }
730
CreateEnvMethods()731 CJEnvMethods* CJEnvironment::CreateEnvMethods()
732 {
733 static CJEnvMethods gCJEnvMethods {
734 .initCJAppNS = [](const std::string& path) {
735 // to keep compatibility with older version
736 CJEnvironment::SetAppPath(path);
737 },
738 .initCJSDKNS = [](const std::string& path) {
739 // @deprecated
740 },
741 .initCJSysNS = [](const std::string& path) {
742 // @deprecated
743 },
744 .initCJChipSDKNS = [](const std::string& path) {
745 // @deprecated
746 },
747 .startRuntime = [] {
748 return CJEnvironment::GetInstance()->StartRuntime();
749 },
750 .startUIScheduler = [] {
751 return CJEnvironment::GetInstance()->StartUIScheduler();
752 },
753 .loadCJModule = [](const char* dllName) {
754 return CJEnvironment::GetInstance()->LoadCJLibrary(dllName);
755 },
756 .loadLibrary = [](uint32_t kind, const char* dllName) {
757 return CJEnvironment::GetInstance()->LoadCJLibrary(static_cast<CJEnvironment::LibraryKind>(kind), dllName);
758 },
759 .getSymbol = [](void* handle, const char* dllName) {
760 return CJEnvironment::GetInstance()->GetSymbol(handle, dllName);
761 },
762 .loadCJLibrary = [](const char* dllName) {
763 return CJEnvironment::GetInstance()->LoadCJLibrary(dllName);
764 },
765 .startDebugger = []() {
766 return CJEnvironment::GetInstance()->StartDebugger();
767 },
768 .registerCJUncaughtExceptionHandler = [](const CJUncaughtExceptionInfo& handle) {
769 return CJEnvironment::GetInstance()->RegisterCJUncaughtExceptionHandler(handle);
770 },
771 .setSanitizerKindRuntimeVersion = [](SanitizerKind kind) {
772 return CJEnvironment::GetInstance()->SetSanitizerKindRuntimeVersion(kind);
773 },
774 .checkLoadCJLibrary = []() {
775 return CJEnvironment::GetInstance()->CheckLoadCJLibrary();
776 },
777 .registerArkVMInRuntime = [](unsigned long long arkVM) {
778 CJEnvironment::GetInstance()->RegisterArkVMInRuntime(arkVM);
779 },
780 .registerStackInfoCallbacks = [](UpdateStackInfoFuncType uFunc) {
781 CJEnvironment::GetInstance()->RegisterStackInfoCallbacks(uFunc);
782 }
783 };
784 return &gCJEnvMethods;
785 }
786
OHOS_InitSpawnEnv()787 CJ_EXPORT extern "C" void OHOS_InitSpawnEnv()
788 {
789 CJEnvironment::InitSpawnEnv();
790 }
791
OHOS_GetCJEnvInstance()792 CJ_EXPORT extern "C" CJEnvMethods* OHOS_GetCJEnvInstance()
793 {
794 return CJEnvironment::CreateEnvMethods();
795 }
796 }
797