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