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
28 using 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
40 namespace {
41 const std::string DEBUGGER = "@Debugger";
42 const std::string SANDBOX_LIB_PATH = "/data/storage/el1/bundle/libs/" APP_LIB_NAME;
43 const std::string CJ_RT_PATH = SANDBOX_LIB_PATH + "/runtime";
44 const std::string CJ_LIB_PATH = SANDBOX_LIB_PATH + "/ohos";
45 const std::string CJ_SYSLIB_PATH = "/system/lib64:/system/lib64/platformsdk:/system/lib64/module:/system/lib64/ndk";
46 const 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
52 namespace OHOS {
LoadInstance()53 CJEnvMethods* 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 }
70 AppLibPathVec CJRuntime::appLibPaths_;
71
72 std::string CJRuntime::packageName_;
73
Create(const Options& options)74 std::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
SetAppLibPath(const AppLibPathMap& appLibPaths)83 void 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
Initialize(const Options& options)104 bool 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
RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo& uncaughtExceptionInfo)132 void 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
IsCJAbility(const std::string& info)142 bool 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
LoadCJAppLibrary(const AppLibPathVec& appLibPaths)149 bool 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
SetPackageName(std::string srcEntryName)179 void 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
SetSanitizerVersion(SanitizerKind kind)186 void 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
StartDebugMode(const DebugOption dOption)196 void 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
StartDebugger()233 bool 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
UnLoadCJAppLibrary()243 void CJRuntime::UnLoadCJAppLibrary()
244 {
245 TAG_LOGI(AAFwkTag::CJRUNTIME, "UnLoadCJAppLibrary not support yet");
246 }
247