diff options
Diffstat (limited to 'akono/src')
-rw-r--r-- | akono/src/main/cpp/akono-jni.cpp | 253 | ||||
-rw-r--r-- | akono/src/main/java/akono/AkonoJni.kt | 58 |
2 files changed, 27 insertions, 284 deletions
diff --git a/akono/src/main/cpp/akono-jni.cpp b/akono/src/main/cpp/akono-jni.cpp index 0480eea5..1d0f7512 100644 --- a/akono/src/main/cpp/akono-jni.cpp +++ b/akono/src/main/cpp/akono-jni.cpp @@ -1,9 +1,11 @@ -#include <string.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <cstring> #include <jni.h> #include <libplatform/libplatform.h> #include <v8.h> -#define NODE_WANT_INTERNALS 1 +#define NODE_WANT_INTERNALS 1 // NOLINT(cppcoreguidelines-macro-usage) #include <node.h> @@ -11,10 +13,9 @@ #include <unistd.h> #include <android/log.h> #include <node_main_instance.h> +#include <node_binding.h> #include <node_native_module_env.h> - - // Provide stubs so that libnode.so links properly namespace node { namespace native_module { @@ -40,7 +41,7 @@ static const char *tag = "myapp"; static void *thread_func(void *) { ssize_t rdsz; - char buf[128]; + char buf[1024]; while ((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) { if (buf[rdsz - 1] == '\n') --rdsz; buf[rdsz] = 0; /* add null-terminator */ @@ -83,7 +84,7 @@ private: JNIEnv *m_env; public: JStringValue(JNIEnv *env, jstring s) : m_env(env), m_jstr(s) { - m_cstr = env->GetStringUTFChars(s, NULL); + m_cstr = env->GetStringUTFChars(s, nullptr); } ~JStringValue() { @@ -111,82 +112,21 @@ static void InitNode(std::vector<const char *> argv) { void notifyCb(uv_async_t *async); static void sendMessageCallback(const v8::FunctionCallbackInfo<v8::Value> &args); -static void loadModuleCallback(const v8::FunctionCallbackInfo<v8::Value> &args); -static void getDataCallback(const v8::FunctionCallbackInfo<v8::Value> &args); static const char *main_code = "global.__akono_run = (x) => {" - " console.log('running code', x);" + " 0 && console.log('running code', x);" " global.eval(x);" "};" "" "global.__akono_onMessage = (x) => {" - " console.log('got __akono_onMessage', x);" - "};" - "" - "mod = require('module');" - "mod._saved_findPath = mod._findPath;" - "mod._akonoMods = {};" - "mod._findPath = (request, paths, isMain) => {" - " console.log('in _findPath');" - " const res = mod._saved_findPath(request, paths, isMain);" - " if (res !== false) return res;" - " const args = JSON.stringify({ request, paths});" - " const loadResult = JSON.parse(global.__akono_loadModule(args));" - " console.log('got loadModule result');" - " if (!loadResult) return false;" - " console.log('loadModule path is', loadResult.path);" - " mod._akonoMods[loadResult.path] = loadResult;" - " console.log('returning path', loadResult.path);" - " return loadResult.path;" - "};" - "" - "function stripBOM(content) {" - " if (content.charCodeAt(0) === 0xFEFF) {" - " content = content.slice(1);" - " }" - " return content;" - "}" - "" - "mod._saved_js_extension = mod._extensions[\".js\"];" - "mod._extensions[\".js\"] = (module, filename) => {" - " console.log('handling js extension', [module, filename]);" - " if (mod._akonoMods.hasOwnProperty(filename)) {" - " const akmod = mod._akonoMods[filename];" - " console.log('found mod');" - " const content = akmod.content;" - " module._compile(stripBOM(content), filename);" - " return;" - " }" - " console.log('falling back');" - " return mod._saved_js_extension(module, filename);" - "};" - "" - "mod._saved_json_extension = mod._extensions[\".json\"];" - "mod._extensions[\".json\"] = (module, filename) => {" - " console.log('handling json extension', [module, filename]);" - " if (mod._akonoMods.hasOwnProperty(filename)) {" - " const akmod = mod._akonoMods[filename];" - " console.log('found mod');" - " const content = akmod.content;" - " try {" - " module.exports = JSON.parse(stripBOM(content));" - " return;" - " } catch (err) {" - " err.message = filename + ': ' + err.message;" - " throw err;" - " }" - " }" - " console.log('falling back');" - " return mod._saved_json_extension(module, filename);" - "};" - ""; + " 0 && console.log('got __akono_onMessage', x);" + "};"; class NativeAkonoInstance { private: static bool logInitialized; static bool v8Initialized; - //static std::unique_ptr<v8::Platform> platform; static node::MultiIsolatePlatform *platform; public: v8::Isolate *isolate; @@ -245,12 +185,8 @@ public: // Arguments for the script run by node std::vector<const char *> nodeExecArgv{}; - mylog("entering global scope"); - v8::Context::Scope context_scope(globalContext.Get(isolate)); - mylog("creating environment"); - node::Environment *environment = node::CreateEnvironment( isolateData, globalContext.Get(isolate), @@ -259,12 +195,8 @@ public: nodeExecArgv.size(), &nodeExecArgv[0]); - mylog("loading environment"); - node::LoadEnvironment(environment); - mylog("finished loading environment"); - v8::Local<v8::ObjectTemplate> dataTemplate = v8::ObjectTemplate::New(isolate); dataTemplate->SetInternalFieldCount(1); v8::Local<v8::Object> dataObject = dataTemplate->NewInstance(context).ToLocalChecked(); @@ -274,29 +206,12 @@ public: sendMessageCallback, dataObject).ToLocalChecked(); - v8::Local<v8::Function> loadModuleFunction = v8::Function::New(context, - loadModuleCallback, - dataObject).ToLocalChecked(); - - v8::Local<v8::Function> getDataFunction = v8::Function::New(context, - getDataCallback, - dataObject).ToLocalChecked(); - v8::Local<v8::Object> global = context->Global(); global->Set(v8::String::NewFromUtf8(isolate, "__akono_sendMessage", v8::NewStringType::kNormal).ToLocalChecked(), sendMessageFunction); - global->Set(v8::String::NewFromUtf8(isolate, "__akono_loadModule", - v8::NewStringType::kNormal).ToLocalChecked(), - loadModuleFunction); - - // Get data synchronously (!) from the embedder - global->Set(v8::String::NewFromUtf8(isolate, "__akono_getData", - v8::NewStringType::kNormal).ToLocalChecked(), - getDataFunction); - } /** @@ -305,12 +220,14 @@ public: * @param env JNI env of the thread we're running in. */ void runNode() { + //printf("running node loop, tid=%llu\n", (unsigned long long) syscall(__NR_gettid)); + v8::Locker locker(isolate); v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> context = globalContext.Get(isolate); v8::Context::Scope context_scope(context); this->breakRequested = false; - while (1) { + while (true) { uv_run(uv_default_loop(), UV_RUN_ONCE); platform->DrainTasks(isolate); if (this->breakRequested) @@ -324,7 +241,7 @@ public: * Must not be called from a different thread. */ void makeCallback(const char *code) { - mylog("in makeCallback"); + v8::Locker locker(isolate); v8::Isolate::Scope isolate_scope(isolate); v8::HandleScope handle_scope(isolate); v8::Local<v8::Context> context = globalContext.Get(isolate); @@ -334,7 +251,6 @@ public: v8::String::NewFromUtf8(isolate, code, v8::NewStringType::kNormal).ToLocalChecked() }; - mylog("calling node::MakeCallback"); node::MakeCallback(isolate, global, "__akono_run", 1, argv, {0, 0}); } @@ -343,8 +259,6 @@ public: } jstring evalJs(JNIEnv *env, jstring sourceString) { - mylog("begin evalJs"); - JStringValue jsv(env, sourceString); v8::Isolate::Scope isolate_scope(isolate); @@ -370,28 +284,19 @@ public: // Compile the source code. v8::Local<v8::Script> script; - mylog("about to compile script"); - if (!v8::Script::Compile(context, source).ToLocal(&script)) { return nullptr; } - mylog("about to run script"); - // Run the script to get the result. v8::Local<v8::Value> result; if (!script->Run(context).ToLocal(&result)) { - mylog("running script failed"); return nullptr; } - mylog("converting script result value"); - // Convert the result to an UTF8 string and print it. v8::String::Utf8Value utf8(isolate, result); - mylog("about to return value"); - return env->NewStringUTF(*utf8); } } @@ -404,8 +309,7 @@ node::MultiIsolatePlatform *NativeAkonoInstance::platform = nullptr; void notifyCb(uv_async_t *async) { - NativeAkonoInstance *akono = (NativeAkonoInstance *) async->data; - mylog("async notifyCb called!"); + auto akono = (NativeAkonoInstance *) async->data; akono->breakRequested = true; } @@ -415,11 +319,9 @@ static void sendMessageCallback(const v8::FunctionCallbackInfo<v8::Value> &args) v8::HandleScope scope(isolate); v8::Local<v8::Value> arg = args[0]; v8::String::Utf8Value value(isolate, arg); - mylog("sendMessageCallback called, yay!"); v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(args.Data()); - mylog("getting instance"); NativeAkonoInstance *myInstance = (NativeAkonoInstance *) data->GetAlignedPointerFromInternalField(0); JNIEnv *env = myInstance->currentJniEnv; @@ -429,7 +331,6 @@ static void sendMessageCallback(const v8::FunctionCallbackInfo<v8::Value> &args) return; } - mylog("finding class"); jclass clazz = env->FindClass("akono/AkonoJni"); if (clazz == nullptr) { @@ -437,12 +338,9 @@ static void sendMessageCallback(const v8::FunctionCallbackInfo<v8::Value> &args) return; } - mylog("creating strings"); jstring jstr1 = env->NewStringUTF("message"); jstring jstr2 = env->NewStringUTF(*value); - mylog("getting method"); - jmethodID meth = env->GetMethodID(clazz, "internalOnNotify", "(Ljava/lang/String;Ljava/lang/String;)V"); if (meth == nullptr) { @@ -450,122 +348,9 @@ static void sendMessageCallback(const v8::FunctionCallbackInfo<v8::Value> &args) return; } - mylog("calling method"); - env->CallVoidMethod(myInstance->currentJniThiz, meth, jstr1, jstr2); } - -static void loadModuleCallback(const v8::FunctionCallbackInfo<v8::Value> &args) { - if (args.Length() < 1) return; - v8::Isolate *isolate = args.GetIsolate(); - v8::HandleScope scope(isolate); - v8::Local<v8::Value> arg = args[0]; - v8::String::Utf8Value value(isolate, arg); - mylog("sendMessageCallback called, yay!"); - - v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(args.Data()); - - mylog("getting instance"); - NativeAkonoInstance *myInstance = (NativeAkonoInstance *) data->GetAlignedPointerFromInternalField(0); - - JNIEnv *env = myInstance->currentJniEnv; - - if (env == nullptr) { - mylog("FATAL: JNI env is nullptr"); - return; - } - - mylog("finding class"); - jclass clazz = env->FindClass("akono/AkonoJni"); - - if (clazz == nullptr) { - mylog("FATAL: class not found"); - return; - } - - mylog("creating strings"); - jstring jstr1 = env->NewStringUTF(*value); - - mylog("getting method"); - - jmethodID meth = env->GetMethodID(clazz, "internalOnModuleLoad", "(Ljava/lang/String;)Ljava/lang/String;"); - - if (meth == nullptr) { - mylog("FATAL: method not found"); - return; - } - - mylog("calling method"); - - jstring jresult = (jstring) env->CallObjectMethod(myInstance->currentJniThiz, meth, jstr1); - - JStringValue resultStringValue(env, jresult); - - // Create a string containing the JavaScript source code. - v8::Local<v8::String> rs = - v8::String::NewFromUtf8(isolate, *resultStringValue, - v8::NewStringType::kNormal) - .ToLocalChecked(); - - args.GetReturnValue().Set(rs); -} - - -static void getDataCallback(const v8::FunctionCallbackInfo<v8::Value> &args) { - if (args.Length() < 1) return; - v8::Isolate *isolate = args.GetIsolate(); - v8::HandleScope scope(isolate); - v8::Local<v8::Value> arg = args[0]; - v8::String::Utf8Value value(isolate, arg); - mylog("getDataCallback called"); - - v8::Local<v8::Object> data = v8::Local<v8::Object>::Cast(args.Data()); - mylog("getting instance"); - NativeAkonoInstance *myInstance = (NativeAkonoInstance *) data->GetAlignedPointerFromInternalField(0); - - JNIEnv *env = myInstance->currentJniEnv; - if (env == nullptr) { - mylog("FATAL: JNI env is nullptr"); - return; - } - - mylog("finding class"); - jclass clazz = env->FindClass("akono/AkonoJni"); - - if (clazz == nullptr) { - mylog("FATAL: class not found"); - return; - } - - mylog("creating strings"); - jstring jstr1 = env->NewStringUTF(*value); - - mylog("getting method"); - - jmethodID meth = env->GetMethodID(clazz, "internalOnGetData", "(Ljava/lang/String;)Ljava/lang/String;"); - - if (meth == nullptr) { - mylog("FATAL: method not found"); - return; - } - - mylog("calling method"); - - jstring jresult = (jstring) env->CallObjectMethod(myInstance->currentJniThiz, meth, jstr1); - - JStringValue resultStringValue(env, jresult); - - // Create a string containing the JavaScript source code. - v8::Local<v8::String> rs = - v8::String::NewFromUtf8(isolate, *resultStringValue, - v8::NewStringType::kNormal) - .ToLocalChecked(); - - args.GetReturnValue().Set(rs); -} - - extern "C" JNIEXPORT jobject JNICALL Java_akono_AkonoJni_initNative(JNIEnv *env, jobject thiz) { NativeAkonoInstance *myInstance = new NativeAkonoInstance(); @@ -608,3 +393,11 @@ Java_akono_AkonoJni_makeCallbackNative(JNIEnv *env, jobject thiz, jstring source myInstance->currentJniThiz = thiz; return myInstance->makeCallback(*jsv); } + +void InitializeAkono(v8::Local<v8::Object> target, + v8::Local<v8::Value> unused, + v8::Local<v8::Context> context, + void* priv) { +} + +NODE_MODULE_CONTEXT_AWARE_INTERNAL(akono, InitializeAkono) diff --git a/akono/src/main/java/akono/AkonoJni.kt b/akono/src/main/java/akono/AkonoJni.kt index 0ba31ee8..6aecb3af 100644 --- a/akono/src/main/java/akono/AkonoJni.kt +++ b/akono/src/main/java/akono/AkonoJni.kt @@ -13,10 +13,10 @@ typealias AkonoNativePointer = ByteBuffer data class ModuleResult(val path: String, val contents: String) +private val TAG = "AkonoJni" + class AkonoJni(vararg nodeArgv: String) { - private var getDataHandler: GetDataHandler? = null private var messageHandler: MessageHandler? = null - private var loadModuleHandler: LoadModuleHandler? = null private val initializedLatch = CountDownLatch(1) private val workQueue = LinkedBlockingDeque<() -> Unit>() @@ -53,49 +53,6 @@ class AkonoJni(vararg nodeArgv: String) { messageHandler?.handleMessage(payload) } - /** - * Called by node/v8 from its thread. - */ - @Suppress("unused") - private fun internalOnModuleLoad(loadInfoStr: String): String { - try { - val loadInfo = JSONObject(loadInfoStr) - val request: String = loadInfo.getString("request") - Log.i("myapp", "request is $request") - val paths = ArrayList<String>() - val pathsJson = loadInfo.getJSONArray("paths") - for (i in 0 until pathsJson.length()) { - val path = pathsJson.getString(i) - if (path.startsWith("/vmodroot/")) { - paths.add(path) - } - } - paths.add("/vmodroot") - val handler = loadModuleHandler - if (handler != null) { - val modResult = handler.loadModule(request, paths.toTypedArray()) ?: return "null" - val result = JSONObject() - result.put("path", modResult.path) - result.put("content", modResult.contents) - return result.toString() - } else { - Log.w("myapp", "no module load handler registered") - return "null" - } - } catch (e: Exception) { - Log.e("myapp", "exception during internalOnModuleLoad: $e") - return "null" - } - } - - /** - * Called by node/v8 from its thread. - */ - @Suppress("unused") - private fun internalOnGetData(what: String): String? { - val data = getDataHandler?.handleGetData(what) ?: return null - return Base64.encodeToString(data, Base64.NO_WRAP) - } fun notifyNative() { initializedLatch.await() @@ -142,7 +99,7 @@ class AkonoJni(vararg nodeArgv: String) { * */ fun waitStopped(): Unit { - Log.i("myapp", "waiting for stop") + Log.i(TAG, "waiting for stop") scheduleNodeThread { stopped = true } @@ -160,13 +117,6 @@ class AkonoJni(vararg nodeArgv: String) { this.messageHandler = handler } - fun setLoadModuleHandler(handler: LoadModuleHandler) { - this.loadModuleHandler = handler - } - - fun setGetDataHandler(handler: GetDataHandler) { - this.getDataHandler = handler - } @Override protected fun finalize() { @@ -208,4 +158,4 @@ class AkonoJni(vararg nodeArgv: String) { interface GetDataHandler { fun handleGetData(what: String): ByteArray? } -}
\ No newline at end of file +} |