Skip to content

Commit

Permalink
Fix #103 (#104)
Browse files Browse the repository at this point in the history
Use macro's to create/get JNIEnv instances attached to the current thread
  • Loading branch information
johanvos authored Apr 17, 2020
1 parent 4516fc7 commit 38033a5
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 365 deletions.
49 changes: 44 additions & 5 deletions gradle/include/android/grandroid_ext.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,28 @@
*/

#include <jni.h>
#include <pthread.h>
#include <unistd.h>
#include <android/log.h>
#include <android/native_window_jni.h>

#define ENABLE_DEBUG_LOG 1
#define LOG_TAG "GraalGluon"

#if ENABLE_DEBUG_LOG == 1
#define LOGD(ignore, ...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGE(ignore, ...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
#else
#define LOGD(ignore, ...)
#define LOGE(ignore, ...)
#endif


extern jclass activityClass;
extern jobject activity;

extern JavaVM *androidVM;
extern JNIEnv *androidEnv;

// expose AndroidVM, Env, MainActivity and its class
// expose AndroidVM, MainActivity and its class
JavaVM* substrateGetAndroidVM();
JNIEnv* substrateGetAndroidEnv();
jclass substrateGetActivityClass();
jclass substrateGetPermissionActivityClass();
jobject substrateGetActivity();
Expand All @@ -51,3 +63,30 @@ void __attribute__((weak)) attach_setLifecycleEvent(const char *event) {}
void attach_setActivityResult(jint requestCode, jint resultCode, jobject intent);
void attach_setLifecycleEvent(const char *event);
#endif

#define ATTACH_GRAAL() \
JNIEnv *graalEnv; \
JavaVM* graalVM = getGraalVM(); \
int tid = gettid(); \
int attach_graal_det = ((*graalVM)->GetEnv(graalVM, (void **)&graalEnv, JNI_VERSION_1_6) == JNI_OK); \
(*graalVM)->AttachCurrentThreadAsDaemon(graalVM, (void **) &graalEnv, NULL); \
LOGD(stderr, "ATTACH_GRAAL, tid = %d, existed? %d, graalEnv at %p\n", tid, attach_graal_det, graalEnv);

#define DETACH_GRAAL() \
int tid_detach = gettid(); \
LOGD(stderr, "DETACH_GRAAL, tid = %d, graalVM = %p, existed = %d, env at %p\n", tid_detach, graalVM, attach_graal_det, graalEnv); \
if (attach_graal_det == 0) (*graalVM)->DetachCurrentThread(graalVM);

#define ATTACH_DALVIK() \
JNIEnv *dalvikEnv; \
JavaVM* dalvikVM = substrateGetAndroidVM(); \
int dalviktid = gettid(); \
int attach_dalvik_det = ((*dalvikVM)->GetEnv(dalvikVM, (void **)&dalvikEnv, JNI_VERSION_1_6) == JNI_OK); \
(*dalvikVM)->AttachCurrentThreadAsDaemon(dalvikVM, (void **) &dalvikEnv, NULL); \
LOGD(stderr, "ATTACH_DALVIK, tid = %d, existed? %d, dalvikEnv at %p\n", dalviktid, attach_dalvik_det, dalvikEnv);

#define DETACH_DALVIK() \
int dalviktid_detach = gettid(); \
LOGD(stderr, "DETACH_DALVIK, tid = %d, existed = %d, env at %p\n", dalviktid_detach, attach_dalvik_det, dalvikEnv); \
if (attach_dalvik_det == 0) (*dalvikVM)->DetachCurrentThread(dalvikVM);

4 changes: 2 additions & 2 deletions gradle/native-build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ ext.nativeBuild = { buildDir, projectDir, name, os ->
File nativeSourcesDir = file("$projectDir/src/main/native/$os/c/")
osSources = [nativeSourcesDir.listFiles().findAll {it.name.endsWith(".c")}].flatten()

def compilerArgs = ["-target", platform, "-c", includeFlags, osIncludeFlags, osSources].flatten()
def compilerArgs = ["-target", platform, "-Werror", "-c", includeFlags, osIncludeFlags, osSources].flatten()

exec {
executable compiler
Expand Down Expand Up @@ -205,4 +205,4 @@ ext.nativeBuild = { buildDir, projectDir, name, os ->
.first()
}
}
}
}
281 changes: 124 additions & 157 deletions modules/ble/src/main/native/android/c/Ble.c

