Skip to content
This repository has been archived by the owner on Mar 9, 2022. It is now read-only.

Commit

Permalink
CouchDB in-process changes
Browse files Browse the repository at this point in the history
* 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
apage43 committed Sep 21, 2011
1 parent 32d799b commit d55d695
Show file tree
Hide file tree
Showing 22 changed files with 976 additions and 381 deletions.
1 change: 1 addition & 0 deletions .classpath
Expand Up @@ -4,5 +4,6 @@
<classpathentry kind="src" path="gen"/> <classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> <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/commons-compress-1.0.jar"/>
<classpathentry kind="lib" path="libs/OtpErlang.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>
Binary file added assets/couchbase-1.0-dp-572c764.tgz.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 17 additions & 1 deletion build.xml
Expand Up @@ -95,6 +95,10 @@
<target name="dist" depends="couchbase-jar"> <target name="dist" depends="couchbase-jar">
<zip destfile="bin/Couchbase.zip"> <zip destfile="bin/Couchbase.zip">


<fileset dir="${basedir}">
<include name="overlay.zip"/>
</fileset>

<mappedresources> <mappedresources>
<fileset dir="${basedir}"> <fileset dir="${basedir}">
<include name="assets/**/*"/> <include name="assets/**/*"/>
Expand Down Expand Up @@ -124,7 +128,19 @@
<include name="README.txt"/> <include name="README.txt"/>
</fileset> </fileset>
</zip> </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"> <target name="javadoc">
<javadoc <javadoc
Expand Down
6 changes: 3 additions & 3 deletions jni/Android.mk
Expand Up @@ -2,8 +2,8 @@ LOCAL_PATH := $(call my-dir)


include $(CLEAR_VARS) include $(CLEAR_VARS)


LOCAL_MODULE := com_google_ase_Exec LOCAL_MODULE := com_couchbase_android_ErlangThread
LOCAL_SRC_FILES := com_google_ase_Exec.cpp LOCAL_SRC_FILES := com_couchbase_android_ErlangThread.cpp android_jni_nif.cpp
LOCAL_LDLIBS := -llog LOCAL_LDLIBS := -llog -ldl -L$(LOCAL_PATH) -lbeam


include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)
78 changes: 78 additions & 0 deletions jni/android_jni_nif.cpp
@@ -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);
65 changes: 65 additions & 0 deletions jni/com_couchbase_android_ErlangThread.cpp
@@ -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;
}
29 changes: 29 additions & 0 deletions jni/com_couchbase_android_ErlangThread.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d55d695

Please sign in to comment.