• 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 <unordered_map>
17 
18 #include "ark_interop_internal.h"
19 #include "ark_interop_external.h"
20 #include "ark_interop_log.h"
21 #include "cj_envsetup.h"
22 
23 struct ARKTS_ModuleCallbacks {
24     ARKTS_Value (*exportModule)(ARKTS_Env env, const char* dllName, ARKTS_Value exports) = nullptr;
25     bool (*hasModuleHandle)(const char* dllName) = nullptr;
26     void (*throwJSError)(ARKTS_Env env, ARKTS_Value) = nullptr;
27     void (*throwNativeError)(const char*) = nullptr;
28     void (*deleteArrayBufferRawData)(void* buffer, int64_t lambdaId) = nullptr;
29     void (*deleteExternal)(int64_t id, ARKTS_Env env) = nullptr;
30     ARKTS_Value (*invokerLambda)(ARKTS_CallInfo, int64_t lambdaId) = nullptr;
31     void (*deleteLambda)(ARKTS_Env env, int64_t lambdaId) = nullptr;
32     void (*invokeAsyncLambda)(ARKTS_Env env, int64_t lambdaId) = nullptr;
33     void (*deleteJSContext)(ARKTS_Env env) = nullptr;
34 };
35 
36 namespace {
37 // each native register only be available during module loading
38 ARKTS_ModuleCallbacks* g_cjModuleCallbacks = nullptr;
39 }
40 
ARKTSInner_ThrowJSErrorToCJ(ARKTS_Env env,ARKTS_Value error)41 bool ARKTSInner_ThrowJSErrorToCJ(ARKTS_Env env, ARKTS_Value error)
42 {
43     if (!g_cjModuleCallbacks) {
44         LOGE("napi module depends on another napi module is forbidden");
45         return false;
46     }
47     g_cjModuleCallbacks->throwJSError(env, error);
48     return true;
49 }
50 
ARKTSInner_ThrowNativeErrorToCJ(const char * error)51 bool ARKTSInner_ThrowNativeErrorToCJ(const char* error)
52 {
53     if (!g_cjModuleCallbacks) {
54         LOGE("napi module depends on another napi module is forbidden");
55         return false;
56     }
57     g_cjModuleCallbacks->throwNativeError(error);
58     return true;
59 }
60 
ARKTS_SetCJModuleCallback(ARKTS_ModuleCallbacks * callback)61 void ARKTS_SetCJModuleCallback(ARKTS_ModuleCallbacks* callback)
62 {
63     if (!callback) {
64         LOGE("register empty module callback is senseless");
65         return;
66     }
67     if (g_cjModuleCallbacks) {
68         LOGE("should never happen");
69         return;
70     }
71     g_cjModuleCallbacks = new ARKTS_ModuleCallbacks(*callback);
72 }
73 
74 // export but only for internal
ARKTS_LoadModule(ARKTS_Env env,const char * dllName)75 panda::JSValueRef* ARKTS_LoadModule(ARKTS_Env env, const char* dllName)
76 {
77     LOGD("ARKTS_LoadCJModule start: %{public}s", dllName);
78     // HandleScope
79     auto scope = ARKTS_OpenScope(env);
80 
81     auto undefined = ARKTS_CreateUndefined();
82     auto runtime = OHOS::CJEnv::LoadInstance();
83     if (!runtime) {
84         return ARKTSInner_Escape(env, scope, undefined);
85     }
86 
87     if (!runtime->startRuntime()) {
88         LOGE("start cj runtime failed");
89         return ARKTSInner_Escape(env, scope, undefined);
90     }
91     if (!g_cjModuleCallbacks || !g_cjModuleCallbacks->hasModuleHandle(dllName)) {
92         if (!runtime->loadCJModule(dllName)) {
93             LOGE("load cj library failed, try load as native");
94             return ARKTSInner_Escape(env, scope, undefined);
95         }
96     }
97 
98     if (!g_cjModuleCallbacks) {
99         LOGE("cj module must dependent on ohos_ark_interop");
100         return ARKTSInner_Escape(env, scope, undefined);
101     }
102 
103     auto exports = ARKTS_CreateObject(env);
104 
105     exports = g_cjModuleCallbacks->exportModule(env, dllName, exports);
106 
107     return ARKTSInner_Escape(env, scope, exports);
108 }
109 
ARKTS_LoadModuleByNapiEnv(void * env,const char * dllName)110 EXPORT panda::JSValueRef* ARKTS_LoadModuleByNapiEnv(void* env, const char* dllName)
111 {
112     if (!env) {
113         LOGE("env is null");
114         return nullptr;
115     }
116     if (!dllName) {
117         LOGE("dllName is null");
118         return nullptr;
119     }
120     auto engine = reinterpret_cast<NativeEngine*>(env);
121     auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
122     if (!vm) {
123         LOGE("vm is null");
124         return nullptr;
125     }
126     auto loop = engine->GetUVLoop();
127     if (!loop) {
128         LOGE("uvloop is null");
129         return nullptr;
130     }
131     if (!ARKTSInner_InitLoop(reinterpret_cast<ARKTS_Env>(vm), loop)) {
132         LOGE("init loop failed");
133         return nullptr;
134     }
135     return ARKTS_LoadModule(reinterpret_cast<ARKTS_Env>(vm), dllName);
136 }
137 
ARKTSInner_CJArrayBufferDeleter(void *,void * buffer,void * lambdaId)138 void ARKTSInner_CJArrayBufferDeleter(void*, void* buffer, void* lambdaId)
139 {
140     if (!g_cjModuleCallbacks) {
141         LOGE("native ark-interop library has no registered module");
142         return;
143     }
144     g_cjModuleCallbacks->deleteArrayBufferRawData(buffer,
145         reinterpret_cast<int64_t>(lambdaId));
146 }
147 
ARKTSInner_CJExternalDeleter(void *,void * data,void * env)148 void ARKTSInner_CJExternalDeleter(void*, void* data, void* env)
149 {
150     if (!g_cjModuleCallbacks) {
151         LOGE("native ark-interop library has no registered module");
152         return;
153     }
154     g_cjModuleCallbacks->deleteExternal(
155         reinterpret_cast<int64_t>(data),
156         reinterpret_cast<ARKTS_Env>(env)
157     );
158 }
159 
ARKTSInner_CJLambdaInvoker(ARKTS_CallInfo callInfo,int64_t lambdaId)160 ARKTS_Result ARKTSInner_CJLambdaInvoker(ARKTS_CallInfo callInfo, int64_t lambdaId)
161 {
162     auto env = ARKTS_GetCallEnv(callInfo);
163     auto scope = ARKTS_OpenScope(env);
164 
165     if (!g_cjModuleCallbacks) {
166         LOGE("native ark-interop library has no registered module");
167         return ARKTS_Return(env, scope, ARKTS_CreateUndefined());
168     }
169 
170     auto result = g_cjModuleCallbacks->invokerLambda(callInfo, lambdaId);
171     return ARKTS_Return(env, scope, result);
172 }
173 
ARKTSInner_CJLambdaDeleter(ARKTS_Env env,int64_t lambdaId)174 void ARKTSInner_CJLambdaDeleter(ARKTS_Env env, int64_t lambdaId)
175 {
176     if (!g_cjModuleCallbacks) {
177         LOGE("native ark-interop library has no registered module");
178         return;
179     }
180 
181     g_cjModuleCallbacks->deleteLambda(env, lambdaId);
182 }
183 
ARKTSInner_CJAsyncCallback(ARKTS_Env env,void * data)184 void ARKTSInner_CJAsyncCallback(ARKTS_Env env, void* data)
185 {
186     if (!g_cjModuleCallbacks) {
187         LOGE("native ark-interop library has no registered module");
188         return;
189     }
190 
191     g_cjModuleCallbacks->invokeAsyncLambda(env, reinterpret_cast<int64_t>(data));
192 }
193 
ARKTS_DisposeJSContext(ARKTS_Env env)194 void ARKTS_DisposeJSContext(ARKTS_Env env)
195 {
196     if (!g_cjModuleCallbacks) {
197         LOGE("native ark-interop library has no registered module");
198         return;
199     }
200     g_cjModuleCallbacks->deleteJSContext(env);
201 }
202