Large diffs are not rendered by default.

39 changes: 13 additions & 26 deletions modules/browser/src/main/native/android/c/Browser.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,20 @@
*/
#include "Browser.h"

static JNIEnv *graalEnv;
JavaVM *jVMBrowser = NULL;

static JavaVM *myAndroidVM = NULL;
static jobject jDalvikBrowserService;
static jmethodID jBrowserServiceLaunchMethod;

static void initializeDalvikHandles() {
myAndroidVM = substrateGetAndroidVM();
jclass jBrowserServiceClass = substrateGetBrowserServiceClass();
JNIEnv* androidEnv;
(*myAndroidVM)->AttachCurrentThread(myAndroidVM, (void **)&androidEnv, NULL);
jmethodID jBrowserServiceInitMethod = (*androidEnv)->GetMethodID(androidEnv, jBrowserServiceClass, "<init>", "(Landroid/app/Activity;)V");
jBrowserServiceLaunchMethod = (*androidEnv)->GetMethodID(androidEnv, jBrowserServiceClass, "launchURL", "(Ljava/lang/String;)Z");
ATTACH_DALVIK();
jmethodID jBrowserServiceInitMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jBrowserServiceClass, "<init>", "(Landroid/app/Activity;)V");
jBrowserServiceLaunchMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jBrowserServiceClass, "launchURL", "(Ljava/lang/String;)Z");

jobject jActivity = substrateGetActivity();
jobject jtmpobj = (*androidEnv)->NewObject(androidEnv, jBrowserServiceClass, jBrowserServiceInitMethod, jActivity);
jDalvikBrowserService = (*androidEnv)->NewGlobalRef(androidEnv, jtmpobj);
(*myAndroidVM)->DetachCurrentThread(myAndroidVM);
jobject jtmpobj = (*dalvikEnv)->NewObject(dalvikEnv, jBrowserServiceClass, jBrowserServiceInitMethod, jActivity);
jDalvikBrowserService = (*dalvikEnv)->NewGlobalRef(dalvikEnv, jtmpobj);
DETACH_DALVIK();
}

