• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 <cstddef>
17 #include <string>
18 #include <variant>
19 #include <vector>
20 #include <map>
21 #include <securec.h>
22 
23 // NOLINTBEGIN
24 
25 #ifdef TS_INTEROP_MODULE
26 #undef TS_INTEROP_MODULE
27 #endif
28 
29 #define TS_INTEROP_MODULE InteropNativeModule
30 #include "interop-logging.h"
31 #include "convertors-napi.h"
32 #include "common-interop.h"
33 
34 #if TS_INTEROP_PROFILER
35 #include "profiler.h"
36 
37 InteropProfiler *InteropProfiler::_instance = nullptr;
38 
39 #endif
40 
41 using std::string;
42 
43 // Callback dispatcher MOVED to convertors-napi.cc.
44 // Let's keep platform-specific parts of the code together
45 
46 typedef void (*HoldT)(KInt);
47 
impl_getTypeOfVariant(KNativePointer varPtr)48 KInt impl_getTypeOfVariant(KNativePointer varPtr)
49 {
50     auto *var = reinterpret_cast<std::variant<int, std::string> *>(varPtr);
51     if (std::get_if<int>(var) != nullptr) {
52         return 0;
53     } else {
54         return 1;
55     }
56 }
TS_INTEROP_1(getTypeOfVariant,KInt,KNativePointer)57 TS_INTEROP_1(getTypeOfVariant, KInt, KNativePointer)
58 
59 KNativePointer impl_getStringFromVariant(KNativePointer varPtr)
60 {
61     auto *var = reinterpret_cast<std::variant<int, std::string> *>(varPtr);
62     auto *res = new std::string(*std::get_if<std::string>(var));
63     return res;
64 }
TS_INTEROP_1(getStringFromVariant,KNativePointer,KNativePointer)65 TS_INTEROP_1(getStringFromVariant, KNativePointer, KNativePointer)
66 
67 KInt impl_getIntFromVariant(KNativePointer varPtr)
68 {
69     auto *var = reinterpret_cast<std::variant<int, std::string> *>(varPtr);
70     auto res = *std::get_if<int>(var);
71     return res;
72 }
TS_INTEROP_1(getIntFromVariant,KInt,KNativePointer)73 TS_INTEROP_1(getIntFromVariant, KInt, KNativePointer)
74 
75 KInteropBuffer impl_MaterializeBuffer(KNativePointer data, KLong length, KInt resourceId, KNativePointer holdPtr,
76                                       KNativePointer releasePtr)
77 {
78     auto hold = reinterpret_cast<void (*)(KInt)>(holdPtr);
79     auto release = reinterpret_cast<void (*)(KInt)>(releasePtr);
80     hold(resourceId);
81     return KInteropBuffer {length, data, resourceId, release};
82 }
TS_INTEROP_5(MaterializeBuffer,KInteropBuffer,KNativePointer,KLong,KInt,KNativePointer,KNativePointer)83 TS_INTEROP_5(MaterializeBuffer, KInteropBuffer, KNativePointer, KLong, KInt, KNativePointer, KNativePointer)
84 
85 KNativePointer impl_GetNativeBufferPointer(KInteropBuffer buffer)
86 {
87     return buffer.data;
88 }
TS_INTEROP_1(GetNativeBufferPointer,KNativePointer,KInteropBuffer)89 TS_INTEROP_1(GetNativeBufferPointer, KNativePointer, KInteropBuffer)
90 
91 KInt impl_StringLength(KNativePointer ptr)
92 {
93     auto *s = reinterpret_cast<string *>(ptr);
94     return s->length();
95 }
TS_INTEROP_1(StringLength,KInt,KNativePointer)96 TS_INTEROP_1(StringLength, KInt, KNativePointer)
97 
98 void impl_StringData(KNativePointer ptr, KByte *bytes, KUInt size)
99 {
100     auto *s = reinterpret_cast<string *>(ptr);
101     if (s != nullptr) {
102         memcpy_s(bytes, size, s->c_str(), size);
103     }
104 }
TS_INTEROP_V3(StringData,KNativePointer,KByte *,KUInt)105 TS_INTEROP_V3(StringData, KNativePointer, KByte *, KUInt)
106 
107 KNativePointer impl_StringMake(const KStringPtr &str)
108 {
109     return new string(str.c_str());
110 }
TS_INTEROP_1(StringMake,KNativePointer,KStringPtr)111 TS_INTEROP_1(StringMake, KNativePointer, KStringPtr)
112 
113 // For slow runtimes w/o fast encoders.
114 KInt impl_ManagedStringWrite(const KStringPtr &str, KByte *buffer, KInt offset)
115 {
116     memcpy_s(buffer + offset, str.length() + 1, str.c_str(), str.length() + 1);
117     return str.length() + 1;
118 }
TS_INTEROP_3(ManagedStringWrite,KInt,KStringPtr,KByte *,KInt)119 TS_INTEROP_3(ManagedStringWrite, KInt, KStringPtr, KByte *, KInt)
120 
121 void stringFinalizer(string *ptr)
122 {
123     delete ptr;
124 }
impl_GetStringFinalizer()125 KNativePointer impl_GetStringFinalizer()
126 {
127     return fnPtr<string>(stringFinalizer);
128 }
TS_INTEROP_0(GetStringFinalizer,KNativePointer)129 TS_INTEROP_0(GetStringFinalizer, KNativePointer)
130 
131 void impl_InvokeFinalizer(KNativePointer obj, KNativePointer finalizer)
132 {
133     auto finalizerF = reinterpret_cast<void (*)(KNativePointer)>(finalizer);
134     finalizerF(obj);
135 }
TS_INTEROP_V2(InvokeFinalizer,KNativePointer,KNativePointer)136 TS_INTEROP_V2(InvokeFinalizer, KNativePointer, KNativePointer)
137 
138 KInt impl_GetPtrVectorSize(KNativePointer ptr)
139 {
140     auto *vec = reinterpret_cast<std::vector<void *> *>(ptr);
141     return vec->size();
142 }
TS_INTEROP_1(GetPtrVectorSize,KInt,KNativePointer)143 TS_INTEROP_1(GetPtrVectorSize, KInt, KNativePointer)
144 
145 KNativePointer impl_GetPtrVectorElement(KNativePointer ptr, KInt index)
146 {
147     auto vector = reinterpret_cast<std::vector<void *> *>(ptr);
148     auto element = vector->at(index);
149     return element;
150 }
TS_INTEROP_2(GetPtrVectorElement,KNativePointer,KNativePointer,KInt)151 TS_INTEROP_2(GetPtrVectorElement, KNativePointer, KNativePointer, KInt)
152 
153 inline KUInt UnpackUInt(const KByte *bytes)
154 {
155     return (bytes[0] | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24));
156 }
157 
MakeStringVector(KStringArray strArray)158 std::vector<KStringPtr> MakeStringVector(KStringArray strArray)
159 {
160     if (strArray == nullptr) {
161         return std::vector<KStringPtr>(0);
162     }
163     KUInt arraySize = UnpackUInt(strArray);
164     std::vector<KStringPtr> res(arraySize);
165     size_t offset = sizeof(KUInt);
166     for (KUInt i = 0; i < arraySize; ++i) {
167         int len = UnpackUInt(strArray + offset);
168         res[i].assign((const char *)(strArray + offset + sizeof(KUInt)), len);
169         offset += len + sizeof(KUInt);
170     }
171     return res;
172 }
173 
MakeStringVector(KNativePointerArray arr,KInt length)174 std::vector<KStringPtr> MakeStringVector(KNativePointerArray arr, KInt length)
175 {
176     if (arr == nullptr) {
177         return std::vector<KStringPtr>(0);
178     } else {
179         std::vector<KStringPtr> res(length);
180         char **strings = reinterpret_cast<char **>(arr);
181         for (KInt i = 0; i < length; ++i) {
182             const char *str = reinterpret_cast<const char *>(strings[i]);
183             res[i].assign(str);
184         }
185         return res;
186     }
187 }
188 
189 typedef KInt (*LoadVirtualMachine_t)(KInt vmKind, const char *classPath, const char *libraryPath,
190                                      void *currentVMContext);
191 typedef KNativePointer (*StartApplication_t)(const char *appUrl, const char *appParams);
192 typedef KBoolean (*RunApplication_t)(const KInt arg0, const KInt arg1);
193 typedef void (*EmitEventT)(const KInt type, const KInt target, const KInt arg0, const KInt arg1);
194 
195 static CallbackCallert g_callbackCaller = nullptr;
setCallbackCaller(CallbackCallert callbackCaller)196 void setCallbackCaller(CallbackCallert callbackCaller)
197 {
198     g_callbackCaller = callbackCaller;
199 }
200 
impl_CallCallback(KInt callbackKind,KByte * args,KInt argsSize)201 void impl_CallCallback(KInt callbackKind, KByte *args, KInt argsSize)
202 {
203     if (g_callbackCaller != nullptr) {
204         g_callbackCaller(callbackKind, args, argsSize);
205     }
206 }
207 TS_INTEROP_V3(CallCallback, KInt, KByte *, KInt)
208 
209 static CallbackCallerSynct g_callbackCallerSync = nullptr;
setCallbackCallerSync(CallbackCallerSynct callbackCallerSync)210 void setCallbackCallerSync(CallbackCallerSynct callbackCallerSync)
211 {
212     g_callbackCallerSync = callbackCallerSync;
213 }
214 
impl_CallCallbackSync(KVMContext vmContext,KInt callbackKind,KByte * args,KInt argsSize)215 void impl_CallCallbackSync(KVMContext vmContext, KInt callbackKind, KByte *args, KInt argsSize)
216 {
217     if (g_callbackCallerSync) {
218         g_callbackCallerSync(vmContext, callbackKind, args, argsSize);
219     }
220 }
TS_INTEROP_CTX_V3(CallCallbackSync,KInt,KByte *,KInt)221 TS_INTEROP_CTX_V3(CallCallbackSync, KInt, KByte *, KInt)
222 
223 void impl_CallCallbackResourceHolder(KNativePointer holder, KInt resourceId)
224 {
225     reinterpret_cast<void (*)(KInt)>(holder)(resourceId);
226 }
TS_INTEROP_V2(CallCallbackResourceHolder,KNativePointer,KInt)227 TS_INTEROP_V2(CallCallbackResourceHolder, KNativePointer, KInt)
228 
229 void impl_CallCallbackResourceReleaser(KNativePointer releaser, KInt resourceId)
230 {
231     reinterpret_cast<void (*)(KInt)>(releaser)(resourceId);
232 }
TS_INTEROP_V2(CallCallbackResourceReleaser,KNativePointer,KInt)233 TS_INTEROP_V2(CallCallbackResourceReleaser, KNativePointer, KInt)
234 
235 // CC-OFFNXT(G.EXP.01) false positive
236 #define __QUOTE(x) #x
237 #define QUOTE(x) __QUOTE(x)
238 
239 #ifndef INTEROP_LIBRARY_NAME
240 #error "INTEROP_LIBRARY_NAME must be defined"
241 #endif
242 
243 void impl_NativeLog(const KStringPtr &str)
244 {
245     fprintf(stdout, "%s: %s\n", QUOTE(INTEROP_LIBRARY_NAME), str.c_str());
246     fflush(stdout);
247 }
TS_INTEROP_V1(NativeLog,KStringPtr)248 TS_INTEROP_V1(NativeLog, KStringPtr)
249 
250 int32_t callCallback(KVMContext context, int32_t methodId, uint8_t *argsData, int32_t argsLength)
251 {
252     TS_INTEROP_CALL_INT(context, methodId, argsLength, argsData);
253     return 0;
254 }
255 
resolveDeferred(KVMDeferred * deferred,uint8_t * argsData,int32_t argsLength)256 void resolveDeferred(KVMDeferred *deferred, [[maybe_unused]] uint8_t *argsData, [[maybe_unused]] int32_t argsLength)
257 {
258     napi_acquire_threadsafe_function((napi_threadsafe_function)deferred->handler);
259     auto status =
260         napi_call_threadsafe_function((napi_threadsafe_function)deferred->handler, deferred, napi_tsfn_nonblocking);
261     if (status != napi_ok)
262         LOGE("cannot call thread-safe function; status=%d", status);
263     napi_release_threadsafe_function((napi_threadsafe_function)deferred->handler, napi_tsfn_release);
264 }
265 
rejectDeferred(KVMDeferred * deferred,const char * message)266 void rejectDeferred(KVMDeferred *deferred, [[maybe_unused]] const char *message)
267 {
268     napi_release_threadsafe_function((napi_threadsafe_function)deferred->handler, napi_tsfn_release);
269     delete deferred;
270 }
271 
resolveDeferredImpl(napi_env env,napi_value js_callback,KVMDeferred * deferred,void * data)272 void resolveDeferredImpl(napi_env env, [[maybe_unused]] napi_value js_callback, KVMDeferred *deferred,
273                          [[maybe_unused]] void *data)
274 {
275     napi_value undefined = nullptr;
276     napi_get_undefined(env, &undefined);
277     auto status = napi_resolve_deferred(env, (napi_deferred)deferred->context, undefined);
278     if (status != napi_ok)
279         LOGE("cannot resolve deferred; status=%d", status);
280     delete deferred;
281 }
282 
releaseDeferred(KVMDeferred * deferred)283 [[maybe_unused]] static void releaseDeferred(KVMDeferred *deferred)
284 {
285     delete deferred;
286 }
287 
CreateDeferred(KVMContext vmContext,KVMObjectHandle * promiseHandle)288 KVMDeferred *CreateDeferred(KVMContext vmContext, KVMObjectHandle *promiseHandle)
289 {
290     KVMDeferred *deferred = new KVMDeferred();
291     deferred->resolve = resolveDeferred;
292     deferred->reject = rejectDeferred;
293     // NOTE(khil): mb move\remove to interop!
294     napi_env env = (napi_env)vmContext;
295     napi_value promise;
296     napi_value resourceName;
297     size_t napiStrLen = 5;
298     napi_create_string_utf8(env, "Async", napiStrLen, &resourceName);
299     auto status = napi_create_promise(env, (napi_deferred *)&deferred->context, &promise);
300     if (status != napi_ok)
301         LOGE("cannot make a promise; status=%d", status);
302     status = napi_create_threadsafe_function(env, nullptr, nullptr, resourceName, 0, 1, nullptr, nullptr, deferred,
303                                              (napi_threadsafe_function_call_js)resolveDeferredImpl,
304                                              (napi_threadsafe_function *)&deferred->handler);
305     if (status != napi_ok)
306         LOGE("cannot make threadsafe function; status=%d", status);
307     *promiseHandle = (KVMObjectHandle)promise;
308     return deferred;
309 }
310 
311 // Allocate, so CTX versions.
impl_Utf8ToString(KVMContext vmContext,KByte * data,KInt offset,KInt length)312 KStringPtr impl_Utf8ToString([[maybe_unused]] KVMContext vmContext, KByte *data, KInt offset, KInt length)
313 {
314     KStringPtr result((const char *)(data + offset), length, false);
315     return result;
316 }
TS_INTEROP_CTX_3(Utf8ToString,KStringPtr,KByte *,KInt,KInt)317 TS_INTEROP_CTX_3(Utf8ToString, KStringPtr, KByte *, KInt, KInt)
318 
319 KStringPtr impl_StdStringToString([[maybe_unused]] KVMContext vmContext, KNativePointer stringPtr)
320 {
321     auto *str = reinterpret_cast<std::string *>(stringPtr);
322     KStringPtr result(str->c_str(), str->size(), false);
323     return result;
324 }
TS_INTEROP_CTX_1(StdStringToString,KStringPtr,KNativePointer)325 TS_INTEROP_CTX_1(StdStringToString, KStringPtr, KNativePointer)
326 
327 KInteropReturnBuffer impl_RawReturnData([[maybe_unused]] KVMContext vmContext, KInt v1, KInt v2)
328 {
329     void *data = new int8_t[v1];
330     memset_s(data, v2, v1, v2);
331     KInteropReturnBuffer buffer = {v1, data, [](KNativePointer ptr, KInt) { delete[](int8_t *) ptr; }};
332     return buffer;
333 }
334 TS_INTEROP_CTX_2(RawReturnData, KInteropReturnBuffer, KInt, KInt)
335 
336 // NOLINTEND
337