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