From a3f0644b5cdcbd9e350cd3b6b4acfae513751394 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 11 Oct 2021 18:39:53 -0300 Subject: Upgrade libraries and clean up build system --- .../java/akono/InstrumentedAkonoTests.kt | 59 -------- .../java/net/taler/akono/InstrumentedAkonoTests.kt | 58 ++++++++ akono/src/main/cpp/CMakeLists.txt | 15 ++ akono/src/main/cpp/akono-jni.cpp | 16 +-- akono/src/main/java/akono/AkonoJni.kt | 151 --------------------- akono/src/main/java/net/taler/akono/AkonoJni.kt | 151 +++++++++++++++++++++ akono/src/test/java/akono/LibraryTest.kt | 16 --- 7 files changed, 232 insertions(+), 234 deletions(-) delete mode 100644 akono/src/androidTest/java/akono/InstrumentedAkonoTests.kt create mode 100644 akono/src/androidTest/java/net/taler/akono/InstrumentedAkonoTests.kt delete mode 100644 akono/src/main/java/akono/AkonoJni.kt create mode 100644 akono/src/main/java/net/taler/akono/AkonoJni.kt delete mode 100644 akono/src/test/java/akono/LibraryTest.kt (limited to 'akono/src') diff --git a/akono/src/androidTest/java/akono/InstrumentedAkonoTests.kt b/akono/src/androidTest/java/akono/InstrumentedAkonoTests.kt deleted file mode 100644 index 0fbcb6f9..00000000 --- a/akono/src/androidTest/java/akono/InstrumentedAkonoTests.kt +++ /dev/null @@ -1,59 +0,0 @@ -package akono.test; - -import androidx.test.ext.junit.runners.AndroidJUnit4 -import org.junit.runner.RunWith -import org.junit.Test -import androidx.test.filters.LargeTest -import org.junit.Assert.assertEquals -import akono.AkonoJni -import android.util.Log -import java.util.concurrent.LinkedBlockingDeque - - -class SyncMessageHandler : AkonoJni.MessageHandler { - private val messageQueue = LinkedBlockingDeque() - override fun handleMessage(message: String) { - messageQueue.put(message) - } - - fun waitForMessage(): String { - return messageQueue.take() - } -} - -// @RunWith is required only if you use a mix of JUnit3 and JUnit4. -@RunWith(AndroidJUnit4::class) -@LargeTest -class InstrumentedAkonoTestOne { - @Test - fun myJsTest() { - val ajni: AkonoJni = AkonoJni() - ajni.putModuleCode("a", "function foo() {}") - assertEquals("2", ajni.evalSimpleJs("1+1")) - assertEquals("36", ajni.evalSimpleJs("6*6")) - assertEquals("42", ajni.evalSimpleJs("(()=>{let x = 42; return x;})()")) - assertEquals("undefined", ajni.evalSimpleJs("const myVal = 42")) - assertEquals("43", ajni.evalSimpleJs("myVal + 1")) - - val myHandler = SyncMessageHandler() - ajni.setMessageHandler(myHandler) - ajni.evalNodeCode("console.log('hi from the test case')") - // Tell the message handler to just ping back messages to us - ajni.evalNodeCode("global.__akono_onMessage = (x) => { global.__akono_sendMessage(x); }") - val sentMessage = "Hello AKONO!!" - ajni.sendMessage(sentMessage) - val receivedMessage = myHandler.waitForMessage() - assertEquals(sentMessage, receivedMessage) - Log.i("myapp", "test case received message: $receivedMessage") - - ajni.evalNodeCode("require('akono');") - ajni.evalNodeCode("a = require('a');") - //ajni.evalNodeCode("a.foo()") - - //val msg2 = myHandler.waitForMessage() - - //assertEquals("hello42", msg2) - - ajni.waitStopped() - } -} diff --git a/akono/src/androidTest/java/net/taler/akono/InstrumentedAkonoTests.kt b/akono/src/androidTest/java/net/taler/akono/InstrumentedAkonoTests.kt new file mode 100644 index 00000000..f7dbdc98 --- /dev/null +++ b/akono/src/androidTest/java/net/taler/akono/InstrumentedAkonoTests.kt @@ -0,0 +1,58 @@ +package net.taler.akono + +import android.util.Log +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.LargeTest +import org.junit.Assert.assertEquals +import org.junit.Test +import org.junit.runner.RunWith +import java.util.concurrent.LinkedBlockingDeque + + +class SyncMessageHandler : AkonoJni.MessageHandler { + private val messageQueue = LinkedBlockingDeque() + override fun handleMessage(message: String) { + messageQueue.put(message) + } + + fun waitForMessage(): String { + return messageQueue.take() + } +} + +// @RunWith is required only if you use a mix of JUnit3 and JUnit4. +@RunWith(AndroidJUnit4::class) +@LargeTest +class InstrumentedAkonoTestOne { + @Test + fun myJsTest() { + val ajni = AkonoJni() + ajni.putModuleCode("a", "function foo() {}") + assertEquals("2", ajni.evalSimpleJs("1+1")) + assertEquals("36", ajni.evalSimpleJs("6*6")) + assertEquals("42", ajni.evalSimpleJs("(()=>{let x = 42; return x;})()")) + assertEquals("undefined", ajni.evalSimpleJs("const myVal = 42")) + assertEquals("43", ajni.evalSimpleJs("myVal + 1")) + + val myHandler = SyncMessageHandler() + ajni.setMessageHandler(myHandler) + ajni.evalNodeCode("console.log('hi from the test case')") + // Tell the message handler to just ping back messages to us + ajni.evalNodeCode("global.__akono_onMessage = (x) => { global.__akono_sendMessage(x); }") + val sentMessage = "Hello AKONO!!" + ajni.sendMessage(sentMessage) + val receivedMessage = myHandler.waitForMessage() + assertEquals(sentMessage, receivedMessage) + Log.i("myapp", "test case received message: $receivedMessage") + + ajni.evalNodeCode("require('akono');") + ajni.evalNodeCode("a = require('a');") + //ajni.evalNodeCode("a.foo()") + + //val msg2 = myHandler.waitForMessage() + + //assertEquals("hello42", msg2) + + ajni.waitStopped() + } +} diff --git a/akono/src/main/cpp/CMakeLists.txt b/akono/src/main/cpp/CMakeLists.txt index 10d6396f..0ee886de 100644 --- a/akono/src/main/cpp/CMakeLists.txt +++ b/akono/src/main/cpp/CMakeLists.txt @@ -27,15 +27,30 @@ add_library(v8 STATIC IMPORTED) set_target_properties(v8 PROPERTIES IMPORTED_LOCATION ${deps_dir}/compiled/${ANDROID_ABI}/libv8.cr.so) +add_library(v8_base STATIC IMPORTED) +set_target_properties(v8_base PROPERTIES IMPORTED_LOCATION + ${deps_dir}/compiled/${ANDROID_ABI}/libv8_libbase.cr.so) + add_library(v8_platform STATIC IMPORTED) set_target_properties(v8_platform PROPERTIES IMPORTED_LOCATION ${deps_dir}/compiled/${ANDROID_ABI}/libv8_libplatform.cr.so) +add_library(icui18n STATIC IMPORTED) +set_target_properties(icui18n PROPERTIES IMPORTED_LOCATION + ${deps_dir}/compiled/${ANDROID_ABI}/libicui18n.cr.so) + +add_library(icuuc STATIC IMPORTED) +set_target_properties(icuuc PROPERTIES IMPORTED_LOCATION + ${deps_dir}/compiled/${ANDROID_ABI}/libicuuc.cr.so) + # Include libraries needed for hello-jni lib target_link_libraries(akono-jni v8 + v8_base v8_platform node + icui18n + icuuc android log) diff --git a/akono/src/main/cpp/akono-jni.cpp b/akono/src/main/cpp/akono-jni.cpp index bbea76e6..0f47622c 100644 --- a/akono/src/main/cpp/akono-jni.cpp +++ b/akono/src/main/cpp/akono-jni.cpp @@ -357,7 +357,7 @@ static void sendMessageCallback(const v8::FunctionCallbackInfo &args) return; } - jclass clazz = env->FindClass("akono/AkonoJni"); + jclass clazz = env->FindClass("net.taler.akono/AkonoJni"); if (clazz == nullptr) { mylog("FATAL: class not found"); @@ -401,27 +401,27 @@ static void getModuleCode(const v8::FunctionCallbackInfo &args) { } extern "C" JNIEXPORT jobject JNICALL -Java_akono_AkonoJni_initNative(JNIEnv *env, jobject thiz) { +Java_net_taler_akono_AkonoJni_initNative(JNIEnv *env, jobject thiz) { NativeAkonoInstance *myInstance = new NativeAkonoInstance(); return env->NewDirectByteBuffer(myInstance, 0); } extern "C" JNIEXPORT void JNICALL -Java_akono_AkonoJni_destroyNative(JNIEnv *env, jobject thiz, jobject buf) { +Java_net_taler_akono_AkonoJni_destroyNative(JNIEnv *env, jobject thiz, jobject buf) { NativeAkonoInstance *myInstance = (NativeAkonoInstance *) env->GetDirectBufferAddress(buf); delete myInstance; } extern "C" JNIEXPORT jstring JNICALL -Java_akono_AkonoJni_evalJs(JNIEnv *env, jobject thiz, jstring sourceStr, jobject buf) { +Java_net_taler_akono_AkonoJni_evalJs(JNIEnv *env, jobject thiz, jstring sourceStr, jobject buf) { NativeAkonoInstance *myInstance = (NativeAkonoInstance *) env->GetDirectBufferAddress(buf); return myInstance->evalJs(env, sourceStr); } extern "C" JNIEXPORT void JNICALL -Java_akono_AkonoJni_putModuleCodeNative(JNIEnv *env, jobject thiz, jstring modName, jstring modCode) { +Java_net_taler_akono_AkonoJni_putModuleCodeNative(JNIEnv *env, jobject thiz, jstring modName, jstring modCode) { mylog("in putModuleCodeNative"); JStringValue cModName(env, modName); JStringValue cModCode(env, modCode); @@ -432,13 +432,13 @@ Java_akono_AkonoJni_putModuleCodeNative(JNIEnv *env, jobject thiz, jstring modNa extern "C" JNIEXPORT void JNICALL -Java_akono_AkonoJni_notifyNative(JNIEnv *env, jobject thiz, jobject buf) { +Java_net_taler_akono_AkonoJni_notifyNative(JNIEnv *env, jobject thiz, jobject buf) { NativeAkonoInstance *myInstance = (NativeAkonoInstance *) env->GetDirectBufferAddress(buf); uv_async_send(&myInstance->async_notify); } extern "C" JNIEXPORT void JNICALL -Java_akono_AkonoJni_runNode(JNIEnv *env, jobject thiz, jobject buf) { +Java_net_taler_akono_AkonoJni_runNode(JNIEnv *env, jobject thiz, jobject buf) { NativeAkonoInstance *myInstance = (NativeAkonoInstance *) env->GetDirectBufferAddress(buf); myInstance->currentJniEnv = env; myInstance->currentJniThiz = thiz; @@ -446,7 +446,7 @@ Java_akono_AkonoJni_runNode(JNIEnv *env, jobject thiz, jobject buf) { } extern "C" JNIEXPORT void JNICALL -Java_akono_AkonoJni_makeCallbackNative(JNIEnv *env, jobject thiz, jstring sourceStr, jobject buf) { +Java_net_taler_akono_AkonoJni_makeCallbackNative(JNIEnv *env, jobject thiz, jstring sourceStr, jobject buf) { JStringValue jsv(env, sourceStr); NativeAkonoInstance *myInstance = (NativeAkonoInstance *) env->GetDirectBufferAddress(buf); myInstance->currentJniEnv = env; diff --git a/akono/src/main/java/akono/AkonoJni.kt b/akono/src/main/java/akono/AkonoJni.kt deleted file mode 100644 index 85ceefa8..00000000 --- a/akono/src/main/java/akono/AkonoJni.kt +++ /dev/null @@ -1,151 +0,0 @@ -package akono - -import android.util.Base64 -import android.util.Log -import java.lang.Exception -import java.nio.ByteBuffer -import java.util.concurrent.CountDownLatch -import java.util.concurrent.LinkedBlockingDeque -import kotlin.concurrent.thread - -typealias AkonoNativePointer = ByteBuffer - -private val TAG = "AkonoJni" - -class AkonoJni(vararg nodeArgv: String) { - private var messageHandler: MessageHandler? = null - private val initializedLatch = CountDownLatch(1) - - private val workQueue = LinkedBlockingDeque<() -> Unit>() - - private external fun evalJs(source: String, p: AkonoNativePointer): String - private external fun runNode(p: AkonoNativePointer) - - private external fun makeCallbackNative(source: String, p: AkonoNativePointer) - private external fun putModuleCodeNative(key: String, source: String) - - private external fun destroyNative(b: AkonoNativePointer) - private external fun initNative(nodeArgv: Array): AkonoNativePointer - private external fun notifyNative(b: AkonoNativePointer) - - private lateinit var internalNativePointer: AkonoNativePointer - - private val jniThread: Thread - - private var stopped = false - - /** - * Schedule a block do be executed in the node thread. - */ - private fun scheduleNodeThread(b: () -> Unit) { - initializedLatch.await() - workQueue.put(b) - notifyNative() - } - - /** - * Called by node/v8 from its thread. - */ - private fun internalOnNotify(payload: String) { - messageHandler?.handleMessage(payload) - } - - - fun notifyNative() { - initializedLatch.await() - notifyNative(internalNativePointer) - } - - /** - * Schedule Node.JS to be run. - */ - fun evalSimpleJs(source: String): String { - val latch = CountDownLatch(1) - var result: String? = null - scheduleNodeThread { - result = evalJs(source, internalNativePointer) - latch.countDown() - } - latch.await() - return result ?: throw Exception("invariant failed") - } - - fun evalNodeCode(source: String) { - scheduleNodeThread { - makeCallbackNative(source, internalNativePointer) - } - } - - /** - * Send a message to node, calling global.__akono_onMessage. - */ - fun sendMessage(message: String) { - val encoded = Base64.encodeToString(message.toByteArray(), Base64.NO_WRAP) - val source = """ - if (global.__native_onMessage) { - const msg = (new Buffer('$encoded', 'base64')).toString('ascii'); - global.__native_onMessage(msg); - } else { - console.log("WARN: no __native_onMessage defined"); - } - """.trimIndent() - evalNodeCode(source) - } - - fun waitStopped(): Unit { - Log.i(TAG, "waiting for stop") - scheduleNodeThread { - stopped = true - } - jniThread.join() - return - } - - fun putModuleCode(modName: String, code: String) { - Log.v(TAG, "putting module code (kotlin)") - putModuleCodeNative(modName, code) - } - - /** - * Register a message handler that is called when the JavaScript code - * running in [runNodeJs] calls __native_sendMessage - * - * Does not block. - */ - fun setMessageHandler(handler: MessageHandler) { - this.messageHandler = handler - } - - - @Override - protected fun finalize() { - destroyNative(internalNativePointer) - } - - init { - jniThread = thread { - internalNativePointer = initNative(nodeArgv) - initializedLatch.countDown() - while (true) { - runNode(internalNativePointer) - while (true) { - val w = workQueue.poll() ?: break - w() - } - if (stopped) { - break - } - } - } - } - - companion object { - init { - System.loadLibrary("akono-jni") - } - } - - interface MessageHandler { - fun handleMessage(message: String) - } -} diff --git a/akono/src/main/java/net/taler/akono/AkonoJni.kt b/akono/src/main/java/net/taler/akono/AkonoJni.kt new file mode 100644 index 00000000..0824e268 --- /dev/null +++ b/akono/src/main/java/net/taler/akono/AkonoJni.kt @@ -0,0 +1,151 @@ +package net.taler.akono + +import android.util.Base64 +import android.util.Log +import java.lang.Exception +import java.nio.ByteBuffer +import java.util.concurrent.CountDownLatch +import java.util.concurrent.LinkedBlockingDeque +import kotlin.concurrent.thread + +typealias AkonoNativePointer = ByteBuffer + +private const val TAG = "AkonoJni" + +class AkonoJni(vararg nodeArgv: String) { + private var messageHandler: MessageHandler? = null + private val initializedLatch = CountDownLatch(1) + + private val workQueue = LinkedBlockingDeque<() -> Unit>() + + private external fun evalJs(source: String, p: AkonoNativePointer): String + private external fun runNode(p: AkonoNativePointer) + + private external fun makeCallbackNative(source: String, p: AkonoNativePointer) + private external fun putModuleCodeNative(key: String, source: String) + + private external fun destroyNative(b: AkonoNativePointer) + private external fun initNative(nodeArgv: Array): AkonoNativePointer + private external fun notifyNative(b: AkonoNativePointer) + + private lateinit var internalNativePointer: AkonoNativePointer + + private val jniThread: Thread + + private var stopped = false + + /** + * Schedule a block do be executed in the node thread. + */ + private fun scheduleNodeThread(b: () -> Unit) { + initializedLatch.await() + workQueue.put(b) + notifyNative() + } + + /** + * Called by node/v8 from its thread. + */ + private fun internalOnNotify(payload: String) { + messageHandler?.handleMessage(payload) + } + + + fun notifyNative() { + initializedLatch.await() + notifyNative(internalNativePointer) + } + + /** + * Schedule Node.JS to be run. + */ + fun evalSimpleJs(source: String): String { + val latch = CountDownLatch(1) + var result: String? = null + scheduleNodeThread { + result = evalJs(source, internalNativePointer) + latch.countDown() + } + latch.await() + return result ?: throw Exception("invariant failed") + } + + fun evalNodeCode(source: String) { + scheduleNodeThread { + makeCallbackNative(source, internalNativePointer) + } + } + + /** + * Send a message to node, calling global.__akono_onMessage. + */ + fun sendMessage(message: String) { + val encoded = Base64.encodeToString(message.toByteArray(), Base64.NO_WRAP) + val source = """ + if (global.__native_onMessage) { + const msg = (new Buffer('$encoded', 'base64')).toString('ascii'); + global.__native_onMessage(msg); + } else { + console.log("WARN: no __native_onMessage defined"); + } + """.trimIndent() + evalNodeCode(source) + } + + fun waitStopped() { + Log.i(TAG, "waiting for stop") + scheduleNodeThread { + stopped = true + } + jniThread.join() + return + } + + fun putModuleCode(modName: String, code: String) { + Log.v(TAG, "putting module code (kotlin)") + putModuleCodeNative(modName, code) + } + + /** + * Register a message handler that is called when the JavaScript code + * running in [runNodeJs] calls __native_sendMessage + * + * Does not block. + */ + fun setMessageHandler(handler: MessageHandler) { + this.messageHandler = handler + } + + + @Override + protected fun finalize() { + destroyNative(internalNativePointer) + } + + init { + jniThread = thread { + internalNativePointer = initNative(nodeArgv) + initializedLatch.countDown() + while (true) { + runNode(internalNativePointer) + while (true) { + val w = workQueue.poll() ?: break + w() + } + if (stopped) { + break + } + } + } + } + + companion object { + init { + System.loadLibrary("akono-jni") + } + } + + interface MessageHandler { + fun handleMessage(message: String) + } +} diff --git a/akono/src/test/java/akono/LibraryTest.kt b/akono/src/test/java/akono/LibraryTest.kt deleted file mode 100644 index 1a16e7e6..00000000 --- a/akono/src/test/java/akono/LibraryTest.kt +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This Kotlin source file was generated by the Gradle 'init' task. - */ -package akono - -import kotlin.test.Test -import kotlin.test.assertTrue -import kotlin.test.assertEquals - -import akono.AkonoJni - -class LibraryTest { - @Test fun testSomeLibraryMethod() { - assertTrue(true) - } -} -- cgit v1.2.3