Permalink
Browse files

CouchDB in-process changes

* CouchDB now runs in the same process as the Dalvik VM.
* JNI library/NIF added for direct communication from Erlang for:
  - Collation via java.text.Collator
  - Notification of CouchDB start, along with URL
  - Direct logging to logcat (as we no longer capture stdout)
* .beam and .app files are now loaded directly from the .APK
* Extra files layout has changed. .beam, .app, and .so files are now
  in overlay.zip, which is extracted over the target project by the
  couchbase.xml ant script.
* .so files now live in libs/armeabi, and get auto-extracted by android
Change-Id: I8ad5817a285ad831ca572683a35799ceb36c3ada
Reviewed-on: http://review.couchbase.org/9617
Reviewed-by: Aaron Miller <apage43@ninjawhale.com>
Tested-by: Aaron Miller <apage43@ninjawhale.com>
  • Loading branch information...
1 parent 32d799b commit d55d695f17dac5fc8b3db918c2c6051042f24757 @apage43 apage43 committed Sep 15, 2011
View
@@ -4,5 +4,6 @@
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="lib" path="libs/commons-compress-1.0.jar"/>
+ <classpathentry kind="lib" path="libs/OtpErlang.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
@@ -95,6 +95,10 @@
<target name="dist" depends="couchbase-jar">
<zip destfile="bin/Couchbase.zip">
+ <fileset dir="${basedir}">
+ <include name="overlay.zip"/>
+ </fileset>
+
<mappedresources>
<fileset dir="${basedir}">
<include name="assets/**/*"/>
@@ -124,7 +128,19 @@
<include name="README.txt"/>
</fileset>
</zip>
- </target>
+ </target>
+
+ <target name="jni">
+ <unzip src="${basedir}/overlay.zip" dest="${basedir}/jni">
+ <patternset>
+ <include name="libs/armeabi/libbeam.so"/>
+ </patternset>
+ <mapper type="flatten"/>
+ </unzip>
+ <exec dir="${basedir}/jni" executable="sh">
+ <arg line="${ndk.dir}/ndk-build"/>
+ </exec>
+ </target>
<target name="javadoc">
<javadoc
View
@@ -2,8 +2,8 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := com_google_ase_Exec
-LOCAL_SRC_FILES := com_google_ase_Exec.cpp
-LOCAL_LDLIBS := -llog
+LOCAL_MODULE := com_couchbase_android_ErlangThread
+LOCAL_SRC_FILES := com_couchbase_android_ErlangThread.cpp android_jni_nif.cpp
+LOCAL_LDLIBS := -llog -ldl -L$(LOCAL_PATH) -lbeam
include $(BUILD_SHARED_LIBRARY)
View
@@ -0,0 +1,78 @@
+#include "android/log.h"
+#include "erl_nif.h"
+#include <string.h>
+#include <jni.h>
+
+#include "com_couchbase_android_ErlangThread.h"
+
+#define LOG_TAG "JNINIF"
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
+#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
+extern JavaVM *jvm;
+extern jclass ErlangThread;
+extern jmethodID ErlMessageMethod;
+
+struct caller_info {
+ ErlNifPid pid;
+ ErlNifEnv *env;
+};
+
+JNIEXPORT void JNICALL Java_com_couchbase_android_ErlangThread_send_1bin
+ (JNIEnv *env, jclass cls, jbyteArray jbin, jlong cinfo) {
+ struct caller_info* inf = (struct caller_info*) cinfo;
+ ErlNifEnv* msg = enif_alloc_env();
+ ERL_NIF_TERM bin_term;
+ jsize length = env->GetArrayLength(jbin);
+ jbyte* bindata = (jbyte*) enif_make_new_binary(msg, length, &bin_term);
+ env->GetByteArrayRegion(jbin, 0, length, bindata);
+ enif_send(inf->env, &(inf->pid), msg, bin_term);
+ enif_free_env(msg);
+}
+
+static ERL_NIF_TERM mkatom(ErlNifEnv* env, const char* name) {
+ ERL_NIF_TERM atom;
+ if(enif_make_existing_atom(env, name, &atom, ERL_NIF_LATIN1)) {
+ return atom;
+ } else {
+ return enif_make_atom(env, name);
+ }
+}
+
+static ERL_NIF_TERM jninif_send(ErlNifEnv* nif_env, int argc, const ERL_NIF_TERM argv[])
+{
+ struct caller_info cinf;
+ JNIEnv *env = NULL;
+ char namebuf[512];
+
+ cinf.env = nif_env;
+ enif_self(nif_env, &(cinf.pid));
+
+ if(!enif_get_atom(nif_env, argv[0], namebuf, 512, ERL_NIF_LATIN1)) {
+ return mkatom(nif_env, "name_too_long");
+ }
+
+ jvm->AttachCurrentThread(&env, NULL);
+ if(env == NULL) {
+ return mkatom(nif_env, "jni_error");
+ }
+
+ env->PushLocalFrame(2); //We use 2 local JNI refs per invoc.
+ ErlNifBinary ebin;
+ jbyteArray jbin;
+ jstring name = env->NewStringUTF(namebuf);
+ enif_inspect_binary(nif_env, argv[1], &ebin);
+ jbin = env->NewByteArray(ebin.size);
+ env->SetByteArrayRegion(jbin, 0, ebin.size, (jbyte*) ebin.data);
+ env->CallStaticVoidMethod(ErlangThread, ErlMessageMethod, name, jbin, (jlong) &cinf);
+ env->PopLocalFrame(NULL);
+ return mkatom(nif_env, "ok");
+}
+
+static ErlNifFunc jninif_funcs[] =
+{
+ {"send", 2, jninif_send}
+};
+
+ERL_NIF_INIT(jninif, jninif_funcs, NULL, NULL, NULL, NULL);
@@ -0,0 +1,65 @@
+#include "com_couchbase_android_ErlangThread.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+#include "android/log.h"
+
+#define LOG_TAG "ErlangThread"
+#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
+
+JavaVM *jvm;
+jclass ErlangThread;
+jmethodID ErlMessageMethod;
+
+JNIEXPORT void JNICALL Java_com_couchbase_android_ErlangThread_start_1erlang
+ (JNIEnv *env, jclass cls, jstring j_bindir, jstring j_sopath, jobjectArray j_args) {
+ jboolean iscopy;
+ int i, argc;
+ char ** argv;
+ void (*erl_start)(int, char**) = NULL;
+
+ const char *sopath = env->GetStringUTFChars(j_sopath, &iscopy);
+ const char *bindir = env->GetStringUTFChars(j_bindir, &iscopy);
+
+ void* handle = dlopen(sopath, RTLD_LAZY);
+
+ if(!handle) {
+ LOGE("Failed to open beam .so: %s", dlerror());
+ goto cleanup;
+ }
+ *(void **)(&erl_start) = dlsym(handle, "erl_start");
+ if(!erl_start) {
+ LOGE("Failed to find erl_start: %s", dlerror());
+ goto cleanup;
+ }
+ argc = env->GetArrayLength(j_args);
+ argv = (char**) malloc(sizeof(char*) * argc);
+
+ for(i = 0; i < argc; i++)
+ {
+ argv[i] = (char*) env->GetStringUTFChars((jstring) env->GetObjectArrayElement(j_args, i), &iscopy);
+ }
+ setenv("BINDIR", bindir, 1);
+ env->GetJavaVM(&jvm);
+ ErlMessageMethod = env->GetStaticMethodID(cls, "erl_message", "(Ljava/lang/String;[BJ)V");
+ ErlangThread = (jclass) env->NewGlobalRef(cls);
+ erl_start(argc, argv);
+
+ cleanup:
+ env->DeleteGlobalRef(ErlangThread);
+ env->ReleaseStringUTFChars(j_sopath, sopath);
+ env->ReleaseStringUTFChars(j_bindir, bindir);
+ if(handle) dlclose(handle);
+ if(argv)
+ {
+ for(i = 0; i < argc; i++)
+ {
+ env->ReleaseStringUTFChars((jstring) env->GetObjectArrayElement(j_args, i), argv[i]);
+ }
+ free(argv);
+ }
+ return;
+}

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
Oops, something went wrong.

0 comments on commit d55d695

Please sign in to comment.