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