• 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 <native_engine/native_engine.h>
17 
18 #include "node_api.h"
19 #include "ark_interop_log.h"
20 #include "cj_envsetup.h"
21 
22 #include <mutex>
23 #include <map>
24 
25 #ifdef USE_LIBS_ARM64
26 #define LIBS_NAME "arm64"
27 #elif defined(USE_LIBS_ARM)
28 #define LIBS_NAME "arm"
29 #elif defined(USE_LIBS_x86_64)
30 #define LIBS_NAME "x86_64"
31 #else
32 #error current platform not supported
33 #endif
34 
35 static std::mutex g_mutex;
36 static bool g_isInited = false;
37 static std::map<napi_env, std::map<std::string, napi_ref>> envMap = {};
38 
ParseLoadParams(napi_env env,napi_callback_info info,char * nameBuf,size_t & size)39 static bool ParseLoadParams(napi_env env, napi_callback_info info, char* nameBuf, size_t& size)
40 {
41     napi_value libNameValue;
42     size_t argCount = 1;
43     auto status = napi_get_cb_info(env, info, &argCount, &libNameValue, nullptr, nullptr);
44     if (status != napi_ok) {
45         napi_throw_error(env, "napi call fail", "napi_get_cb_info failed");
46         return false;
47     }
48 
49     if (argCount != 1) {
50         napi_throw_error(env, "argument invalid", "need one argument");
51         return false;
52     }
53 
54     napi_valuetype valuetype;
55     status = napi_typeof(env, libNameValue, &valuetype);
56     if (status != napi_ok) {
57         napi_throw_error(env, "napi call fail", "napi_typeof failed");
58         return false;
59     }
60     if (valuetype != napi_string) {
61         napi_throw_error(env, "argument invalid", "need a string");
62         return false;
63     }
64 
65     status = napi_get_value_string_utf8(env, libNameValue, nameBuf, size, &size);
66     if (status != napi_ok) {
67         napi_throw_error(env, "argument invalid", "napi_get_value_string_utf8 not ok");
68         return false;
69     }
70     return true;
71 }
72 
LoadArkCJModule(void * handle,napi_env env,const char * libName,napi_value * result)73 static bool LoadArkCJModule(void *handle, napi_env env, const char* libName, napi_value* result)
74 {
75     auto engine = reinterpret_cast<NativeEngine*>(env);
76     std::lock_guard<std::mutex> lock(g_mutex);
77     std::string str(libName);
78     if (envMap.find(env) != envMap.end() && envMap[env].find(str) != envMap[env].end()) {
79         napi_value callback = nullptr;
80         napi_get_reference_value(env, envMap[env][str], &callback);
81         *result = callback;
82         return true;
83     }
84     auto runtime = OHOS::CJEnv::LoadInstance();
85     if (handle == nullptr) {
86         LOGE("get handle failed");
87         return false;
88     }
89     if (runtime == nullptr) {
90         LOGE("load Instance failed");
91         return false;
92     }
93     if (auto symbol = runtime->getSymbol(handle, "ARKTS_LoadModuleByNapiEnv")) {
94         auto loader = reinterpret_cast<napi_value(*)(napi_env, const char*)>(symbol);
95         *result = loader(env, libName);
96     } else if (auto symbol = runtime->getSymbol(handle, "ARKTS_LoadModule")) {
97         auto loader = reinterpret_cast<napi_value(*)(EcmaVM*, const char*)>(symbol);
98         auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
99         *result = loader(vm, libName);
100     } else {
101         return false;
102     }
103     napi_ref callbackRef = nullptr;
104     napi_create_reference(env, *result, 1, &callbackRef);
105     envMap[env][str] = callbackRef;
106 
107     return true;
108 }
109 
GetArkInteropLibHandle(napi_env env)110 static void *GetArkInteropLibHandle(napi_env env)
111 {
112     const char* targetName;
113 #ifdef __OHOS__
114     targetName = "libark_interop.z.so";
115 #elif defined(__WINDOWS__)
116     targetName = "libark_interop.dll";
117 #elif defined(__LINUX__)
118     targetName = "libark_interop.so";
119 #endif
120     auto runtime = OHOS::CJEnv::LoadInstance();
121     if (!runtime) {
122         LOGE("load Instance failed");
123         return nullptr;
124     }
125     auto handle = runtime->loadLibrary(0, targetName);
126     if (!handle) {
127         LOGE("open '%{public}s' failed", targetName);
128         return nullptr;
129     }
130     return handle;
131 }
132 
RegisterStackInfoCallbacks(void * arkInteropLibHandle)133 static bool RegisterStackInfoCallbacks(void *arkInteropLibHandle)
134 {
135     auto runtime = OHOS::CJEnv::LoadInstance();
136     if (!runtime) {
137         LOGE("load Instance failed");
138         return false;
139     }
140     auto updateStackInfoFunc = runtime->getSymbol(arkInteropLibHandle, "ARKTS_UpdateStackInfo");
141     if (updateStackInfoFunc == nullptr) {
142         LOGE("load symbol ARKTS_UpdateStackInfo failed");
143         return false;
144     }
145     runtime->registerStackInfoCallbacks(
146         reinterpret_cast<void(*)(unsigned long long, void *, unsigned int)>(updateStackInfoFunc)
147     );
148     return true;
149 }
150 
LoadCJModule(napi_env env,napi_callback_info info)151 static napi_value LoadCJModule(napi_env env, napi_callback_info info)
152 {
153     napi_value result;
154     if (napi_get_undefined(env, &result) != napi_ok) {
155         return result;
156     }
157     constexpr size_t BUF_SIZE = 256;
158     char nameBuf[BUF_SIZE];
159     size_t realSize = BUF_SIZE;
160     void *arkInteropHandle = nullptr;
161     if (!ParseLoadParams(env, info, nameBuf, realSize)) {
162         return result;
163     }
164     if (!g_isInited) {
165         std::lock_guard<std::mutex> lock(g_mutex);
166         if (!g_isInited) {
167             auto runtime = OHOS::CJEnv::LoadInstance();
168             if (!runtime) {
169                 LOGE("load Instance failed");
170                 return result;
171             }
172             runtime->initCJChipSDKNS("/system/lib64/chipset-pub-sdk");
173             runtime->initCJAppNS("/data/storage/el1/bundle/libs/" LIBS_NAME);
174             runtime->initCJSDKNS("/data/storage/el1/bundle/libs/" LIBS_NAME "/ohos:"
175                                  "/data/storage/el1/bundle/libs/" LIBS_NAME "/runtime");
176             runtime->initCJSysNS("/system/lib64:/system/lib64/platformsdk:/system/lib64/module:/system/lib64/ndk");
177             if (!runtime->startRuntime()) {
178                 LOGE("start cjruntime failed");
179                 return result;
180             }
181             arkInteropHandle = GetArkInteropLibHandle(env);
182             RegisterStackInfoCallbacks(arkInteropHandle);
183             auto engine = reinterpret_cast<NativeEngine*>(env);
184             auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
185             auto vmAddr = static_cast<unsigned long long>(reinterpret_cast<uintptr_t>(vm));
186             runtime->registerArkVMInRuntime(vmAddr);
187             if (!runtime->startUIScheduler()) {
188                 LOGE("start cj ui context failed");
189                 return result;
190             }
191             g_isInited = true;
192         }
193     }
194     if (!arkInteropHandle) {
195         arkInteropHandle = GetArkInteropLibHandle(env);
196     }
197     LoadArkCJModule(arkInteropHandle, env, nameBuf, &result);
198     return result;
199 }
200 
ExportLoadCJModule(napi_env env,napi_value exports)201 static napi_value ExportLoadCJModule(napi_env env, napi_value exports)
202 {
203     static napi_property_descriptor desc[] = {
204         {"requireCJLib", nullptr, LoadCJModule, nullptr, nullptr, nullptr, napi_default, nullptr}
205     };
206     napi_define_properties(env, exports, sizeof(desc) / sizeof(napi_property_descriptor), desc);
207     return exports;
208 }
209 
LoadCJModuleRegister()210 extern "C" __attribute__((constructor)) void LoadCJModuleRegister()
211 {
212     static napi_module callbackModule = {
213         .nm_version = 1,
214         .nm_flags = 0,
215         .nm_filename = nullptr,
216         .nm_register_func = ExportLoadCJModule,
217         .nm_modname = "cjLibLoader",
218         .nm_priv = nullptr,
219         .reserved = { 0 },
220     };
221     napi_module_register(&callbackModule);
222 }
223