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