summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Lillqvist <tlillqvist@suse.com>2011-11-15 01:41:57 +0200
committerTor Lillqvist <tlillqvist@suse.com>2011-11-15 01:54:49 +0200
commit2bf110d691053353d6cb06ad2bbd1b78fef60f19 (patch)
tree159fcfed4e1d335f65a1e17802a2445a7cfe2487
parentd14416463a0e62cf624cf66e8a599abac5694cd2 (diff)
Rework the bootstrap mechanism of a LO program on Android
Do use NativeActivity and android_native_app_glue after all. I hope this enables us to have a "message pump" (a loop that typically would call ALooper_pollAll()) inside the LO "program" being run, as expected by LO code. (On Android, a "program", even one mostly implemented in native code, is actually a shared library loaded by the main Java code of an app.) The android_native_app_glue code and the android_main() it calls belongs in the bootstrap library, though. Not in SAL_MAIN_IMPL. The earlier idea, having a "normal" Java Activity subclass, would mean events come in as method calls to that class. To then turn those into something the LO code can "get", we would have effectively had to re-implement what android_native_app_glue does anyway.
-rw-r--r--sal/inc/sal/main.h3
-rw-r--r--sal/osl/android/AndroidManifest.xml9
-rw-r--r--sal/osl/android/Makefile2
-rw-r--r--sal/osl/android/jni/Android.mk2
-rw-r--r--sal/osl/android/jni/android_native_app_glue.c (renamed from solenv/inc/unxandr/android_native_app_glue.c)0
-rw-r--r--sal/osl/android/jni/android_native_app_glue.h (renamed from solenv/inc/unxandr/android_native_app_glue.h)0
-rw-r--r--sal/osl/android/jni/lo-bootstrap.c524
-rw-r--r--sal/osl/android/project.properties2
-rw-r--r--sal/osl/android/src/org/libreoffice/android/Bootstrap.java150
9 files changed, 502 insertions, 190 deletions
diff --git a/sal/inc/sal/main.h b/sal/inc/sal/main.h
index 6bbbb1e8e2a2..d1d3fffde862 100644
--- a/sal/inc/sal/main.h
+++ b/sal/inc/sal/main.h
@@ -133,6 +133,7 @@ static int sal_main_with_args(int argc, char **argv); \
\
void lo_main(int argc, char **argv) \
{ \
+ LOGI("in lo_main, argc=%d, argv[0]=%s, argv[1]=%s", argc, argv[0], argv[1]); \
sal_detail_initialize(argc, argv); \
sal_main_with_args(argc, argv); \
sal_detail_deinitialize(); \
@@ -143,7 +144,7 @@ static int sal_main(void); \
\
void lo_main(int argc, char **argv) \
{ \
- LOGI("in lo_main, argc=%d, argv[0]=%s, argv[1]=%s", argc, argv[0], argv[1]); \
+ LOGI("in lo_main, argc=%d, argv[0]=%s, argv[1]=%s", argc, argv[0], argv[1]); \
sal_detail_initialize(argc, argv); \
sal_main(); \
sal_detail_deinitialize(); \
diff --git a/sal/osl/android/AndroidManifest.xml b/sal/osl/android/AndroidManifest.xml
index c88a9d11576c..159bbf105d75 100644
--- a/sal/osl/android/AndroidManifest.xml
+++ b/sal/osl/android/AndroidManifest.xml
@@ -4,10 +4,17 @@
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" />
+ <!-- This .apk uses a subclass of NativeActivity, so it *has* Java code. -->
+ <!-- android:hasCode="false" -->
<application android:label="@string/app_name"
android:debuggable="true">
+ <!-- <activity android:name="android.app.NativeActivity" -->
<activity android:name=".Bootstrap"
- android:label="@string/app_name">
+ android:label="LibreOffice Bootstrap"
+ android:configChanges="orientation|keyboardHidden">
+ <!-- Tell NativeActivity the name of our .so -->
+ <meta-data android:name="android.app.lib_name"
+ android:value="lo-bootstrap" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
diff --git a/sal/osl/android/Makefile b/sal/osl/android/Makefile
index 8ee14b8bf2d9..4e89f669ecd7 100644
--- a/sal/osl/android/Makefile
+++ b/sal/osl/android/Makefile
@@ -15,4 +15,4 @@ run: all
unset JAVA_HOME && ant debug install
#
# Note: this is of course just an example
- adb shell am start -a org.libreoffice.android -n org.libreoffice.android/.Bootstrap -e lo-main-library libcppunittester -e lo-main-cmdline "cppunittester /data/data/org.libreoffice.android/lib/libqa_sal_types.so"
+ adb shell am start -n org.libreoffice.android/.Bootstrap -e lo-main-library libcppunittester -e lo-main-cmdline "cppunittester /data/data/org.libreoffice.android/lib/libqa_sal_types.so"
diff --git a/sal/osl/android/jni/Android.mk b/sal/osl/android/jni/Android.mk
index ea6845d4b443..dbb014a63dc9 100644
--- a/sal/osl/android/jni/Android.mk
+++ b/sal/osl/android/jni/Android.mk
@@ -18,6 +18,6 @@ include $(CLEAR_VARS)
LOCAL_MODULE := lo-bootstrap
LOCAL_SRC_FILES := lo-bootstrap.c
-LOCAL_LDLIBS := -llog
+LOCAL_LDLIBS := -llog -landroid
include $(BUILD_SHARED_LIBRARY)
diff --git a/solenv/inc/unxandr/android_native_app_glue.c b/sal/osl/android/jni/android_native_app_glue.c
index 8ff9f69d9946..8ff9f69d9946 100644
--- a/solenv/inc/unxandr/android_native_app_glue.c
+++ b/sal/osl/android/jni/android_native_app_glue.c
diff --git a/solenv/inc/unxandr/android_native_app_glue.h b/sal/osl/android/jni/android_native_app_glue.h
index 1b8c1f10725d..1b8c1f10725d 100644
--- a/solenv/inc/unxandr/android_native_app_glue.h
+++ b/sal/osl/android/jni/android_native_app_glue.h
diff --git a/sal/osl/android/jni/lo-bootstrap.c b/sal/osl/android/jni/lo-bootstrap.c
index 56b72fef5f3e..327d868a3ccf 100644
--- a/sal/osl/android/jni/lo-bootstrap.c
+++ b/sal/osl/android/jni/lo-bootstrap.c
@@ -28,19 +28,61 @@
*/
#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
#include <unistd.h>
#include <fcntl.h>
#include <dlfcn.h>
+
#include <jni.h>
+
#include <linux/elf.h>
+
#include <android/log.h>
+#include <../../../inc/osl/android-lo-bootstrap.h>
+
+#include "android_native_app_glue.c"
+
+#undef LOGI
+#undef LOGW
+
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "lo-bootstrap", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "lo-bootstrap", __VA_ARGS__))
+struct engine {
+ int dummy;
+};
+
+static struct android_app *app;
+static JNIEnv *jni_env;
+static const char **library_locations;
+static int (*lo_main)(int, const char **);
+static int lo_main_argc;
+static const char **lo_main_argv;
+
+static void
+engine_handle_cmd(struct android_app* app,
+ int32_t cmd)
+{
+ struct engine* engine = (struct engine*)app->userData;
+ switch (cmd) {
+ case APP_CMD_SAVE_STATE:
+ break;
+ case APP_CMD_INIT_WINDOW:
+ break;
+ case APP_CMD_TERM_WINDOW:
+ break;
+ case APP_CMD_GAINED_FOCUS:
+ break;
+ case APP_CMD_LOST_FOCUS:
+ break;
+ }
+}
+
static char *
-read_section(JNIEnv *env,
- int fd,
+read_section(int fd,
Elf32_Shdr *shdr)
{
char *result;
@@ -60,15 +102,230 @@ read_section(JNIEnv *env,
return result;
}
+static void
+free_ptrarray(void **pa)
+{
+ void **rover = pa;
+
+ while (*rover != NULL)
+ free(*rover++);
+
+ free(pa);
+}
+
+static void
+setup_library_locations(const char *lib_dir)
+{
+ int n;
+ char *ld_library_path;
+ char *elem;
+
+ ld_library_path = getenv("LD_LIBRARY_PATH");
+ if (ld_library_path == NULL)
+ ld_library_path = "/vendor/lib:/system/lib";
+ ld_library_path = strdup(ld_library_path);
+
+ n = 1;
+ elem = ld_library_path;
+ while ((elem = strchr(elem, ':')) != NULL) {
+ n++;
+ elem++;
+ }
+ library_locations = malloc((n + 2) * sizeof(char *));
+ library_locations[0] = lib_dir;
+ elem = ld_library_path;
+ library_locations[1] = elem;
+ n = 2;
+ while ((elem = strchr(elem, ':')) != NULL) {
+ *elem = '\0';
+ elem++;
+ library_locations[n++] = elem;
+ }
+ library_locations[n] = NULL;
+
+ for (n = 0; library_locations[n] != NULL; n++)
+ LOGI("library_locations[%d] = %s", n, library_locations[n]);
+}
+
jobjectArray
Java_org_libreoffice_android_Bootstrap_dlneeds(JNIEnv* env,
jobject clazz,
jstring library)
{
- int i, fd;
+ char **needed;
int n_needed;
const jbyte *libName;
+ jclass String;
jobjectArray result;
+
+ libName = (*env)->GetStringUTFChars(env, library, NULL);
+
+ needed = lo_dlneeds(libName);
+
+ (*env)->ReleaseStringUTFChars(env, library, libName);
+
+ if (needed == NULL)
+ return NULL;
+
+ n_needed = 0;
+ while (needed[n_needed] != NULL)
+ n_needed++;
+
+ /* Allocate return value */
+
+ String = (*env)->FindClass(env, "java/lang/String");
+ if (String == NULL) {
+ LOGI("Could not find the String class");
+ free_ptrarray((void **) needed);
+ return NULL;
+ }
+
+ result = (*env)->NewObjectArray(env, n_needed, String, NULL);
+ if (result == NULL) {
+ LOGI("Could not create the String array");
+ free_ptrarray((void **) needed);
+ return NULL;
+ }
+
+ for (n_needed = 0; needed[n_needed] != NULL; n_needed++)
+ (*env)->SetObjectArrayElement(env, result, n_needed, (*env)->NewStringUTF(env, needed[n_needed]));
+
+ free_ptrarray((void **) needed);
+
+ return result;
+}
+
+jint
+Java_org_libreoffice_android_Bootstrap_dlopen(JNIEnv* env,
+ jobject clazz,
+ jstring library)
+{
+ const jbyte *libName = (*env)->GetStringUTFChars(env, library, NULL);
+ void *p = lo_dlopen (libName);
+
+ (*env)->ReleaseStringUTFChars(env, library, libName);
+
+ return (jint) p;
+}
+
+jint
+Java_org_libreoffice_android_Bootstrap_dlsym(JNIEnv* env,
+ jobject clazz,
+ jint handle,
+ jstring symbol)
+{
+ const jbyte *symName = (*env)->GetStringUTFChars(env, symbol, NULL);
+ void *p = lo_dlsym ((void *) handle, symName);
+
+ (*env)->ReleaseStringUTFChars(env, symbol, symName);
+
+ return (jint) p;
+}
+
+jint
+Java_org_libreoffice_android_Bootstrap_dlcall(JNIEnv* env,
+ jobject clazz,
+ jint function,
+ jobject argument)
+{
+ jclass StringArray = (*env)->FindClass(env, "[Ljava/lang/String;");
+
+ if (StringArray == NULL) {
+ LOGI("Could not find String[] class");
+ return 0;
+ }
+
+ if ((*env)->IsInstanceOf(env, argument, StringArray)) {
+ LOGI("Yes, a string array argument of length %d", (*env)->GetArrayLength(env, argument));
+ int argc = (*env)->GetArrayLength(env, argument);
+ const char **argv = malloc(sizeof(char *) * (argc+1));
+ int i, result;
+ for (i = 0; i < argc; i++) {
+ argv[i] = (*env)->GetStringUTFChars(env, (*env)->GetObjectArrayElement(env, argument, i), NULL);
+ LOGI("argv[%d] = %s", i, argv[i]);
+ }
+ argv[argc] = NULL;
+
+ result = lo_dlcall_argc_argv((void *) function, argc, argv);
+
+ for (i = 0; i < argc; i++)
+ (*env)->ReleaseStringUTFChars(env, (*env)->GetObjectArrayElement(env, argument, i), argv[i]);
+
+ free(argv);
+ return result;
+ }
+
+ return 0;
+}
+
+jboolean
+Java_org_libreoffice_android_Bootstrap_setup__Ljava_lang_String_2(JNIEnv* env,
+ jobject this,
+ jstring dataDir)
+{
+ int i;
+ const jbyte *dataDirPath;
+ char *lib_dir;
+
+ LOGI("in %s! this=%p", __FUNCTION__, this);
+
+ dataDirPath = (*env)->GetStringUTFChars(env, dataDir, NULL);
+
+ lib_dir = malloc(strlen(dataDirPath) + 5);
+ strcpy(lib_dir, dataDirPath);
+ strcat(lib_dir, "/lib");
+
+ (*env)->ReleaseStringUTFChars(env, dataDir, dataDirPath);
+
+ setup_library_locations(lib_dir);
+
+ return JNI_TRUE;
+}
+
+jboolean
+Java_org_libreoffice_android_Bootstrap_setup__ILjava_lang_Object_2(JNIEnv* env,
+ jobject this,
+ void *lo_main_ptr,
+ jobject lo_main_argument)
+{
+ jclass StringArray;
+ int i;
+
+ LOGI("in %s! this=%p", __FUNCTION__, this);
+
+ lo_main = lo_main_ptr;
+
+ StringArray = (*env)->FindClass(env, "[Ljava/lang/String;");
+ if (StringArray == NULL) {
+ LOGI("Could not find String[] class");
+ return JNI_FALSE;
+ }
+
+ if (!(*env)->IsInstanceOf(env, lo_main_argument, StringArray)) {
+ LOGI("lo_main_argument is not a String[]?");
+ return JNI_FALSE;
+ }
+
+ lo_main_argc = (*env)->GetArrayLength(env, lo_main_argument);
+ lo_main_argv = malloc(sizeof(char *) * (lo_main_argc+1));
+
+ for (i = 0; i < lo_main_argc; i++) {
+ const jbyte *s = (*env)->GetStringUTFChars(env, (*env)->GetObjectArrayElement(env, lo_main_argument, i), NULL);
+ lo_main_argv[i] = strdup(s);
+ (*env)->ReleaseStringUTFChars(env, (*env)->GetObjectArrayElement(env, lo_main_argument, i), s);
+ LOGI("argv[%d] = %s", i, lo_main_argv[i]);
+ }
+ lo_main_argv[lo_main_argc] = NULL;
+
+ return JNI_TRUE;
+}
+
+char **
+lo_dlneeds(const char *library)
+{
+ int i, fd;
+ int n_needed;
+ char **result;
char *shstrtab, *dynstr;
Elf32_Ehdr hdr;
Elf32_Shdr shdr;
@@ -76,13 +333,8 @@ Java_org_libreoffice_android_Bootstrap_dlneeds(JNIEnv* env,
/* Open library and read ELF header */
- libName = (*env)->GetStringUTFChars(env, library, NULL);
-
- LOGI("dlneeds(%s)\n", libName);
-
- fd = open (libName, O_RDONLY);
-
- (*env)->ReleaseStringUTFChars(env, library, libName);
+ LOGI("lo_dlneeds(%s)\n", library);
+ fd = open(library, O_RDONLY);
if (fd == -1) {
LOGI("Could not open library");
@@ -90,44 +342,44 @@ Java_org_libreoffice_android_Bootstrap_dlneeds(JNIEnv* env,
}
if (read(fd, &hdr, sizeof(hdr)) < sizeof(hdr)) {
- close(fd);
LOGI("Could not read ELF header");
+ close(fd);
return NULL;
}
/* Read in .shstrtab */
if (lseek(fd, hdr.e_shoff + hdr.e_shstrndx * sizeof(shdr), SEEK_SET) < 0) {
- close(fd);
LOGI("Could not seek to .shstrtab section header");
+ close(fd);
return NULL;
}
if (read(fd, &shdr, sizeof(shdr)) < sizeof(shdr)) {
- close(fd);
LOGI("Could not read section header");
+ close(fd);
return NULL;
}
- shstrtab = read_section(env, fd, &shdr);
+ shstrtab = read_section(fd, &shdr);
if (shstrtab == NULL)
return NULL;
/* Read section headers, looking for .dynstr section */
if (lseek(fd, hdr.e_shoff, SEEK_SET) < 0) {
- close(fd);
LOGI("Could not seek to section headers");
+ close(fd);
return NULL;
}
for (i = 0; i < hdr.e_shnum; i++) {
if (read(fd, &shdr, sizeof(shdr)) < sizeof(shdr)) {
- close(fd);
LOGI("Could not read section header");
+ close(fd);
return NULL;
}
if (shdr.sh_type == SHT_STRTAB &&
strcmp(shstrtab + shdr.sh_name, ".dynstr") == 0) {
- dynstr = read_section(env, fd, &shdr);
+ dynstr = read_section(fd, &shdr);
if (dynstr == NULL) {
free(shstrtab);
return NULL;
@@ -137,40 +389,39 @@ Java_org_libreoffice_android_Bootstrap_dlneeds(JNIEnv* env,
}
if (i == hdr.e_shnum) {
- close(fd);
LOGI("No .dynstr section");
+ close(fd);
return NULL;
}
/* Read section headers, looking for .dynamic section */
if (lseek(fd, hdr.e_shoff, SEEK_SET) < 0) {
- close(fd);
LOGI("Could not seek to section headers");
+ close(fd);
return NULL;
}
for (i = 0; i < hdr.e_shnum; i++) {
if (read(fd, &shdr, sizeof(shdr)) < sizeof(shdr)) {
- close(fd);
LOGI("Could not read section header");
+ close(fd);
return NULL;
}
if (shdr.sh_type == SHT_DYNAMIC) {
int dynoff;
int *libnames;
- jclass String;
/* Count number of DT_NEEDED entries */
n_needed = 0;
if (lseek(fd, shdr.sh_offset, SEEK_SET) < 0) {
- close(fd);
LOGI("Could not seek to .dynamic section");
+ close(fd);
return NULL;
}
for (dynoff = 0; dynoff < shdr.sh_size; dynoff += sizeof(dyn)) {
if (read(fd, &dyn, sizeof(dyn)) < sizeof(dyn)) {
- close(fd);
LOGI("Could not read .dynamic entry");
+ close(fd);
return NULL;
}
if (dyn.d_tag == DT_NEEDED)
@@ -179,37 +430,25 @@ Java_org_libreoffice_android_Bootstrap_dlneeds(JNIEnv* env,
LOGI("Found %d DT_NEEDED libs", n_needed);
- /* Allocate return value */
-
- String = (*env)->FindClass(env, "java/lang/String");
- if (String == NULL) {
- close(fd);
- LOGI("Could not find the String class");
- return NULL;
- }
-
- result = (*env)->NewObjectArray(env, n_needed, String, NULL);
- if (result == NULL) {
- close (fd);
- LOGI("Could not create the String array");
- return NULL;
- }
+ result = malloc((n_needed+1) * sizeof(char *));
n_needed = 0;
if (lseek(fd, shdr.sh_offset, SEEK_SET) < 0) {
- close(fd);
LOGI("Could not seek to .dynamic section");
+ close(fd);
+ free(result);
return NULL;
}
for (dynoff = 0; dynoff < shdr.sh_size; dynoff += sizeof(dyn)) {
if (read(fd, &dyn, sizeof(dyn)) < sizeof(dyn)) {
- close(fd);
LOGI("Could not read .dynamic entry");
+ close(fd);
+ free(result);
return NULL;
}
if (dyn.d_tag == DT_NEEDED) {
LOGI("needs: %s\n", dynstr + dyn.d_un.d_val);
- (*env)->SetObjectArrayElement(env, result, n_needed, (*env)->NewStringUTF(env, dynstr + dyn.d_un.d_val));
+ result[n_needed] = strdup(dynstr + dyn.d_un.d_val);
n_needed++;
}
}
@@ -217,6 +456,7 @@ Java_org_libreoffice_android_Bootstrap_dlneeds(JNIEnv* env,
close(fd);
free(dynstr);
free(shstrtab);
+ result[n_needed] = NULL;
return result;
}
}
@@ -224,76 +464,170 @@ Java_org_libreoffice_android_Bootstrap_dlneeds(JNIEnv* env,
return NULL;
}
-jint
-Java_org_libreoffice_android_Bootstrap_dlopen(JNIEnv* env,
- jobject clazz,
- jstring library)
+void *
+lo_dlopen(const char *library)
{
- const jbyte *libName = (*env)->GetStringUTFChars(env, library, NULL);
- void *p = dlopen (libName, RTLD_LOCAL);
- LOGI("dlopen(%s) = %p", libName, p);
- (*env)->ReleaseStringUTFChars(env, library, libName);
- if (p == NULL) {
- LOGI(dlerror());
- return 0;
+ /*
+ * We should *not* try to just dlopen() the bare library name
+ * first, as the stupid dynamic linker remembers for each library
+ * basename if loading it has failed. Thus if you try loading it
+ * once, and it fails because of missing needed libraries, and
+ * your load those, and then try again, it fails with an
+ * infuriating message "failed to load previously" in the log.
+ *
+ * We *must* first dlopen() all needed libraries, recursively. It
+ * shouldn't matter if we dlopen() a library that already is
+ * loaded, dlopen() just returns the same value then.
+ */
+
+ typedef struct loadedLib {
+ const char *name;
+ void *handle;
+ struct loadedLib *next;
+ } *loadedLib;
+ static loadedLib loaded_libraries = NULL;
+
+ loadedLib rover;
+ loadedLib new_loaded_lib;
+
+ struct stat st;
+ void *p;
+ char *full_name;
+ char **needed;
+ int i;
+ int found = 0;
+
+ rover = loaded_libraries;
+ while (rover != NULL &&
+ strcmp(rover->name, library) != 0)
+ rover = rover->next;
+
+ if (rover != NULL)
+ return rover->handle;
+
+ LOGI("lo_dlopen(%s)", library);
+
+ if (library[0] == '/') {
+ full_name = strdup(library);
+
+ if (stat(full_name, &st) == 0 &&
+ S_ISREG(st.st_mode))
+ found = 1;
+ else
+ free(full_name);
+ } else {
+ for (i = 0; !found && library_locations[i] != NULL; i++) {
+ full_name = malloc(strlen(library_locations[i]) + 1 + strlen(library) + 1);
+ strcpy(full_name, library_locations[i]);
+ strcat(full_name, "/");
+ strcat(full_name, library);
+
+ if (stat(full_name, &st) == 0 &&
+ S_ISREG(st.st_mode))
+ found = 1;
+ else
+ free(full_name);
+ }
}
- return (jint) p;
+
+ if (!found) {
+ LOGI("Library %s not found", library);
+ return NULL;
+ }
+
+ needed = lo_dlneeds(full_name);
+ if (needed == NULL) {
+ free(full_name);
+ return NULL;
+ }
+
+ for (i = 0; needed[i] != NULL; i++) {
+ if (lo_dlopen(needed[i]) == NULL) {
+ free_ptrarray((void **) needed);
+ free(full_name);
+ return NULL;
+ }
+ }
+
+ p = dlopen(full_name, RTLD_LOCAL);
+ LOGI("dlopen(%s) = %p", full_name, p);
+ free(full_name);
+ if (p == NULL)
+ LOGI(dlerror());
+
+ new_loaded_lib = malloc(sizeof(*new_loaded_lib));
+ new_loaded_lib->name = strdup(library);
+ new_loaded_lib->handle = p;
+
+ new_loaded_lib->next = loaded_libraries;
+ loaded_libraries = new_loaded_lib;
+
+ return p;
}
-jint
-Java_org_libreoffice_android_Bootstrap_dlsym(JNIEnv* env,
- jobject clazz,
- jint handle,
- jstring symbol)
+void *
+lo_dlsym(void *handle,
+ const char *symbol)
{
- const jbyte *symName = (*env)->GetStringUTFChars(env, symbol, NULL);
- void *p = dlsym ((void *)handle, symName);
- LOGI("dlsym(%p,%s) = %p", handle, symName, p);
- (*env)->ReleaseStringUTFChars(env, symbol, symName);
- if (p == NULL) {
+ void *p = dlsym(handle, symbol);
+ LOGI("dlsym(%p, %s) = %p", handle, symbol, p);
+ if (p == NULL)
LOGI(dlerror());
- return 0;
- }
- return (jint) p;
+ return p;
}
-jint
-Java_org_libreoffice_android_Bootstrap_dlcall(JNIEnv* env,
- jobject clazz,
- jint function,
- jobject argument)
+int
+lo_dlcall_argc_argv(void *function,
+ int argc,
+ const char **argv)
{
- jclass StringArray = (*env)->FindClass(env, "[Ljava/lang/String;");
+ int (*fp)(int, const char **) = function;
+ int result = fp(argc, argv);
- if (StringArray == NULL) {
- LOGI("Could not find String[] class");
- return 0;
- }
+ return result;
+}
- if ((*env)->IsInstanceOf(env, argument, StringArray)) {
- LOGI("Yes, a string array argument of length %d", (*env)->GetArrayLength(env, argument));
- int argc = (*env)->GetArrayLength(env, argument);
- const char **argv = malloc(sizeof(char *) * (argc+1));
- int i, result;
- for (i = 0; i < argc; i++) {
- argv[i] = (*env)->GetStringUTFChars(env, (*env)->GetObjectArrayElement(env, argument, i), NULL);
- LOGI("argv[%d] = %s", i, argv[i]);
- }
- argv[argc] = NULL;
+void android_main(struct android_app* state)
+{
+ struct engine engine;
- int (*fp)(int, const char **) = function;
+ LOGI("here we are %s:%d", __FUNCTION__, __LINE__);
- result = fp(argc, argv);
+ app = state;
- for (i = 0; i < argc; i++)
- (*env)->ReleaseStringUTFChars(env, (*env)->GetObjectArrayElement(env, argument, i), argv[i]);
+ memset(&engine, 0, sizeof(engine));
+ state->userData = &engine;
+ state->onAppCmd = engine_handle_cmd;
- free(argv);
- return result;
- }
+ char cwd[1000];
+ getcwd(cwd, sizeof(cwd));
+ LOGI("cwd=%s", cwd);
- /* To be implemented */
- return 0;
+ // lo_main(lo_main_argc, lo_main_argv);
+
+ // loop waiting for stuff to do.
+
+ while (1) {
+ // Read all pending events.
+ int ident;
+ int events;
+ struct android_poll_source* source;
+
+ while ((ident=ALooper_pollAll(-1, NULL, &events,
+ (void**)&source)) >= 0) {
+ LOGI("got an event ident=%d", ident);
+
+ // Process this event.
+ if (source != NULL) {
+ source->process(state, source);
+ }
+
+ // Check if we are exiting.
+ if (state->destroyRequested != 0) {
+ return;
+ }
+ }
+ }
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sal/osl/android/project.properties b/sal/osl/android/project.properties
index 5a7094538fde..730e911f2f9e 100644
--- a/sal/osl/android/project.properties
+++ b/sal/osl/android/project.properties
@@ -8,4 +8,4 @@
# project structure.
# Project target.
-target=android-7
+target=android-14
diff --git a/sal/osl/android/src/org/libreoffice/android/Bootstrap.java b/sal/osl/android/src/org/libreoffice/android/Bootstrap.java
index 5ba969ad41e3..fe65e0a8e875 100644
--- a/sal/osl/android/src/org/libreoffice/android/Bootstrap.java
+++ b/sal/osl/android/src/org/libreoffice/android/Bootstrap.java
@@ -28,96 +28,43 @@
package org.libreoffice.android;
-import android.app.Activity;
+import android.app.NativeActivity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
-import java.io.File;
-import java.util.HashMap;
+// We override NativeActivity so that we can get at the intent of the
+// activity and its extra parameters, that we use to tell us what
+// actual LibreOffice "program" to run. I.e. something that on desktop
+// OSes would be a program, but for Androis is actually built as a
+// shared object, with an "lo_main" function.
-public class Bootstrap extends Activity
+public class Bootstrap extends NativeActivity
{
private static String TAG = "lo-bootstrap";
- private String dataDir;
- // A native method to list the DT_NEEDED names in a ELF shared object
- public static native String[] dlneeds(String library);
+ public native boolean setup(String dataDir);
- // A native method to call dlopen(library, RTLD_LOCAL)
+ public native boolean setup(int lo_main_ptr,
+ Object lo_main_argument);
+
+ // This is not just a wrapper for the C library dlopen(), but also
+ // loads recursively dependent libraries.
public static native int dlopen(String library);
- // A native method to call dlsym(handle, symbol)
+ // This is just a wrapper for the C library dlsym().
public static native int dlsym(int handle, String symbol);
- // A native method to call (*function)(argument)
- public static native int dlcall(int function, Object argument);
-
- // Already loaded libraries
- private HashMap<String, Integer> presentLibs = new HashMap<String, Integer>();
-
- private int loadLibrary(String library)
- {
- // We should *not* try to just dlopen() the bare library name
- // first, as the stupid dynamic linker remembers for each
- // library basename if loading it has failed. Thus if you try
- // loading it once, and it fails because of missing needed
- // libraries, and your load those, and then try again, it
- // fails with an infurtating message "failed to load
- // previously" in the log.
-
- // We *must* first dlopen() all needed libraries,
- // recursively. It shouldn't matter if we dlopen() a library
- // that already is loaded, dlopen() just returns the same
- // value then.
-
- Integer handle;
-
- if ((handle = presentLibs.get(library)) != null)
- return handle;
-
- String fullName = null;
- boolean found = false;
- String[] libraryLocations = { dataDir + "/lib/", "/system/lib/" };
- for (String dir : libraryLocations ) {
- fullName = dir + library;
- if (new File(fullName).exists()) {
- found = true;
- break;
- }
- }
- if (!found) {
- Log.i(TAG, String.format("Library not found: %s\n", library));
- return 0;
- }
-
- String[] needs = dlneeds(fullName);
- if (needs == null)
- return 0;
-
- for (String neededLibrary : needs) {
- if (loadLibrary(neededLibrary) == 0)
- return 0;
- }
- if ((handle = dlopen(fullName)) == 0)
- return 0;
-
- presentLibs.put(library, handle);
- return handle;
- }
-
- /** Called when the activity is first created. */
@Override
- public void onCreate(Bundle savedInstanceState)
+ protected void onCreate(Bundle savedInstanceState)
{
- super.onCreate(savedInstanceState);
+ String dataDir = null;
try {
ApplicationInfo ai = this.getPackageManager().getApplicationInfo
("org.libreoffice.android",
PackageManager.GET_META_DATA);
- Log.i(TAG, String.format("sourceDir=%s\n", ai.sourceDir));
dataDir = ai.dataDir;
Log.i(TAG, String.format("dataDir=%s\n", dataDir));
}
@@ -125,39 +72,62 @@ public class Bootstrap extends Activity
return;
}
+ // This inspects LD_LIBRARY_PATH and dataDir
+ if (!setup(dataDir))
+ return;
+
String mainLibrary = getIntent().getStringExtra("lo-main-library");
if (mainLibrary == null)
mainLibrary = "libcppunittester";
- if (mainLibrary != null) {
- int loLib = loadLibrary(mainLibrary + ".so");
+ mainLibrary += ".so";
+
+ Log.i(TAG, String.format("mainLibrary=%s", mainLibrary));
+
+ // Get "command line" to pass to the LO "program"
+ String cmdLine = getIntent().getStringExtra("lo-main-cmdline");
+
+ if (cmdLine == null)
+ cmdLine = "cppunittester /data/data/org.libreoffice.android/lib/libqa_sal_types.so";
- if (loLib == 0)
- return;
+ Log.i(TAG, String.format("cmdLine=%s", cmdLine));
- // Get "command line" to pass to the LO "program"
- String cmdLine = getIntent().getStringExtra("lo-main-cmdline");
+ String[] argv = cmdLine.split(" ");
- if (cmdLine == null)
- cmdLine = "cppunittester /data/data/org.libreoffice.android/lib/libqa_rtl_strings.so";
+ // Load the LO "program" here and look up lo_main
+ int loLib = dlopen(mainLibrary);
- String[] argv;
- if (cmdLine != null)
- argv = cmdLine.split(" ");
- else
- argv = new String[0];
- int loLibMain = dlsym(loLib, "lo_main");
- if (loLibMain != 0)
- dlcall(loLibMain, argv);
+ if (loLib == 0) {
+ Log.i(TAG, String.format("Could not load %s", mainLibrary));
+ return;
}
+
+ int lo_main = dlsym(loLib, "lo_main");
+ if (lo_main == 0) {
+ Log.i(TAG, String.format("No lo_main in %s", mainLibrary));
+ return;
+ }
+
+ // This saves lo_main and argv
+ if (!setup(lo_main, argv))
+ return;
+
+ // Finally, call our super-class, NativeActivity's onCreate(),
+ // which eventually calls the ANativeActivity_onCreate() in
+ // android_native_app_glue.c, which starts a thread in which
+ // android_main() from lo-bootstrap.c is called.
+
+ // android_main() calls the lo_main() defined in sal/main.h
+ // through the function pointer passed to setup() above, with
+ // the argc and argv also saved from the setup() call.
+ super.onCreate(savedInstanceState);
}
- /* This is used to load the 'lo-bootstrap' library on application
- * startup. The library has already been unpacked into
- * /data/data/<app name>/lib/liblo-bootstrap.so at
- * installation time by the package manager.
- */
+ // This is used to load the 'lo-bootstrap' library on application
+ // startup. The library has already been unpacked into
+ // /data/data/<app name>/lib/liblo-bootstrap.so at installation
+ // time by the package manager.
static {
System.loadLibrary("lo-bootstrap");
}