• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 <map>
17 #include "convertors-ani.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 = "I[BI:I";
24 
25 static const char* FAST_NATIVE_PREFIX = "#F$";
26 
27 const bool registerByOne = true;
28 
registerNatives(ani_env * env,const ani_class clazz,const std::vector<std::tuple<std::string,std::string,void *,int>> impls)29 static bool registerNatives(ani_env *env, const ani_class clazz, const std::vector<std::tuple<std::string, std::string, void*, int>> impls) {
30     std::vector<ani_native_function> methods;
31     methods.reserve(impls.size());
32     bool result = true;
33     for (const auto &[name, type, func, flag] : impls) {
34         ani_native_function method;
35         method.name = name.c_str();
36         method.pointer = func;
37         method.signature = (flag & ANI_SLOW_NATIVE_FLAG) == 0 ? FAST_NATIVE_PREFIX : nullptr;
38         if (registerByOne) {
39             result &= env->Class_BindNativeMethods(clazz, &method, 1) == ANI_OK;
40             ani_boolean isError = false;
41             env->ExistUnhandledError(&isError);
42             if (isError) {
43                 env->ResetError();
44             }
45         }
46         else {
47             methods.push_back(method);
48         }
49     }
50     if (!registerByOne) {
51         result = env->Class_BindNativeMethods(clazz, methods.data(), static_cast<ani_size>(methods.size())) == ANI_OK;
52     }
53     return registerByOne ? true : result;
54 }
55 
registerAllModules(ani_env * env)56 bool registerAllModules(ani_env *env) {
57     auto moduleNames = AniExports::getInstance()->getModules();
58 
59     for (auto it = moduleNames.begin(); it != moduleNames.end(); ++it) {
60         std::string classpath = AniExports::getInstance()->getClasspath(*it);
61         ani_class nativeModule = nullptr;
62         env->FindClass(classpath.c_str(), &nativeModule);
63         if (nativeModule == nullptr) {
64             LOGE("Cannot find managed class %s", classpath.c_str());
65             continue;
66         }
67         if (!registerNatives(env, nativeModule, AniExports::getInstance()->getMethods(*it))) {
68             return false;
69         }
70     }
71 
72     return true;
73 }
74 
getInstance()75 AniExports* AniExports::getInstance() {
76     static AniExports *instance = nullptr;
77     if (instance == nullptr) {
78         instance = new AniExports();
79     }
80     return instance;
81 }
82 
getModules()83 std::vector<std::string> AniExports::getModules() {
84     std::vector<std::string> result;
85     for (auto it = implementations.begin(); it != implementations.end(); ++it) {
86         result.push_back(it->first);
87     }
88     return result;
89 }
90 
getMethods(const std::string & module)91 const std::vector<std::tuple<std::string, std::string, void*, int>>& AniExports::getMethods(const std::string& module) {
92     auto it = implementations.find(module);
93     if (it == implementations.end()) {
94         LOGE("Module %s is not registered", module.c_str());
95     }
96     return it->second;
97 }
98 
addMethod(const char * module,const char * name,const char * type,void * impl,int flags)99 void AniExports::addMethod(const char* module, const char *name, const char *type, void *impl, int flags) {
100     auto it = implementations.find(module);
101     if (it == implementations.end()) {
102         it = implementations.insert(std::make_pair(module, std::vector<std::tuple<std::string, std::string, void*, int>>())).first;
103     }
104     it->second.push_back(std::make_tuple(name, convertType(name, type), impl, flags));
105 }
106 
setClasspath(const char * module,const char * classpath)107 void AniExports::setClasspath(const char* module, const char *classpath) {
108     auto it = classpaths.find(module);
109     if (it == classpaths.end()) {
110         classpaths.insert(std::make_pair(module, classpath));
111     } else {
112         LOGE("Classpath for module %s was redefined", module);
113     }
114 }
115 
116 static std::map<std::string, std::string> g_defaultClasspaths = {
117     {"InteropNativeModule", "@koalaui/interop/InteropNativeModule/InteropNativeModule"},
118     // todo leave just InteropNativeModule, define others via KOALA_ETS_INTEROP_MODULE_CLASSPATH
119     {"TestNativeModule", "@koalaui/arkts-arkui/generated/arkts/TestNativeModule/TestNativeModule"},
120     {"ArkUINativeModule", "@koalaui/arkts-arkui/generated/arkts/ArkUINativeModule/ArkUINativeModule"},
121     {"ArkUIGeneratedNativeModule", "@koalaui/arkts-arkui/generated/arkts/ArkUIGeneratedNativeModule/ArkUIGeneratedNativeModule"},
122 };
getClasspath(const std::string & module)123 const std::string& AniExports::getClasspath(const std::string& module) {
124     auto it = classpaths.find(module);
125     if (it != classpaths.end()) {
126         return it->second;
127     }
128     auto defaultClasspath = g_defaultClasspaths.find(module);
129     if (defaultClasspath != g_defaultClasspaths.end()) {
130         return defaultClasspath->second;
131     }
132     INTEROP_FATAL("Classpath for module %s was not registered", module.c_str());
133 }
134