• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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 <map>
17 #include "convertors-ets.h"
18 #include "signatures.h"
19 #include "interop-logging.h"
20 #include "interop-types.h"
21 
22 static const char* callCallbackFromNative = "callCallbackFromNative";
23 static const char* callCallbackFromNativeSig = "IJI:I";
24 
25 static const char* FAST_NATIVE_PREFIX = "#F$";
26 
27 const bool registerByOne = true;
28 
registerNatives(ets_env * env,const ets_class clazz,const std::vector<std::tuple<std::string,std::string,void *,int>> impls)29 static bool registerNatives(ets_env *env, const ets_class clazz, const std::vector<std::tuple<std::string, std::string, void*, int>> impls) {
30     std::vector<EtsNativeMethod> methods;
31     methods.reserve(impls.size());
32     bool result = true;
33     for (const auto &[name, type, func, flag] : impls) {
34         EtsNativeMethod method;
35         method.name = name.c_str();
36         method.func = func;
37         method.signature = (flag & ETS_SLOW_NATIVE_FLAG) == 0 ? FAST_NATIVE_PREFIX : nullptr;
38         if (registerByOne) {
39             result &= env->RegisterNatives(clazz, &method, 1) >= 0;
40             if (env->ErrorCheck()) {
41                 //env->ErrorDescribe();
42                 env->ErrorClear();
43             }
44         }
45         else {
46             methods.push_back(method);
47         }
48     }
49     if (!registerByOne) {
50         result = env->RegisterNatives(clazz, methods.data(), static_cast<ets_int>(methods.size())) >= 0;
51     }
52     return registerByOne ? true : result;
53 }
54 
registerAllModules(ets_env * env)55 bool registerAllModules(ets_env *env) {
56     auto moduleNames = EtsExports::getInstance()->getModules();
57 
58     for (auto it = moduleNames.begin(); it != moduleNames.end(); ++it) {
59         std::string className = EtsExports::getInstance()->getClasspath(*it);
60         ets_class nativeModule = env->FindClass(className.c_str());
61         if (nativeModule == nullptr) {
62             LOGE("Cannot find managed class %s", className.c_str());
63             continue;
64         }
65         if (!registerNatives(env, nativeModule, EtsExports::getInstance()->getMethods(*it))) {
66             return false;
67         }
68     }
69 
70     return true;
71 }
72 
EtsNapiOnLoad(ets_env * env)73 extern "C" ETS_EXPORT ets_int ETS_CALL EtsNapiOnLoad(ets_env *env) {
74     LOGE("Use ETSNAPI")
75     if (!registerAllModules(env)) {
76         LOGE("Failed to register ets modules");
77         return ETS_ERR;
78     }
79     auto interopClasspath = EtsExports::getInstance()->getClasspath("InteropNativeModule");
80     auto interopClass = env->FindClass(interopClasspath.c_str());
81     if (interopClass == nullptr) {
82         LOGE("Can not find InteropNativeModule classpath to set callback dispatcher");
83         return ETS_ERR;
84     }
85     if (!setKoalaEtsNapiCallbackDispatcher(env, interopClass, callCallbackFromNative, callCallbackFromNativeSig)) {
86         LOGE("Failed to set koala ets callback dispatcher");
87         return ETS_ERR;
88     }
89     return ETS_NAPI_VERSION_1_0;
90 }
91 
getInstance()92 EtsExports* EtsExports::getInstance() {
93     static EtsExports *instance = nullptr;
94     if (instance == nullptr) {
95         instance = new EtsExports();
96     }
97     return instance;
98 }
99 
getModules()100 std::vector<std::string> EtsExports::getModules() {
101     std::vector<std::string> result;
102     for (auto it = implementations.begin(); it != implementations.end(); ++it) {
103         result.push_back(it->first);
104     }
105     return result;
106 }
107 
getMethods(const std::string & module)108 const std::vector<std::tuple<std::string, std::string, void*, int>>& EtsExports::getMethods(const std::string& module) {
109     auto it = implementations.find(module);
110     if (it == implementations.end()) {
111         LOGE("Module %s is not registered", module.c_str());
112     }
113     return it->second;
114 }
115 
addMethod(const char * module,const char * name,const char * type,void * impl,int flags)116 void EtsExports::addMethod(const char* module, const char *name, const char *type, void *impl, int flags) {
117     auto it = implementations.find(module);
118     if (it == implementations.end()) {
119         it = implementations.insert(std::make_pair(module, std::vector<std::tuple<std::string, std::string, void*, int>>())).first;
120     }
121     it->second.push_back(std::make_tuple(name, convertType(name, type), impl, flags));
122 }
123 
setClasspath(const char * module,const char * classpath)124 void EtsExports::setClasspath(const char* module, const char *classpath) {
125     auto it = classpaths.find(module);
126     if (it == classpaths.end()) {
127         classpaths.insert(std::make_pair(module, classpath));
128     } else {
129         LOGE("Classpath for module %s was redefined", module);
130     }
131 }
132 
133 static std::map<std::string, std::string> g_defaultClasspaths = {
134     {"InteropNativeModule", "@koalaui/interop/InteropNativeModule/InteropNativeModule"},
135     // todo leave just InteropNativeModule, define others via KOALA_ETS_INTEROP_MODULE_CLASSPATH
136     {"TestNativeModule", "arkui/component/arkts/TestNativeModule/TestNativeModule"},
137     {"ArkUINativeModule", "arkui/component/arkts/ArkUINativeModule/ArkUINativeModule"},
138     {"ArkUIGeneratedNativeModule", "arkui/component/arkts/ArkUIGeneratedNativeModule/ArkUIGeneratedNativeModule"},
139 };
getClasspath(const std::string & module)140 const std::string& EtsExports::getClasspath(const std::string& module) {
141     auto it = classpaths.find(module);
142     if (it != classpaths.end()) {
143         return it->second;
144     }
145     auto defaultClasspath = g_defaultClasspaths.find(module);
146     if (defaultClasspath != g_defaultClasspaths.end()) {
147         return defaultClasspath->second;
148     }
149     INTEROP_FATAL("Classpath for module %s was not registered", module.c_str());
150 }
151