• 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 
17 #define KOALA_INTEROP_MODULE
18 #include "convertors-jni.h"
19 #include "signatures.h"
20 #include "interop-logging.h"
21 #include "interop-types.h"
22 
23 static const char* nativeModule = "org/koalaui/arkoala/InteropNativeModule";
24 static const char* nativeModulePrefix = "org/koalaui/arkoala/";
25 static const char* callCallbackFromNative = "callCallbackFromNative";
26 static const char* callCallbackFromNativeSig = "(I[BI)I";
27 
28 const bool registerByOne = true;
29 
registerNatives(JNIEnv * env,jclass clazz,const std::vector<std::tuple<std::string,std::string,void * >> impls)30 static bool registerNatives(JNIEnv *env, jclass clazz, const std::vector<std::tuple<std::string, std::string, void* >> impls) {
31     size_t numMethods = impls.size();
32     JNINativeMethod *methods = new JNINativeMethod[numMethods];
33     bool result = true;
34     for (size_t i = 0; i < numMethods; i++)
35     {
36         methods[i].name = (char *)std::get<0>(impls[i]).c_str();
37         methods[i].signature = (char *)std::get<1>(impls[i]).c_str();
38         methods[i].fnPtr = std::get<2>(impls[i]);
39         if (registerByOne) {
40             result &= (env->RegisterNatives(clazz, methods + i, 1) >= 0);
41             if (env->ExceptionCheck()) {
42                 env->ExceptionDescribe();
43                 env->ExceptionClear();
44                 result = false;
45             }
46         }
47     }
48     return registerByOne ? true : env->RegisterNatives(clazz, methods, numMethods) >= 0;
49 }
50 
51 constexpr bool splitPerModule = true;
52 
JNI_OnLoad(JavaVM * vm,void * reserved)53 JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
54     JNIEnv *env;
55     if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_8) != JNI_OK) {
56         return JNI_ERR;
57     }
58     auto modules = JniExports::getInstance()->getModules();
59     jclass defaultNativeModule = env->FindClass(nativeModule);
60     for (auto it = modules.begin(); it != modules.end(); ++it) {
61         std::string className = std::string(nativeModulePrefix) + *it;
62         jclass nativeModule =
63             (!splitPerModule) ? defaultNativeModule : env->FindClass(className.c_str());
64         if (nativeModule == nullptr) {
65             LOGE("Cannot find managed class %s", className.c_str());
66             continue;
67         }
68         registerNatives(env, nativeModule, JniExports::getInstance()->getMethods(*it));
69     }
70     if (!setKoalaJniCallbackDispatcher(env, defaultNativeModule, callCallbackFromNative, callCallbackFromNativeSig)) return JNI_ERR;
71     return JNI_VERSION_1_8;
72 }
73 
getInstance()74 JniExports *JniExports::getInstance()
75 {
76     static JniExports *instance = nullptr;
77     if (instance == nullptr)
78     {
79         instance = new JniExports();
80     }
81     return instance;
82 }
83 
getModules()84 std::vector<std::string> JniExports::getModules() {
85     std::vector<std::string> result;
86     for (auto it = implementations.begin(); it != implementations.end(); ++it) {
87         result.push_back(it->first);
88     }
89     return result;
90 }
91 
getMethods(const std::string & module)92 const std::vector<std::tuple<std::string, std::string, void*>>& JniExports::getMethods(const std::string& module) {
93     auto it = implementations.find(module);
94     if (it == implementations.end()) {
95         LOGE("Module %s is not registered", module.c_str());
96         INTEROP_FATAL("Fatal error: not registered module %s", module.c_str());
97     }
98     return it->second;
99 }
100 
addMethod(const char * module,const char * name,const char * type,void * impl)101 void JniExports::addMethod(const char* module, const char *name, const char *type, void *impl) {
102     auto it = implementations.find(module);
103     if (it == implementations.end()) {
104         it = implementations.insert(std::make_pair(module, std::vector<std::tuple<std::string, std::string, void*>>())).first;
105     }
106     it->second.push_back(std::make_tuple(name, convertType(name, type), impl));
107 }
108