summaryrefslogtreecommitdiff
path: root/sal
diff options
context:
space:
mode:
authorTor Lillqvist <tlillqvist@suse.com>2011-11-19 02:28:06 +0200
committerTor Lillqvist <tlillqvist@suse.com>2011-11-19 02:55:12 +0200
commit2ad14b0e0380c390f09256b3f4f70f733e310df2 (patch)
tree582405a21b9173cbfd83b7d6bd1d85d48ffd00dd /sal
parent79d0853239b7b8bd4fa2de5d8e1917343b27f8d1 (diff)
More misc Android work
Add possibility to start strace tracing the process. Unfortunately it this doesn't seem to work as nicely as one might have hoped. If the process crashes, the last strace output does not show up. Some buffering that gets abruptly discarded when the straced process dies? Add a function to the native code to look up an archive member in the .apk and return a pointer to it. To be used for non-compressed resources only. We mmap the whole .apk. The Zip format parsing code is borrrowed from Mozilla's APKOpen.cpp. Correspondingly, add to the local build.xml a re-definition of the "-package-resources" target from Ant's build.xml modified to not compress resources. Improved the Makefile a lot. New target "install" to build the apk and install it without constructing the apk twice. Other minor changes here and there.
Diffstat (limited to 'sal')
-rw-r--r--sal/osl/android/Makefile73
-rw-r--r--sal/osl/android/build.xml29
-rw-r--r--sal/osl/android/jni/lo-bootstrap.c240
-rw-r--r--sal/osl/android/jni/lo-bootstrap.h3
-rw-r--r--sal/osl/android/src/org/libreoffice/android/Bootstrap.java38
5 files changed, 333 insertions, 50 deletions
diff --git a/sal/osl/android/Makefile b/sal/osl/android/Makefile
index d60618ab34b3..a607d9346c4d 100644
--- a/sal/osl/android/Makefile
+++ b/sal/osl/android/Makefile
@@ -2,34 +2,60 @@ NDK_HOME:=$(shell type -p ndk-build)
NDK_HOME:=$(shell dirname $(NDK_HOME))
SODEST=libs/armeabi-v7a
+OBJLOCAL=obj/local/armeabi-v7a
-all:
+define COPY
+cp $(1) $(SODEST)$(if $(2),/$(2)) && \
+arm-linux-androideabi-strip --strip-debug $(SODEST)$(if $(2),/$(2),/$(notdir $(1))) && \
+cp $(1) $(OBJLOCAL)$(if $(2),/$(2))
+endef
+
+define CONDCOPY
+test -f $(1) && $(call COPY,$(1),$(2))
+endef
+
+# The default target just builds
+all: ndk-build
+ unset JAVA_HOME && ant debug
+ @echo 'Install it on the device with ant debug install'
+ @echo 'Then run it with something like what "make run" does (see Makefile)'
+
+ndk-build:
ndk-build V=1
#
# Copy shared libraries we need to libs/armeabi-v7a so that ant will
# include them in the .apk.
-# First ones from here, sal
- cp ../../$(INPATH)/bin/cppunittester $(SODEST)/libcppunittester.so
#
-# Then the cppunit library
- cp $(OUTDIR)/lib/libcppunit-1.12.so $(SODEST)
+# Copy them to obj/local/armeabi-v7a, too, where gdb will look for
+# them.
+#
+# First the cppunittester "program" from here, which as all "program"
+# files we build for Android actually is a shared object.
+ $(call COPY,../../$(INPATH)/bin/cppunittester,libcppunittester.so)
#
-# Then cppunit "plug-ins", first ones from sal
+# The cppunit library
+ $(call COPY,$(OUTDIR)/lib/libcppunit-1.12.so)
#
- cp ../../$(INPATH)/lib/*.so $(SODEST)
+# cppunit "plug-ins", first ones from sal
#
-# Then ones from other modules. Note that depending on when you try
+ $(call COPY,../../$(INPATH)/lib/*.so)
+#
+# and ones from other modules. Note that depending on when you try
# this, these might not have been built yet.
#
-for F in $(SRC_ROOT)/cppu/$(INPATH)/lib/qa_*.so; do \
- test -f $${F} && cp $${F} $(SODEST); \
+ $(call CONDCOPY,$${F},`basename $${F}`); \
done
#
-for F in i18npool_test_breakiterator; do \
- test -f $(WORKDIR)/LinkTarget/CppunitTest/libtest_$${F}.so && cp $(WORKDIR)/LinkTarget/CppunitTest/libtest_$${F}.so $(SODEST); \
+ $(call CONDCOPY,$(WORKDIR)/LinkTarget/CppunitTest/libtest_$${F}.so); \
done
+
#
-# Then libs and UNO components that the tests from other modules need.
+# Other "programs"
+ $(call COPY,$(OUTDIR)/bin/uno,libunoexe.so)
+#
+# Libs and UNO components that the tests from other modules need.
#
-for F in gcc3_uno \
reg \
@@ -37,31 +63,22 @@ all:
uno_cppu \
uno_salhelpergcc3 \
uno_cppuhelpergcc3 \
+ unoexceptionprotector \
+ xml2 \
xmlreader \
bootstrap.uno; do \
- test -f $(OUTDIR)/lib/lib$${F}.so && cp $(OUTDIR)/lib/lib$${F}.so $(SODEST); \
+ $(call CONDCOPY,$(OUTDIR)/lib/lib$${F}.so); \
done
#
# Then the shared GNU C++ library
- cp $(NDK_HOME)/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/libgnustl_shared.so $(SODEST)
-#
-# Copy them to obj/local/armeabi-v7a, too, where gdb will look for
-# them. Not sure if this is useful or not; I have great problems with
-# ndk-gdb. Actually, commenting out this part for now...
-#
-# cp ../../$(INPATH)/bin/cppunittester obj/local/armeabi-v7a/libcppunittester.so
-# cp $(OUTPATH)/lib/libcppunit-1.12.so obj/local/armeabi-v7a
-# cp ../../$(INPATH)/lib/*.so obj/local/armeabi-v7a
-# cp $(NDK_HOME)/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/libgnustl_shared.so obj/local/armeabi-v7a
- unset JAVA_HOME && ant debug
- @echo 'Install it on the device with ant debug install'
- @echo 'Then run it with something like what "make run" does (see Makefile)'
+ $(call COPY,$(NDK_HOME)/sources/cxx-stl/gnu-libstdc++/libs/armeabi-v7a/libgnustl_shared.so)
-run: all
+install: ndk-build
unset JAVA_HOME && ant debug install
-#
+
+run: install
# Note: this is of course just an example. The full path the the test
# .so needs to be supplied, unfortunately, I guess cppunittester
# checks its existance using the pathname instead of just
# osl_loadModule'ing it.
- 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"
+ adb shell am start -n org.libreoffice.android/.Bootstrap -e lo-main-library libcppunittester -e lo-main-cmdline "/data/data/org.libreoffice.android/lib/libqa_sal_types.so"
diff --git a/sal/osl/android/build.xml b/sal/osl/android/build.xml
index a186d8d62060..6b091c49c2bd 100644
--- a/sal/osl/android/build.xml
+++ b/sal/osl/android/build.xml
@@ -82,4 +82,33 @@
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
+ <!-- Re-define the "-package-resources" target to not compress resources -->
+
+ <target name="-package-resources" depends="-crunch">
+ <!-- only package resources if *not* a library project -->
+ <do-only-if-not-library elseText="Library project: do not package resources..." >
+ <aapt executable="${aapt}"
+ command="package"
+ versioncode="${version.code}"
+ versionname="${version.name}"
+ debug="${build.is.packaging.debug}"
+ manifest="AndroidManifest.xml"
+ assets="${asset.absolute.dir}"
+ androidjar="${android.jar}"
+ apkfolder="${out.absolute.dir}"
+ nocrunch="${build.packaging.nocrunch}"
+ resourcefilename="${resource.package.file.name}"
+ resourcefilter="${aapt.resource.filter}"
+ projectLibrariesResName="project.libraries.res"
+ projectLibrariesPackageName="project.libraries.package"
+ previousBuildType="${build.last.target}"
+ buildType="${build.target}">
+ <res path="${out.res.absolute.dir}" />
+ <res path="${resource.absolute.dir}" />
+ <nocompress /> <!-- forces no compression on any files in assets or res/raw -->
+ <!-- <nocompress extension="xml" /> forces no compression on specific file extensions in assets and res/raw -->
+ </aapt>
+ </do-only-if-not-library>
+ </target>
+
</project>
diff --git a/sal/osl/android/jni/lo-bootstrap.c b/sal/osl/android/jni/lo-bootstrap.c
index 04540a947b53..0ddbe3f87974 100644
--- a/sal/osl/android/jni/lo-bootstrap.c
+++ b/sal/osl/android/jni/lo-bootstrap.c
@@ -16,6 +16,9 @@
* Copyright (C) 2011 Tor Lillqvist <tml@iki.fi> (initial developer)
* Copyright (C) 2011 SUSE Linux http://suse.com (initial developer's employer)
*
+ * Zip parsing code lifted from Mozilla's other-licenses/android/APKOpen.cpp,
+ * by Michael Wu <mwu@mozilla.com>.
+ *
* All Rights Reserved.
*
* For minor contributions see the git repository.
@@ -35,6 +38,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <dlfcn.h>
+#include <sys/mman.h>
#include <jni.h>
@@ -57,11 +61,68 @@ struct engine {
};
static struct android_app *app;
-static JNIEnv *jni_env;
static const char **library_locations;
+static void *apk_file;
+static int apk_file_size;
static int (*lo_main)(int, const char **);
static int lo_main_argc;
static const char **lo_main_argv;
+static int sleep_time = 0;
+
+/* compression methods */
+#define STORE 0
+#define DEFLATE 8
+#define LZMA 14
+
+struct local_file_header {
+ uint32_t signature;
+ uint16_t min_version;
+ uint16_t general_flag;
+ uint16_t compression;
+ uint16_t lastmod_time;
+ uint16_t lastmod_date;
+ uint32_t crc32;
+ uint32_t compressed_size;
+ uint32_t uncompressed_size;
+ uint16_t filename_size;
+ uint16_t extra_field_size;
+ char data[0];
+} __attribute__((__packed__));
+
+struct cdir_entry {
+ uint32_t signature;
+ uint16_t creator_version;
+ uint16_t min_version;
+ uint16_t general_flag;
+ uint16_t compression;
+ uint16_t lastmod_time;
+ uint16_t lastmod_date;
+ uint32_t crc32;
+ uint32_t compressed_size;
+ uint32_t uncompressed_size;
+ uint16_t filename_size;
+ uint16_t extra_field_size;
+ uint16_t file_comment_size;
+ uint16_t disk_num;
+ uint16_t internal_attr;
+ uint32_t external_attr;
+ uint32_t offset;
+ char data[0];
+} __attribute__((__packed__));
+
+#define CDIR_END_SIG 0x06054b50
+
+struct cdir_end {
+ uint32_t signature;
+ uint16_t disk_num;
+ uint16_t cdir_disk;
+ uint16_t disk_entries;
+ uint16_t cdir_entries;
+ uint32_t cdir_size;
+ uint32_t cdir_offset;
+ uint16_t comment_size;
+ char comment[0];
+} __attribute__((__packed__));
static void
engine_handle_cmd(struct android_app* app,
@@ -225,16 +286,21 @@ Java_org_libreoffice_android_Bootstrap_dlcall(JNIEnv* env,
}
// public native boolean setup(String dataDir,
+// String apkFile,
// String[] ld_library_path);
jboolean
-Java_org_libreoffice_android_Bootstrap_setup__Ljava_lang_String_2_3Ljava_lang_String_2(JNIEnv* env,
- jobject this,
- jstring dataDir,
- jobjectArray ld_library_path)
+Java_org_libreoffice_android_Bootstrap_setup__Ljava_lang_String_2Ljava_lang_String_2_3Ljava_lang_String_2
+ (JNIEnv* env,
+ jobject this,
+ jstring dataDir,
+ jstring apkFile,
+ jobjectArray ld_library_path)
{
- int i, n;
+ struct stat st;
+ int i, n, fd;
const jbyte *dataDirPath;
+ const jbyte *apkFilePath;
char *lib_dir;
n = (*env)->GetArrayLength(env, ld_library_path);
@@ -262,17 +328,45 @@ Java_org_libreoffice_android_Bootstrap_setup__Ljava_lang_String_2_3Ljava_lang_St
for (n = 0; library_locations[n] != NULL; n++)
LOGI("library_locations[%d] = %s", n, library_locations[n]);
+ apkFilePath = (*env)->GetStringUTFChars(env, apkFile, NULL);
+
+ fd = open(apkFilePath, O_RDONLY);
+ if (fd == -1) {
+ LOGI("Could not open %s", apkFilePath);
+ (*env)->ReleaseStringUTFChars(env, apkFile, apkFilePath);
+ return JNI_FALSE;
+ }
+ if (fstat(fd, &st) == -1) {
+ LOGI("Could not fstat %s", apkFilePath);
+ close(fd);
+ (*env)->ReleaseStringUTFChars(env, apkFile, apkFilePath);
+ return JNI_FALSE;
+ }
+ apk_file = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+ close(fd);
+
+ if (apk_file == MAP_FAILED) {
+ LOGI("Could not mmap %s", apkFilePath);
+ (*env)->ReleaseStringUTFChars(env, apkFile, apkFilePath);
+ return JNI_FALSE;
+ }
+ apk_file_size = st.st_size;
+
+ (*env)->ReleaseStringUTFChars(env, apkFile, apkFilePath);
+
return JNI_TRUE;
}
// public native boolean setup(int lo_main_ptr,
-// Object lo_main_argument);
+// Object lo_main_argument,
+// int lo_main_delay);
jboolean
-Java_org_libreoffice_android_Bootstrap_setup__ILjava_lang_Object_2(JNIEnv* env,
- jobject this,
- void *lo_main_ptr,
- jobject lo_main_argument)
+Java_org_libreoffice_android_Bootstrap_setup__ILjava_lang_Object_2I(JNIEnv* env,
+ jobject this,
+ void *lo_main_ptr,
+ jobject lo_main_argument,
+ jint lo_main_delay)
{
jclass StringArray;
int i;
@@ -301,9 +395,37 @@ Java_org_libreoffice_android_Bootstrap_setup__ILjava_lang_Object_2(JNIEnv* env,
}
lo_main_argv[lo_main_argc] = NULL;
+ sleep_time = lo_main_delay;
+
return JNI_TRUE;
}
+// public static native int getpid();
+
+jint
+Java_org_libreoffice_android_Bootstrap_getpid(JNIEnv* env,
+ jobject clazz)
+{
+ return getpid();
+}
+
+
+// public static native void system(String cmdline);
+
+jint
+Java_org_libreoffice_android_Bootstrap_system(JNIEnv* env,
+ jobject clazz,
+ jstring cmdline)
+{
+ const jbyte *s = (*env)->GetStringUTFChars(env, cmdline, NULL);
+
+ LOGI("system(%s)", s);
+
+ system(s);
+
+ (*env)->ReleaseStringUTFChars(env, cmdline, s);
+}
+
char **
lo_dlneeds(const char *library)
{
@@ -534,6 +656,7 @@ lo_dlopen(const char *library)
return NULL;
}
}
+ free_ptrarray((void **) needed);
p = dlopen(full_name, RTLD_LOCAL);
LOGI("dlopen(%s) = %p", full_name, p);
@@ -569,14 +692,10 @@ lo_dladdr(void *addr,
FILE *maps;
char line[200];
int result;
+ int found;
result = dladdr(addr, info);
- if (result != 0)
- LOGI("dladdr(%p) = { %s:%p, %s:%p ]",
- addr,
- info->dli_fname, info->dli_fbase,
- info->dli_sname ? info->dli_sname : "(none)", info->dli_saddr);
- else {
+ if (result == 0) {
LOGI("dladdr(%p) = 0", addr);
return 0;
}
@@ -586,6 +705,8 @@ lo_dladdr(void *addr,
LOGI("lo_dladdr: Could not open /proc/self/maps: %s", strerror(errno));
return 0;
}
+
+ found = 0;
while (fgets(line, sizeof(line), maps) != NULL &&
line[strlen(line)-1] == '\n') {
void *lo, *hi;
@@ -599,16 +720,93 @@ lo_dladdr(void *addr,
fclose(maps);
return 0;
}
+ LOGI("dladdr(%p) = { %s:%p, %s:%p }: %s",
+ addr,
+ info->dli_fname, info->dli_fbase,
+ info->dli_sname ? info->dli_sname : "(none)", info->dli_saddr,
+ file);
info->dli_fname = strdup(file);
+ found = 1;
break;
}
}
}
+ if (!found)
+ LOGI("lo_dladdr: Did not find %p in /proc/self/maps", addr);
fclose(maps);
return result;
}
+static uint32_t cdir_entry_size (struct cdir_entry *entry)
+{
+ return sizeof(*entry) +
+ letoh16(entry->filename_size) +
+ letoh16(entry->extra_field_size) +
+ letoh16(entry->file_comment_size);
+}
+
+static struct cdir_entry *
+find_cdir_entry (struct cdir_entry *entry, int count, const char *name)
+{
+ size_t name_size = strlen(name);
+ while (count--) {
+ if (letoh16(entry->filename_size) == name_size &&
+ !memcmp(entry->data, name, name_size))
+ return entry;
+ entry = (struct cdir_entry *)((char *)entry + cdir_entry_size(entry));
+ }
+ return NULL;
+}
+
+void *
+lo_apkentry(const char *filename,
+ size_t *size)
+{
+ struct cdir_end *dirend = (struct cdir_end *)((char *) apk_file + apk_file_size - sizeof(*dirend));
+ uint32_t cdir_offset;
+ uint16_t cdir_entries;
+ struct cdir_entry *cdir_start;
+ struct cdir_entry *entry;
+ struct local_file_header *file;
+ void *data;
+
+ while ((void *)dirend > apk_file &&
+ letoh32(dirend->signature) != CDIR_END_SIG)
+ dirend = (struct cdir_end *)((char *)dirend - 1);
+ if (letoh32(dirend->signature) != CDIR_END_SIG) {
+ LOGI("lo_apkentry: Could not find end of central directory record");
+ return;
+ }
+
+ cdir_offset = letoh32(dirend->cdir_offset);
+ cdir_entries = letoh16(dirend->cdir_entries);
+ cdir_start = (struct cdir_entry *)((char *)apk_file + cdir_offset);
+
+ if (*filename == '/')
+ filename++;
+
+ entry = find_cdir_entry(cdir_start, cdir_entries, filename);
+
+ if (entry == NULL) {
+ LOGI("lo_apkentry: Could not find %s", filename);
+ return NULL;
+ }
+ file = (struct local_file_header *)((char *)apk_file + letoh32(entry->offset));
+
+ if (letoh16(file->compression) != STORE) {
+ LOGI("lo_apkentry: File %s is compressed", filename);
+ return NULL;
+ }
+
+ data = ((char *)&file->data) + letoh16(file->filename_size) + letoh16(file->extra_field_size);
+ *size = file->uncompressed_size;
+
+ LOGI("lo_apkentry(%s): %p, %d", filename, data, *size);
+
+ return data;
+}
+
int
lo_dlcall_argc_argv(void *function,
int argc,
@@ -623,6 +821,7 @@ lo_dlcall_argc_argv(void *function,
void android_main(struct android_app* state)
{
struct engine engine;
+ Dl_info lo_main_info;
app = state;
@@ -630,6 +829,13 @@ void android_main(struct android_app* state)
state->userData = &engine;
state->onAppCmd = engine_handle_cmd;
+ if (lo_dladdr(lo_main, &lo_main_info) != 0) {
+ lo_main_argv[0] = lo_main_info.dli_fname;
+ }
+
+ if (sleep_time != 0)
+ sleep(sleep_time);
+
lo_main(lo_main_argc, lo_main_argv);
exit(0);
diff --git a/sal/osl/android/jni/lo-bootstrap.h b/sal/osl/android/jni/lo-bootstrap.h
index 523ba991c935..c01ae3c40523 100644
--- a/sal/osl/android/jni/lo-bootstrap.h
+++ b/sal/osl/android/jni/lo-bootstrap.h
@@ -42,6 +42,9 @@ void *lo_dlsym(void *handle,
int lo_dladdr(void *addr,
Dl_info *info);
+void *lo_apkentry(const char *filename,
+ size_t *size);
+
int lo_dlcall_argc_argv(void *function,
int argc,
const char **argv);
diff --git a/sal/osl/android/src/org/libreoffice/android/Bootstrap.java b/sal/osl/android/src/org/libreoffice/android/Bootstrap.java
index 5e705435b1e1..505b72e692e4 100644
--- a/sal/osl/android/src/org/libreoffice/android/Bootstrap.java
+++ b/sal/osl/android/src/org/libreoffice/android/Bootstrap.java
@@ -45,10 +45,12 @@ public class Bootstrap extends NativeActivity
private static String TAG = "lo-bootstrap";
public native boolean setup(String dataDir,
+ String apkFile,
String[] ld_library_path);
public native boolean setup(int lo_main_ptr,
- Object lo_main_argument);
+ Object lo_main_argument,
+ int lo_main_delay);
// This is not just a wrapper for the C library dlopen(), but also
// loads recursively dependent libraries.
@@ -57,6 +59,12 @@ public class Bootstrap extends NativeActivity
// This is just a wrapper for the C library dlsym().
public static native int dlsym(int handle, String symbol);
+ // Wrapper for getpid()
+ public static native int getpid();
+
+ // Wrapper for system()
+ public static native void system(String cmdline);
+
@Override
protected void onCreate(Bundle savedInstanceState)
{
@@ -79,7 +87,7 @@ public class Bootstrap extends NativeActivity
String[] llpa = llp.split(":");
- if (!setup(dataDir, llpa))
+ if (!setup(dataDir, getApplication().getPackageResourcePath(), llpa))
return;
String mainLibrary = getIntent().getStringExtra("lo-main-library");
@@ -95,12 +103,22 @@ public class Bootstrap extends NativeActivity
String cmdLine = getIntent().getStringExtra("lo-main-cmdline");
if (cmdLine == null)
- cmdLine = "cppunittester /data/data/org.libreoffice.android/lib/libqa_sal_types.so";
+ cmdLine = "/data/data/org.libreoffice.android/lib/libqa_sal_types.so";
+
+ // argv[0] will be replaced by android_main() in lo-bootstrap.c by the
+ // pathname of the mainLibrary.
+ cmdLine = "dummy-program-name " + cmdLine;
Log.i(TAG, String.format("cmdLine=%s", cmdLine));
String[] argv = cmdLine.split(" ");
+ // As we don't do any shell style quote handling, to enable
+ // having spaces in argv elements, they need to be entered as
+ // '~' characters which we here change into spaces...
+ for (int i = 0; i < argv.length; i++)
+ argv[i] = argv[i].replace('~', ' ');
+
// Load the LO "program" here and look up lo_main
int loLib = dlopen(mainLibrary);
@@ -115,8 +133,18 @@ public class Bootstrap extends NativeActivity
return;
}
- // This saves lo_main and argv
- if (!setup(lo_main, argv))
+ // Tell lo-bootstrap to Start a strace on itself if requested
+ String strace_args = getIntent().getStringExtra("lo-strace");
+ if (strace_args != null)
+ system("/system/xbin/strace -p " + getpid() + " " + (strace_args != "yes" ? strace_args : "" ) + " &");
+
+ int delay = 0;
+ String sdelay = getIntent().getStringExtra("lo-main-delay");
+ if (sdelay != null)
+ delay = Integer.parseInt(sdelay);
+
+ // Tell lo-bootstrap.c the stuff it needs to know
+ if (!setup(lo_main, argv, delay))
return;
// Finally, call our super-class, NativeActivity's onCreate(),