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 
Create(const Options & options)72 std::unique_ptr<CJRuntime> CJRuntime::Create(const Options& options)
73 {
74     auto instance = std::make_unique<CJRuntime>();
75     if (!instance || !instance->Initialize(options)) {
76         return nullptr;
77     }
78     return instance;
79 }
80 
SetAppLibPath(const AppLibPathMap & appLibPaths)81 void CJRuntime::SetAppLibPath(const AppLibPathMap& appLibPaths)
82 {
83     std::string appPath = "";
84     for (const auto& kv : appLibPaths) {
85         for (const auto& libPath : kv.second) {
86             TAG_LOGD(AAFwkTag::CJRUNTIME, "SetCJAppLibPath: %{public}s.", libPath.c_str());
87             CJRuntime::appLibPaths_.emplace_back(libPath);
88             appPath += appPath.empty() ? libPath : ":" + libPath;
89         }
90     }
91     auto cjEnv = OHOS::CJEnv::LoadInstance();
92     if (cjEnv == nullptr) {
93         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed.");
94         return;
95     }
96     cjEnv->initCJChipSDKNS(CJ_CHIPSDK_PATH);
97     cjEnv->initCJAppNS(appPath);
98     cjEnv->initCJSDKNS(CJ_RT_PATH + ":" + CJ_LIB_PATH);
99     cjEnv->initCJSysNS(CJ_SYSLIB_PATH);
100 }
101 
Initialize(const Options & options)102 bool CJRuntime::Initialize(const Options& options)
103 {
104     if (options.lang != GetLanguage()) {
105         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJRuntime Initialize fail, language mismatch");
106         return false;
107     }
108     auto cjEnv = OHOS::CJEnv::LoadInstance();
109     if (cjEnv == nullptr) {
110         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed.");
111         return false;
112     }
113     if (!cjEnv->startRuntime()) {
114         TAG_LOGE(AAFwkTag::CJRUNTIME, "start cj runtime failed");
115         return false;
116     }
117     if (!cjEnv->startUIScheduler()) {
118         TAG_LOGE(AAFwkTag::CJRUNTIME, "start cj ui context failed");
119         return false;
120     }
121     if (!LoadCJAppLibrary(CJRuntime::appLibPaths_)) {
122         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJRuntime::Initialize fail, load app library fail.");
123         return false;
124     }
125     bundleName_ = options.bundleName;
126     instanceId_ = static_cast<uint32_t>(getproctid());
127     return true;
128 }
129 
RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo & uncaughtExceptionInfo)130 void CJRuntime::RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo& uncaughtExceptionInfo)
131 {
132     auto cjEnv = OHOS::CJEnv::LoadInstance();
133     if (cjEnv == nullptr) {
134         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed.");
135         return;
136     }
137     cjEnv->registerCJUncaughtExceptionHandler(uncaughtExceptionInfo);
138 }
139 
IsCJAbility(const std::string & info)140 bool CJRuntime::IsCJAbility(const std::string& info)
141 {
142     // in cj application, the srcEntry format should be packageName.AbilityClassName.
143     std::string pattern = "^([a-zA-Z0-9_]+\\.)+[a-zA-Z0-9_]+$";
144     return std::regex_match(info, std::regex(pattern));
145 }
146 
LoadCJAppLibrary(const AppLibPathVec & appLibPaths)147 bool CJRuntime::LoadCJAppLibrary(const AppLibPathVec& appLibPaths)
148 {
149     auto cjEnv = OHOS::CJEnv::LoadInstance();
150     if (cjEnv == nullptr) {
151         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed.");
152         return false;
153     }
154     void* handle = nullptr;
155     for (const auto& libPath : appLibPaths) {
156         for (auto& itor : std::filesystem::directory_iterator(libPath)) {
157             // According to the convention, the names of cj generated products must contain the following keywords
158             if (itor.path().string().find("ohos_app_cangjie") == std::string::npos) {
159                 continue;
160             }
161             handle = cjEnv->loadCJLibrary(itor.path().c_str());
162             if (handle == nullptr) {
163                 char* errMsg = dlerror();
164                 TAG_LOGE(AAFwkTag::CJRUNTIME,
165                     "Failed to load %{public}s : reason: %{public}s.", itor.path().c_str(), errMsg ? errMsg : "null");
166                 return false;
167             }
168         }
169     }
170     appLibLoaded_ = true;
171     return true;
172 }
173 
SetAsanVersion()174 void CJRuntime::SetAsanVersion()
175 {
176     auto cjEnv = OHOS::CJEnv::LoadInstance();
177     if (cjEnv == nullptr) {
178         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed.");
179         return;
180     }
181     cjEnv->setSanitizerKindRuntimeVersion(SanitizerKind::ASAN);
182 }
183 
SetTsanVersion()184 void CJRuntime::SetTsanVersion()
185 {
186     auto cjEnv = OHOS::CJEnv::LoadInstance();
187     if (cjEnv == nullptr) {
188         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed.");
189         return;
190     }
191     cjEnv->setSanitizerKindRuntimeVersion(SanitizerKind::TSAN);
192 }
193 
SetHWAsanVersion()194 void CJRuntime::SetHWAsanVersion()
195 {
196     auto cjEnv = OHOS::CJEnv::LoadInstance();
197     if (cjEnv == nullptr) {
198         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed.");
199         return;
200     }
201     cjEnv->setSanitizerKindRuntimeVersion(SanitizerKind::HWASAN);
202 }
203 
StartDebugMode(const DebugOption dOption)204 void CJRuntime::StartDebugMode(const DebugOption dOption)
205 {
206     if (debugModel_) {
207         TAG_LOGI(AAFwkTag::CJRUNTIME, "Already in debug mode");
208         return;
209     }
210 
211     bool isStartWithDebug = dOption.isStartWithDebug;
212     bool isDebugApp = dOption.isDebugApp;
213     const std::string bundleName = bundleName_;
214     std::string inputProcessName = bundleName_ != dOption.processName ? dOption.processName : "";
215 
216     TAG_LOGI(AAFwkTag::CJRUNTIME, "StartDebugMode %{public}s", bundleName_.c_str());
217 
218     HdcRegister::Get().StartHdcRegister(bundleName_, inputProcessName, isDebugApp,
219         [bundleName, isStartWithDebug, isDebugApp](int socketFd, std::string option) {
220             TAG_LOGI(AAFwkTag::CJRUNTIME,
221                 "HdcRegister callback is call, socket fd is %{public}d, option is %{public}s.",
222                 socketFd, option.c_str());
223             if (option.find(DEBUGGER) == std::string::npos) {
224                 if (!isDebugApp) {
225                     ConnectServerManager::Get().StopConnectServer(false);
226                 }
227                 ConnectServerManager::Get().SendDebuggerInfo(isStartWithDebug, isDebugApp);
228                 ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false);
229             } else {
230                 TAG_LOGE(AAFwkTag::CJRUNTIME, "debugger service unexpected option: %{public}s", option.c_str());
231             }
232         });
233     if (isDebugApp) {
234         ConnectServerManager::Get().StartConnectServer(bundleName_, -1, true);
235     }
236     ConnectServerManager::Get().AddInstance(instanceId_, instanceId_);
237 
238     debugModel_ = StartDebugger();
239 }
240 
StartDebugger()241 bool CJRuntime::StartDebugger()
242 {
243     auto cjEnv = OHOS::CJEnv::LoadInstance();
244     if (cjEnv == nullptr) {
245         TAG_LOGE(AAFwkTag::CJRUNTIME, "CJEnv LoadInstance failed.");
246         return false;
247     }
248     return cjEnv->startDebugger();
249 }
250 
UnLoadCJAppLibrary()251 void CJRuntime::UnLoadCJAppLibrary()
252 {
253     TAG_LOGI(AAFwkTag::CJRUNTIME, "UnLoadCJAppLibrary not support yet");
254 }
255