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_runtime.h" 17 18#include <dlfcn.h> 19#include <unistd.h> 20#include <filesystem> 21#include <regex> 22 23#include "cj_envsetup.h" 24#include "hilog_tag_wrapper.h" 25#include "hdc_register.h" 26#include "connect_server_manager.h" 27 28using namespace OHOS::AbilityRuntime; 29 30#ifdef APP_USE_ARM64 31#define APP_LIB_NAME "arm64" 32#elif defined(APP_USE_ARM) 33#define APP_LIB_NAME "arm" 34#elif defined(APP_USE_X86_64) 35#define APP_LIB_NAME "x86_64" 36#else 37#error unsupported platform 38#endif 39 40namespace { 41const std::string DEBUGGER = "@Debugger"; 42const std::string SANDBOX_LIB_PATH = "/data/storage/el1/bundle/libs/" APP_LIB_NAME; 43const std::string CJ_RT_PATH = SANDBOX_LIB_PATH + "/runtime"; 44const std::string CJ_LIB_PATH = SANDBOX_LIB_PATH + "/ohos"; 45const std::string CJ_SYSLIB_PATH = "/system/lib64:/system/lib64/platformsdk:/system/lib64/module:/system/lib64/ndk"; 46const std::string CJ_CHIPSDK_PATH = "/system/lib64/chipset-pub-sdk"; 47} // namespace 48 49#define LIB_NAME "libcj_environment.z.so" 50#define GET_ENV_INS_NAME "OHOS_GetCJEnvInstance" 51 52namespace OHOS { 53CJEnvMethods* CJEnv::LoadInstance() 54{ 55 auto handle = dlopen(LIB_NAME, RTLD_NOW); 56 if (!handle) { 57 TAG_LOGE(AAFwkTag::CJRUNTIME, "dlopen failed %{public}s, %{public}s", LIB_NAME, dlerror()); 58 return nullptr; 59 } 60 auto symbol = dlsym(handle, GET_ENV_INS_NAME); 61 if (!symbol) { 62 TAG_LOGE(AAFwkTag::CJRUNTIME, "dlsym failed %{public}s, %{public}s", GET_ENV_INS_NAME, dlerror()); 63 dlclose(handle); 64 return nullptr; 65 } 66 auto func = reinterpret_cast<CJEnvMethods* (*)()>(symbol); 67 return func(); 68} 69} 70AppLibPathVec CJRuntime::appLibPaths_; 71 72std::string CJRuntime::packageName_; 73 74std::unique_ptr<CJRuntime> CJRuntime::Create(const Options& options) 75{ 76 auto instance = std::make_unique<CJRuntime>(); 77 if (!instance || !instance->Initialize(options)) { 78 return nullptr; 79 } 80 return instance; 81} 82 83void CJRuntime::SetAppLibPath(const AppLibPathMap& appLibPaths) 84{ 85 std::string appPath = ""; 86 for (const auto& kv : appLibPaths) { 87 for (const auto& libPath : kv.second) { 88 TAG_LOGD(AAFwkTag::CJRUNTIME, "SetCJAppLibPath: %{public}s.", libPath.c_str()); 89 CJRuntime::appLibPaths_.emplace_back(libPath); 90 appPath += appPath.empty() ? libPath : ":" + libPath; 91 } 92 } 93 auto cjEnv = OHOS::CJEnv::LoadInstance(); 94 if (cjEnv == nullptr) { 95 TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed."); 96 return; 97 } 98 cjEnv->initCJChipSDKNS(CJ_CHIPSDK_PATH); 99 cjEnv->initCJAppNS(appPath); 100 cjEnv->initCJSDKNS(CJ_RT_PATH + ":" + CJ_LIB_PATH); 101 cjEnv->initCJSysNS(CJ_SYSLIB_PATH); 102} 103 104bool CJRuntime::Initialize(const Options& options) 105{ 106 if (options.lang != GetLanguage()) { 107 TAG_LOGE(AAFwkTag::CJRUNTIME, "CJRuntime Initialize fail, language mismatch"); 108 return false; 109 } 110 auto cjEnv = OHOS::CJEnv::LoadInstance(); 111 if (cjEnv == nullptr) { 112 TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed."); 113 return false; 114 } 115 if (!cjEnv->startRuntime()) { 116 TAG_LOGE(AAFwkTag::CJRUNTIME, "start cj runtime failed"); 117 return false; 118 } 119 if (!cjEnv->startUIScheduler()) { 120 TAG_LOGE(AAFwkTag::CJRUNTIME, "start cj ui context failed"); 121 return false; 122 } 123 if (!LoadCJAppLibrary(CJRuntime::appLibPaths_)) { 124 TAG_LOGE(AAFwkTag::CJRUNTIME, "CJRuntime::Initialize fail, load app library fail."); 125 return false; 126 } 127 bundleName_ = options.bundleName; 128 instanceId_ = static_cast<uint32_t>(getproctid()); 129 return true; 130} 131 132void CJRuntime::RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo& uncaughtExceptionInfo) 133{ 134 auto cjEnv = OHOS::CJEnv::LoadInstance(); 135 if (cjEnv == nullptr) { 136 TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed."); 137 return; 138 } 139 cjEnv->registerCJUncaughtExceptionHandler(uncaughtExceptionInfo); 140} 141 142bool CJRuntime::IsCJAbility(const std::string& info) 143{ 144 // in cj application, the srcEntry format should be packageName.AbilityClassName. 145 std::string pattern = "^([a-zA-Z0-9_]+\\.)+[a-zA-Z0-9_]+$"; 146 return std::regex_match(info, std::regex(pattern)); 147} 148 149bool CJRuntime::LoadCJAppLibrary(const AppLibPathVec& appLibPaths) 150{ 151 auto cjEnv = OHOS::CJEnv::LoadInstance(); 152 if (cjEnv == nullptr) { 153 TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed."); 154 return false; 155 } 156 void* handle = nullptr; 157 // According to the OHOS rule, the format of the SO name is as follows 158 auto targetSoName = "lib" + packageName_ + ".so"; 159 160 for (const auto& libPath : appLibPaths) { 161 for (auto& itor : std::filesystem::directory_iterator(libPath)) { 162 // According to the convention, the names of cj generated products must contain the following keywords 163 if (itor.path().string().find(targetSoName) == std::string::npos) { 164 continue; 165 } 166 handle = cjEnv->loadCJLibrary(itor.path().c_str()); 167 if (handle == nullptr) { 168 char* errMsg = dlerror(); 169 TAG_LOGE(AAFwkTag::CJRUNTIME, 170 "Failed to load %{public}s : reason: %{public}s.", itor.path().c_str(), errMsg ? errMsg : "null"); 171 return false; 172 } 173 } 174 } 175 appLibLoaded_ = true; 176 return true; 177} 178 179void CJRuntime::SetPackageName(std::string srcEntryName) 180{ 181 // According to the srcEntry rule in the Cangjie application, 182 // the last '.' The previous strings were all package names 183 packageName_ = srcEntryName.substr(0, srcEntryName.find_last_of(".")); 184} 185 186void CJRuntime::SetSanitizerVersion(SanitizerKind kind) 187{ 188 auto cjEnv = OHOS::CJEnv::LoadInstance(); 189 if (cjEnv == nullptr) { 190 TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed."); 191 return; 192 } 193 cjEnv->setSanitizerKindRuntimeVersion(kind); 194} 195 196void CJRuntime::StartDebugMode(const DebugOption dOption) 197{ 198 if (debugModel_) { 199 TAG_LOGI(AAFwkTag::CJRUNTIME, "Already in debug mode"); 200 return; 201 } 202 203 bool isStartWithDebug = dOption.isStartWithDebug; 204 bool isDebugApp = dOption.isDebugApp; 205 const std::string bundleName = bundleName_; 206 std::string inputProcessName = bundleName_ != dOption.processName ? dOption.processName : ""; 207 208 TAG_LOGI(AAFwkTag::CJRUNTIME, "StartDebugMode %{public}s", bundleName_.c_str()); 209 210 HdcRegister::Get().StartHdcRegister(bundleName_, inputProcessName, isDebugApp, 211 [bundleName, isStartWithDebug, isDebugApp](int socketFd, std::string option) { 212 TAG_LOGI(AAFwkTag::CJRUNTIME, 213 "HdcRegister callback is call, socket fd is %{public}d, option is %{public}s.", 214 socketFd, option.c_str()); 215 if (option.find(DEBUGGER) == std::string::npos) { 216 if (!isDebugApp) { 217 ConnectServerManager::Get().StopConnectServer(false); 218 } 219 ConnectServerManager::Get().SendDebuggerInfo(isStartWithDebug, isDebugApp); 220 ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false); 221 } else { 222 TAG_LOGE(AAFwkTag::CJRUNTIME, "debugger service unexpected option: %{public}s", option.c_str()); 223 } 224 }); 225 if (isDebugApp) { 226 ConnectServerManager::Get().StartConnectServer(bundleName_, -1, true); 227 } 228 ConnectServerManager::Get().AddInstance(instanceId_, instanceId_); 229 230 debugModel_ = StartDebugger(); 231} 232 233bool CJRuntime::StartDebugger() 234{ 235 auto cjEnv = OHOS::CJEnv::LoadInstance(); 236 if (cjEnv == nullptr) { 237 TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed."); 238 return false; 239 } 240 return cjEnv->startDebugger(); 241} 242 243void CJRuntime::UnLoadCJAppLibrary() 244{ 245 TAG_LOGI(AAFwkTag::CJRUNTIME, "UnLoadCJAppLibrary not support yet"); 246} 247