//////////////////////////
Expand All @@ -56,9 +51,9 @@ static void initializeDalvikHandles() {
JNIEXPORT jint JNICALL
JNI_OnLoad_Browser(JavaVM *vm, void *reserved)
{
fprintf(stderr, "JNI_OnLoad_Browser called\n");
ATTACH_LOG_INFO("JNI_OnLoad_Browser called\n");
#ifdef JNI_VERSION_1_8
jVMBrowser = vm;
JNIEnv* graalEnv;
if ((*vm)->GetEnv(vm, (void **)&graalEnv, JNI_VERSION_1_8) != JNI_OK) {
ATTACH_LOG_WARNING("Error initializing native Browser from OnLoad");
return JNI_FALSE;
Expand All @@ -73,22 +68,14 @@ fprintf(stderr, "JNI_OnLoad_Browser called\n");

// from Java to Android

static JNIEnv* getSafeAndroidEnv() {
JNIEnv* androidEnv;
if ((*myAndroidVM)->GetEnv(myAndroidVM, (void **)&androidEnv, JNI_VERSION_1_6) != JNI_OK) {
ATTACH_LOG_WARNING("AndroidEnv called from not-attached thread\n");
(*myAndroidVM)->AttachCurrentThread(myAndroidVM, (void **)&androidEnv, NULL);
}
return androidEnv;
}

JNIEXPORT jboolean JNICALL Java_com_gluonhq_attach_browser_impl_AndroidBrowserService_launchURL
(JNIEnv *env, jclass jClass, jstring jurl)
{
const char *urlChars = (*env)->GetStringUTFChars(env, jurl, NULL);
JNIEnv* androidEnv = getSafeAndroidEnv();
jstring durl = (*androidEnv)->NewStringUTF(androidEnv, urlChars);
jboolean result = (*androidEnv)->CallBooleanMethod(androidEnv, jDalvikBrowserService, jBrowserServiceLaunchMethod, durl);
(*env)->ReleaseStringUTFChars(env, jurl, urlChars);
ATTACH_DALVIK();
jstring durl = (*dalvikEnv)->NewStringUTF(dalvikEnv, urlChars);
jboolean result = (*dalvikEnv)->CallBooleanMethod(dalvikEnv, jDalvikBrowserService, jBrowserServiceLaunchMethod, durl);
DETACH_DALVIK();
// (*env)->ReleaseStringUTFChars(env, jurl, urlChars);
return result;
}
60 changes: 25 additions & 35 deletions modules/display/src/main/native/android/c/Display.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,25 @@
*/
#include "Display.h"

static JNIEnv *graalEnv;
JavaVM *jVMDisplay = NULL;

static JavaVM *myAndroidVM = NULL;
static jobject jDalvikDisplayService;
static jmethodID jDisplayServiceWidthMethod;
static jmethodID jDisplayServiceHeightMethod;
static jmethodID jDisplayServiceFactorMethod;
static jmethodID jDisplayServiceRoundMethod;

static void initializeDalvikHandles() {
myAndroidVM = substrateGetAndroidVM();
static void initializeDisplayDalvikHandles() {
ATTACH_DALVIK();
jclass jDisplayServiceClass = substrateGetDisplayServiceClass();
JNIEnv* androidEnv;
(*myAndroidVM)->AttachCurrentThread(myAndroidVM, (void **)&androidEnv, NULL);
jmethodID jDisplayServiceInitMethod = (*androidEnv)->GetMethodID(androidEnv, jDisplayServiceClass, "<init>", "(Landroid/app/Activity;)V");
jDisplayServiceWidthMethod = (*androidEnv)->GetMethodID(androidEnv, jDisplayServiceClass, "screenWidth", "()D");
jDisplayServiceHeightMethod = (*androidEnv)->GetMethodID(androidEnv, jDisplayServiceClass, "screenHeight", "()D");
jDisplayServiceFactorMethod = (*androidEnv)->GetMethodID(androidEnv, jDisplayServiceClass, "isPhoneFactor", "()Z");
jDisplayServiceRoundMethod = (*androidEnv)->GetMethodID(androidEnv, jDisplayServiceClass, "isScreenRound", "()Z");
jmethodID jDisplayServiceInitMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "<init>", "(Landroid/app/Activity;)V");
jDisplayServiceWidthMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "screenWidth", "()D");
jDisplayServiceHeightMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "screenHeight", "()D");
jDisplayServiceFactorMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "isPhoneFactor", "()Z");
jDisplayServiceRoundMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jDisplayServiceClass, "isScreenRound", "()Z");

jobject jActivity = substrateGetActivity();
jobject jtmpobj = (*androidEnv)->NewObject(androidEnv, jDisplayServiceClass, jDisplayServiceInitMethod, jActivity);
jDalvikDisplayService = (*androidEnv)->NewGlobalRef(androidEnv, jtmpobj);
(*myAndroidVM)->DetachCurrentThread(myAndroidVM);
jobject jtmpobj = (*dalvikEnv)->NewObject(dalvikEnv, jDisplayServiceClass, jDisplayServiceInitMethod, jActivity);
jDalvikDisplayService = (*dalvikEnv)->NewGlobalRef(dalvikEnv, jtmpobj);
DETACH_DALVIK();
}

