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