blob: 0ce5069e4042412deda1fc07c8e97178c58f85f9 [file]
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#pragma once
#include <jni.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#if _WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#endif
#if _WIN32
#define FFI_PLUGIN_EXPORT __declspec(dllexport)
#else
#define FFI_PLUGIN_EXPORT
#endif
#if defined _WIN32
#define thread_local __declspec(thread)
#else
#define thread_local __thread
#endif
#ifdef __ANDROID__
#include <android/log.h>
#endif
#define JNI_LOG_TAG "Dart-JNI"
#ifdef __ANDROID__
#define __ENVP_CAST (JNIEnv **)
#else
#define __ENVP_CAST (void **)
#endif
typedef struct JniContext {
JavaVM *jvm;
jobject classLoader;
jmethodID loadClassMethod;
jobject currentActivity;
jobject appContext;
} JniContext;
extern thread_local JNIEnv *jniEnv;
extern JniContext jni;
enum DartJniLogLevel {
JNI_VERBOSE = 2,
JNI_DEBUG,
JNI_INFO,
JNI_WARN,
JNI_ERROR
};
enum JniType {
boolType = 0,
byteType = 1,
shortType = 2,
charType = 3,
intType = 4,
longType = 5,
floatType = 6,
doubleType = 7,
objectType = 8,
voidType = 9,
};
FFI_PLUGIN_EXPORT JniContext GetJniContext();
FFI_PLUGIN_EXPORT JavaVM *GetJavaVM(void);
FFI_PLUGIN_EXPORT int DestroyJavaVM();
FFI_PLUGIN_EXPORT JNIEnv *GetJniEnv(void);
FFI_PLUGIN_EXPORT JNIEnv *SpawnJvm(JavaVMInitArgs *args);
FFI_PLUGIN_EXPORT jclass LoadClass(const char *name);
FFI_PLUGIN_EXPORT jobject GetClassLoader(void);
FFI_PLUGIN_EXPORT jobject GetApplicationContext(void);
FFI_PLUGIN_EXPORT jobject GetCurrentActivity(void);
/// For use by jni_gen's generated code
/// don't use these.
// these 2 fn ptr vars will be defined by generated code library
extern JniContext (*context_getter)(void);
extern JNIEnv *(*env_getter)(void);
// this function will be exported by generated code library
// it will set above 2 variables.
FFI_PLUGIN_EXPORT void setJniGetters(struct JniContext (*cg)(void),
JNIEnv *(*eg)(void));
// `static inline` because `inline` doesn't work, it may still not
// inline the function in which case a linker error may be produced.
//
// There has to be a better way to do this. Either to force inlining on target
// platforms, or just leave it as normal function.
static inline void __load_class_into(jclass *cls, const char *name) {
#ifdef __ANDROID__
jstring className = (*jniEnv)->NewStringUTF(jniEnv, name);
*cls = (*jniEnv)->CallObjectMethod(jniEnv, jni.classLoader,
jni.loadClassMethod, className);
(*jniEnv)->DeleteLocalRef(jniEnv, className);
#else
*cls = (*jniEnv)->FindClass(jniEnv, name);
#endif
}
static inline void load_class(jclass *cls, const char *name) {
if (*cls == NULL) {
__load_class_into(cls, name);
}
}
static inline void load_class_gr(jclass *cls, const char *name) {
if (*cls == NULL) {
jclass tmp;
__load_class_into(&tmp, name);
*cls = (*jniEnv)->NewGlobalRef(jniEnv, tmp);
(*jniEnv)->DeleteLocalRef(jniEnv, tmp);
}
}
static inline void attach_thread() {
if (jniEnv == NULL) {
(*jni.jvm)->AttachCurrentThread(jni.jvm, __ENVP_CAST & jniEnv,
NULL);
}
}
static inline void load_env() {
if (jniEnv == NULL) {
jni = context_getter();
jniEnv = env_getter();
}
}
static inline void load_method(jclass cls, jmethodID *res, const char *name,
const char *sig) {
if (*res == NULL) {
*res = (*jniEnv)->GetMethodID(jniEnv, cls, name, sig);
}
}
static inline void load_static_method(jclass cls, jmethodID *res,
const char *name, const char *sig) {
if (*res == NULL) {
*res = (*jniEnv)->GetStaticMethodID(jniEnv, cls, name, sig);
}
}
static inline void load_field(jclass cls, jfieldID *res, const char *name,
const char *sig) {
if (*res == NULL) {
*res = (*jniEnv)->GetFieldID(jniEnv, cls, name, sig);
}
}
static inline void load_static_field(jclass cls, jfieldID *res,
const char *name, const char *sig) {
if (*res == NULL) {
*res = (*jniEnv)->GetStaticFieldID(jniEnv, cls, name, sig);
}
}
static inline jobject to_global_ref(jobject ref) {
jobject g = (*jniEnv)->NewGlobalRef(jniEnv, ref);
(*jniEnv)->DeleteLocalRef(jniEnv, ref);
return g;
}