//////////////////////////
Expand All @@ -62,15 +56,15 @@ static void initializeDalvikHandles() {
JNIEXPORT jint JNICALL
JNI_OnLoad_Display(JavaVM *vm, void *reserved)
{
fprintf(stderr, "JNI_OnLoad_Display called\n");
JNIEnv* graalEnv;
ATTACH_LOG_INFO("JNI_OnLoad_Display called\n");
#ifdef JNI_VERSION_1_8
jVMDisplay = vm;
if ((*vm)->GetEnv(vm, (void **)&graalEnv, JNI_VERSION_1_8) != JNI_OK) {
ATTACH_LOG_WARNING("Error initializing native Display from OnLoad");
return JNI_FALSE;
}
ATTACH_LOG_FINE("[Display Service] Initializing native Display from OnLoad");
initializeDalvikHandles();
initializeDisplayDalvikHandles();
return JNI_VERSION_1_8;
#else
#error Error: Java 8+ SDK is required to compile Attach
Expand All @@ -79,21 +73,12 @@ fprintf(stderr, "JNI_OnLoad_Display called\n");

// from Java to Android

static JNIEnv* getSafeAndroidEnv() {
JNIEnv* androidEnv;
if ((*myAndroidVM)->GetEnv(myAndroidVM, (void **)&androidEnv, JNI_VERSION_1_6) != JNI_OK) {
ATTACH_LOG_WARNING("AndroidEnv called from not-attached thread\n");
(*myAndroidVM)->AttachCurrentThread(myAndroidVM, (void **)&androidEnv, NULL);
}
return androidEnv;
}

JNIEXPORT jdoubleArray JNICALL Java_com_gluonhq_attach_display_impl_AndroidDisplayService_screenSize
(JNIEnv *env, jclass jClass)
{
JNIEnv* androidEnv = getSafeAndroidEnv();
jdouble w = (*androidEnv)->CallDoubleMethod(androidEnv, jDalvikDisplayService, jDisplayServiceWidthMethod);
jdouble h = (*androidEnv)->CallDoubleMethod(androidEnv, jDalvikDisplayService, jDisplayServiceHeightMethod);
ATTACH_DALVIK();
jdouble w = (*dalvikEnv)->CallDoubleMethod(dalvikEnv, jDalvikDisplayService, jDisplayServiceWidthMethod);
jdouble h = (*dalvikEnv)->CallDoubleMethod(dalvikEnv, jDalvikDisplayService, jDisplayServiceHeightMethod);

jdoubleArray output = (*env)->NewDoubleArray(env, 2);
if (output == NULL)
Expand All @@ -102,19 +87,24 @@ JNIEXPORT jdoubleArray JNICALL Java_com_gluonhq_attach_display_impl_AndroidDispl
}
jdouble res[] = {w, h};
(*env)->SetDoubleArrayRegion(env, output, 0, 2, res);
DETACH_DALVIK();
return output;
}

JNIEXPORT jboolean JNICALL Java_com_gluonhq_attach_display_impl_AndroidDisplayService_isPhoneFactor
(JNIEnv *env, jclass jClass)
{
JNIEnv* androidEnv = getSafeAndroidEnv();
return (*androidEnv)->CallBooleanMethod(androidEnv, jDalvikDisplayService, jDisplayServiceFactorMethod);
ATTACH_DALVIK();
jboolean answer = (*dalvikEnv)->CallBooleanMethod(dalvikEnv, jDalvikDisplayService, jDisplayServiceFactorMethod);
DETACH_DALVIK();
return answer;
}

JNIEXPORT jboolean JNICALL Java_com_gluonhq_attach_display_impl_AndroidDisplayService_screenRound
(JNIEnv *env, jclass jClass)
{
JNIEnv* androidEnv = getSafeAndroidEnv();
return (*androidEnv)->CallBooleanMethod(androidEnv, jDalvikDisplayService, jDisplayServiceRoundMethod);
ATTACH_DALVIK();
jboolean answer = (*dalvikEnv)->CallBooleanMethod(dalvikEnv, jDalvikDisplayService, jDisplayServiceRoundMethod);
DETACH_DALVIK();
return answer;
}
51 changes: 11 additions & 40 deletions modules/keyboard/src/main/native/android/c/Keyboard.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@
*/
#include "Keyboard.h"

static JNIEnv *env;
JNIEnv* javaEnvKeyboard = NULL;
static JavaVM *graalVM = NULL;
static jclass jAttachKeyboardClass;
static jmethodID jAttach_notifyHeightMethod;
int debugKeyboard = 0;
Expand All @@ -40,11 +37,11 @@ JNI_OnLoad_Keyboard(JavaVM *vm, void *reserved)
{
#ifdef JNI_VERSION_1_8
//min. returned JNI_VERSION required by JDK8 for builtin libraries
JNIEnv* env;
if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_8) != JNI_OK) {
ATTACH_LOG_WARNING("Error initializing native Keyboard from OnLoad");
return JNI_FALSE;
}
graalVM = getGraalVM();
ATTACH_LOG_FINE("Initializing native Keyboard from OnLoad");
jAttachKeyboardClass = (*env)->NewGlobalRef(env, (*env)->FindClass(env, "com/gluonhq/attach/keyboard/impl/AndroidKeyboardService"));
jAttach_notifyHeightMethod = (*env)->GetStaticMethodID(env, jAttachKeyboardClass, "notifyVisibleHeight", "(F)V");
Expand All @@ -67,18 +64,16 @@ void initKeyboard()
KeyboardInited = 1;

