• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &current);
434     dlns_get(CJEnvironment::cjNDKNSName, &cjnative);
435     dlns_inherit(&chip_sdk, &cjnative, "allow_all_shared_libs");
436     dlns_inherit(&chip_sdk, &current, "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, &current);
461     dlns_get(cjSDKNSName, &sdk);
462     dlns_inherit(&ns, &cjnative, "allow_all_shared_libs");
463     dlns_inherit(&cjnative, &current, "allow_all_shared_libs");
464     dlns_inherit(&current, &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