• 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 "hitrace_meter.h"
26 #include "hdc_register.h"
27 #include "connect_server_manager.h"
28 
29 using namespace OHOS::AbilityRuntime;
30 
31 
32 namespace {
33 const std::string DEBUGGER = "@Debugger";
34 } // namespace
35 
36 #define LIB_NAME "libcj_environment.z.so"
37 #define GET_ENV_INS_NAME "OHOS_GetCJEnvInstance"
38 
39 namespace OHOS {
LoadInstance()40 CJEnvMethods* CJEnv::LoadInstance()
41 {
42     auto handle = dlopen(LIB_NAME, RTLD_NOW);
43     if (!handle) {
44         TAG_LOGE(AAFwkTag::CJRUNTIME, "dlopen failed %{public}s, %{public}s", LIB_NAME, dlerror());
45         return nullptr;
46     }
47     auto symbol = dlsym(handle, GET_ENV_INS_NAME);
48     if (!symbol) {
49         TAG_LOGE(AAFwkTag::CJRUNTIME, "dlsym failed %{public}s, %{public}s", GET_ENV_INS_NAME, dlerror());
50         dlclose(handle);
51         return nullptr;
52     }
53     auto func = reinterpret_cast<CJEnvMethods* (*)()>(symbol);
54     return func();
55 }
56 }
57 AppLibPathVec CJRuntime::appLibPaths_;
58 
59 std::string CJRuntime::packageName_;
60 
Create(const Options & options)61 std::unique_ptr<CJRuntime> CJRuntime::Create(const Options& options)
62 {
63     auto instance = std::make_unique<CJRuntime>();
64     if (!instance || !instance->Initialize(options)) {
65         return nullptr;
66     }
67     return instance;
68 }
69 
SetAppLibPath(const AppLibPathMap & appLibPaths)70 void CJRuntime::SetAppLibPath(const AppLibPathMap& appLibPaths)
71 {
72     HITRACE_METER_NAME(HITRACE_TAG_APP, "Initialize cangjie runtime and namespace");
73     std::string appPath = "";
74     for (const auto& kv : appLibPaths) {
75         for (const auto& libPath : kv.second) {
76             TAG_LOGD(AAFwkTag::CJRUNTIME, "SetCJAppLibPath: %{public}s.", libPath.c_str());
77             CJRuntime::appLibPaths_.emplace_back(libPath);
78             appPath += appPath.empty() ? libPath : ":" + libPath;
79         }
80     }
81     auto cjEnv = OHOS::CJEnv::LoadInstance();
82     if (cjEnv == nullptr) {
83         TAG_LOGE(AAFwkTag::CJRUNTIME, "null cjEnv");
84         return;
85     }
86 
87     cjEnv->initCJAppNS(appPath);
88 }
89 
Initialize(const Options & options)90 bool CJRuntime::Initialize(const Options& options)
91 {
92     if (options.lang != GetLanguage()) {
93         TAG_LOGE(AAFwkTag::CJRUNTIME, "language mismatch");
94         return false;
95     }
96     auto cjEnv = OHOS::CJEnv::LoadInstance();
97     if (cjEnv == nullptr) {
98         TAG_LOGE(AAFwkTag::CJRUNTIME, "null cjEnv");
99         return false;
100     }
101     if (!cjEnv->startRuntime()) {
102         TAG_LOGE(AAFwkTag::CJRUNTIME, "start cj runtime failed");
103         return false;
104     }
105     if (!cjEnv->startUIScheduler()) {
106         TAG_LOGE(AAFwkTag::CJRUNTIME, "start cj ui context failed");
107         return false;
108     }
109     if (!LoadCJAppLibrary(CJRuntime::appLibPaths_)) {
110         TAG_LOGE(AAFwkTag::CJRUNTIME, "load app library fail");
111         return false;
112     }
113     bundleName_ = options.bundleName;
114     instanceId_ = static_cast<uint32_t>(getproctid());
115     return true;
116 }
117 
RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo & uncaughtExceptionInfo)118 void CJRuntime::RegisterUncaughtExceptionHandler(const CJUncaughtExceptionInfo& uncaughtExceptionInfo)
119 {
120     auto cjEnv = OHOS::CJEnv::LoadInstance();
121     if (cjEnv == nullptr) {
122         TAG_LOGE(AAFwkTag::CJRUNTIME, "null cjEnv");
123         return;
124     }
125     cjEnv->registerCJUncaughtExceptionHandler(uncaughtExceptionInfo);
126 }
127 
IsCJAbility(const std::string & info)128 bool CJRuntime::IsCJAbility(const std::string& info)
129 {
130     // in cj application, the srcEntry format should be packageName.AbilityClassName.
131     std::string pattern = "^([a-zA-Z0-9_]+\\.)+[a-zA-Z0-9_]+$";
132     return std::regex_match(info, std::regex(pattern));
133 }
134 
LoadCJAppLibrary(const AppLibPathVec & appLibPaths)135 bool CJRuntime::LoadCJAppLibrary(const AppLibPathVec& appLibPaths)
136 {
137     HITRACE_METER_NAME(HITRACE_TAG_APP, __PRETTY_FUNCTION__);
138     auto cjEnv = OHOS::CJEnv::LoadInstance();
139     if (cjEnv == nullptr) {
140         TAG_LOGE(AAFwkTag::CJRUNTIME, "null cjEnv");
141         return false;
142     }
143     void* handle = nullptr;
144     // According to the OHOS rule, the format of the SO name is as follows
145     auto targetSoName = "lib" + packageName_ + ".so";
146 
147     for (const auto& libPath : appLibPaths) {
148         for (auto& itor : std::filesystem::directory_iterator(libPath)) {
149             // According to the convention, the names of cj generated products must contain the following keywords
150             if (itor.path().string().find(targetSoName) == std::string::npos) {
151                 continue;
152             }
153             handle = cjEnv->loadCJLibrary(itor.path().c_str());
154             if (handle == nullptr) {
155                 char* errMsg = dlerror();
156                 TAG_LOGE(AAFwkTag::CJRUNTIME,
157                     "load %{public}s failed, reason: %{public}s", itor.path().c_str(), errMsg ? errMsg : "null");
158                 return false;
159             }
160         }
161     }
162     appLibLoaded_ = true;
163     return true;
164 }
165 
SetPackageName(std::string srcEntryName)166 void CJRuntime::SetPackageName(std::string srcEntryName)
167 {
168     // According to the srcEntry rule in the Cangjie application,
169     // the last '.' The previous strings were all package names
170     packageName_ = srcEntryName.substr(0, srcEntryName.find_last_of("."));
171 }
172 
SetSanitizerVersion(SanitizerKind kind)173 void CJRuntime::SetSanitizerVersion(SanitizerKind kind)
174 {
175     auto cjEnv = OHOS::CJEnv::LoadInstance();
176     if (cjEnv == nullptr) {
177         TAG_LOGE(AAFwkTag::CJRUNTIME, "null cjEnv");
178         return;
179     }
180     cjEnv->setSanitizerKindRuntimeVersion(kind);
181 }
182 
RegisterCangjieCallback()183 bool CJRuntime::RegisterCangjieCallback()
184 {
185     auto cjEnv = OHOS::CJEnv::LoadInstance();
186     constexpr char CANGJIE_DEBUGGER_LIB_PATH[] = "libark_connect_inspector.z.so";
187     #define LIBARARYKIND_SYS 0
188     auto handlerConnectServerSo = cjEnv->loadLibrary(LIBARARYKIND_SYS, CANGJIE_DEBUGGER_LIB_PATH);
189     if (handlerConnectServerSo == nullptr) {
190         TAG_LOGE(AAFwkTag::CJRUNTIME, "null handlerConnectServerSo: %{public}s", dlerror());
191         return false;
192     }
193     using SendMsgCB = const std::function<void(const std::string& message)>;
194     using SetCangjieCallback = void(*)(const std::function<void(const std::string& message, SendMsgCB)>);
195     using CangjieCallback = void(*)(const std::string& message, SendMsgCB);
196     auto setCangjieCallback = reinterpret_cast<SetCangjieCallback>(
197         cjEnv->getSymbol(handlerConnectServerSo, "SetCangjieCallback"));
198     if (setCangjieCallback == nullptr) {
199         TAG_LOGE(AAFwkTag::CJRUNTIME, "null setCangjieCallback: %{public}s", dlerror());
200         return false;
201     }
202     #define RTLIB_NAME "libcangjie-runtime.so"
203     #define LIBARARYKIND_SDK 1
204     auto dso = cjEnv->loadLibrary(LIBARARYKIND_SDK, RTLIB_NAME);
205     if (!dso) {
206         TAG_LOGE(AAFwkTag::CJRUNTIME, "load library failed: %{public}s", RTLIB_NAME);
207         return false;
208     }
209     TAG_LOGE(AAFwkTag::CJRUNTIME, "load libcangjie-runtime.so success");
210     #define PROFILERAGENT "ProfilerAgent"
211     CangjieCallback cangjieCallback = reinterpret_cast<CangjieCallback>(cjEnv->getSymbol(dso, PROFILERAGENT));
212     if (cangjieCallback == nullptr) {
213         TAG_LOGE(AAFwkTag::CJRUNTIME, "runtime api not found: %{public}s", PROFILERAGENT);
214         dlclose(handlerConnectServerSo);
215         handlerConnectServerSo = nullptr;
216         return false;
217     }
218     TAG_LOGE(AAFwkTag::CJRUNTIME, "find runtime api success");
219     setCangjieCallback(cangjieCallback);
220     dlclose(handlerConnectServerSo);
221     handlerConnectServerSo = nullptr;
222     return true;
223 }
224 
StartDebugMode(const DebugOption dOption)225 void CJRuntime::StartDebugMode(const DebugOption dOption)
226 {
227     if (debugModel_) {
228         TAG_LOGI(AAFwkTag::CJRUNTIME, "already debug mode");
229         return;
230     }
231 
232     bool isStartWithDebug = dOption.isStartWithDebug;
233     bool isDebugApp = dOption.isDebugApp;
234     const std::string bundleName = bundleName_;
235     int32_t instanceId = static_cast<int32_t>(instanceId_);
236     std::string inputProcessName = bundleName_ != dOption.processName ? dOption.processName : "";
237 
238     TAG_LOGI(AAFwkTag::CJRUNTIME, "StartDebugMode %{public}s", bundleName_.c_str());
239 
240     HdcRegister::Get().StartHdcRegister(bundleName_, inputProcessName, isDebugApp,
241         HdcRegister::DebugRegisterMode::HDC_DEBUG_REG,
242         [bundleName, isStartWithDebug, isDebugApp, instanceId](int socketFd, std::string option) {
243             TAG_LOGI(AAFwkTag::CJRUNTIME, "hdcRegister callback call, socket fd: %{public}d, option: %{public}s.",
244                 socketFd, option.c_str());
245             if (option.find(DEBUGGER) == std::string::npos) {
246                 ConnectServerManager::Get().StopConnectServer(false);
247                 TAG_LOGI(AAFwkTag::CJRUNTIME, "start SendInstanceMessage");
248                 ConnectServerManager::Get().SendInstanceMessage(instanceId, instanceId, bundleName);
249                 ConnectServerManager::Get().SendDebuggerInfo(isStartWithDebug, isDebugApp);
250                 ConnectServerManager::Get().StartConnectServer(bundleName, socketFd, false);
251                 CJRuntime::RegisterCangjieCallback();
252             } else {
253                 TAG_LOGE(AAFwkTag::CJRUNTIME, "debugger service unexpected option: %{public}s", option.c_str());
254             }
255         });
256     if (isDebugApp) {
257         ConnectServerManager::Get().StartConnectServer(bundleName_, -1, true);
258     }
259     ConnectServerManager::Get().AddInstance(instanceId_, instanceId_);
260 
261     debugModel_ = StartDebugger();
262 }
263 
StartDebugger()264 bool CJRuntime::StartDebugger()
265 {
266     auto cjEnv = OHOS::CJEnv::LoadInstance();
267     if (cjEnv == nullptr) {
268         TAG_LOGE(AAFwkTag::CJRUNTIME, "null cjEnv");
269         return false;
270     }
271     return cjEnv->startDebugger();
272 }
273 
UnLoadCJAppLibrary()274 void CJRuntime::UnLoadCJAppLibrary()
275 {
276     TAG_LOGI(AAFwkTag::CJRUNTIME, "UnLoadCJAppLibrary not support yet");
277 }
278