ATTACH_LOG_FINE("Init AndroidKeyboardService");
JavaVM* androidVM = substrateGetAndroidVM();
jclass activityClass = substrateGetActivityClass();
jobject jActivity = substrateGetActivity();
jclass jKeyboardServiceClass = substrateGetKeyboardServiceClass();

JNIEnv* androidEnv;
(*androidVM)->AttachCurrentThread(androidVM, (void **)&androidEnv, NULL);
jmethodID jKeyboardServiceInitMethod = (*androidEnv)->GetMethodID(androidEnv, jKeyboardServiceClass, "<init>", "(Landroid/app/Activity;)V");
jobject keyboardservice = (*androidEnv)->NewObject(androidEnv, jKeyboardServiceClass, jKeyboardServiceInitMethod, jActivity);
(*androidVM)->DetachCurrentThread(androidVM);
ATTACH_DALVIK();
jmethodID jKeyboardServiceInitMethod = (*dalvikEnv)->GetMethodID(dalvikEnv, jKeyboardServiceClass, "<init>", "(Landroid/app/Activity;)V");
jobject keyboardservice = (*dalvikEnv)->NewObject(dalvikEnv, jKeyboardServiceClass, jKeyboardServiceInitMethod, jActivity);
density = android_getDensity(dalvikEnv);
DETACH_DALVIK();

density = android_getDensity(env);
if (density == 0.0f) {
density = 1.0f;
}
Expand All @@ -91,35 +86,11 @@ JNIEXPORT void JNICALL Java_com_gluonhq_attach_keyboard_impl_AndroidKeyboardServ
debugKeyboard = 1;
}

void initializeKeyboardFromNative() {
if (javaEnvKeyboard != NULL) {
return; // already have a JNIEnv
}
if (graalVM == NULL) {
ATTACH_LOG_FINE("initialize Keyboard from native can't be done without JVM");
return; // can't initialize from native before we have a graalVM
}
if (debugKeyboard == 1) {
ATTACH_LOG_FINE("Initializing native Keyboard from Android/native code");
}
jint error = (*graalVM)->AttachCurrentThread(graalVM, (void **)&javaEnvKeyboard, NULL);
if (error != 0) {
ATTACH_LOG_FINE("initializeKeyboardFromNative failed with error %d", error);
}
}

JNIEXPORT void JNICALL Java_com_gluonhq_helloandroid_KeyboardService_nativeDispatchKeyboardHeight(JNIEnv *env, jobject activity, jfloat jheight)
{
if (debugKeyboard == 1) {
ATTACH_LOG_FINE("Dispatching keyboard height from native Dalvik layer: %.3f", jheight / density);
}
initializeKeyboardFromNative();
if (javaEnvKeyboard == NULL) {
ATTACH_LOG_FINE("javaEnvKeyboard still null, not ready to process keyboard events");
return;
}
(*javaEnvKeyboard)->CallStaticVoidMethod(javaEnvKeyboard, jAttachKeyboardClass, jAttach_notifyHeightMethod, jheight / density);
if (debugKeyboard == 1) {
ATTACH_LOG_FINE("called Attach method from native Keyboard done");
}
ATTACH_LOG_FINE("Dispatching keyboard height from native Dalvik layer: %.3f", jheight / density);
ATTACH_GRAAL();
(*graalEnv)->CallStaticVoidMethod(graalEnv, jAttachKeyboardClass, jAttach_notifyHeightMethod, jheight / density);
DETACH_GRAAL();
ATTACH_LOG_FINE("called Attach method from native Keyboard done");
}
Loading

0 comments on commit 38033a5

Please sign in to comment.