Bug 588607 - 1. Add support for reading libraries out of the apk, r=taras a=blocking-fennec
authorMichael Wu <mwu@mozilla.com>
Fri, 15 Oct 2010 11:27:57 -0700
changeset 55916 266535ecad798107ec63757e3cb21447ddb92fd0
parent 55915 6277ca1ac576047a16bcba7b75c050d89b8839b0
child 55917 a6b6ebdd29a281841b5540ebc6802e3a641c6bf5
push idunknown
push userunknown
push dateunknown
reviewerstaras, blocking-fennec
bugs588607
milestone2.0b8pre
Bug 588607 - 1. Add support for reading libraries out of the apk, r=taras a=blocking-fennec
embedding/android/utils/Makefile.in
embedding/android/utils/nsGeckoUtils.cpp
other-licenses/android/APKOpen.cpp
other-licenses/android/Makefile.in
other-licenses/android/debugger.c
other-licenses/android/dlfcn.c
other-licenses/android/dlfcn.h
other-licenses/android/linker.c
other-licenses/android/linker.h
other-licenses/android/nsGeckoUtils.cpp
deleted file mode 100644
--- a/embedding/android/utils/Makefile.in
+++ /dev/null
@@ -1,50 +0,0 @@
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is the Mozilla browser.
-#
-# The Initial Developer of the Original Code is
-#   Mozilla Foundation
-# Portions created by the Initial Developer are Copyright (C) 2010
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#   Brad Lassey <blassey@mozilla.com>
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either the GNU General Public License Version 2 or later (the "GPL"), or
-# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-DEPTH		= ../../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-MODULE         = mozutils
-LIBRARY_NAME   = mozutils
-FORCE_SHARED_LIB = 1
-
-CPPSRCS = nsGeckoUtils.cpp
-
-include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/embedding/android/utils/nsGeckoUtils.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Android code.
- *
- * The Initial Developer of the Original Code is Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Brad Lassey <blassey@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include <jni.h>
-#include <stdlib.h>
-
-extern "C" {
-  void JNICALL Java_org_mozilla_gecko_GeckoAppShell_putenv(JNIEnv *jenv, jclass, jstring map);
-}
-
-__attribute__ ((visibility("default")))
-void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_putenv(JNIEnv *jenv, jclass, jstring map)
-{
-    const char* str;
-    // XXX: java doesn't give us true UTF8, we should figure out something 
-    // better to do here
-    str = jenv->GetStringUTFChars(map, NULL);
-    if (str == NULL)
-        return;
-    putenv(strdup(str));
-    jenv->ReleaseStringUTFChars(map, str);
-}
-
new file mode 100644
--- /dev/null
+++ b/other-licenses/android/APKOpen.cpp
@@ -0,0 +1,518 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Michael Wu <mwu@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <jni.h>
+#include <android/log.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <endian.h>
+#include <unistd.h>
+#include <zlib.h>
+#include "dlfcn.h"
+
+/* 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 size_t zip_size;
+static int zip_fd;
+
+static void * map_file (const char *file)
+{
+  int fd = open(file, O_RDONLY);
+  if (fd == -1) {
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoMapFile", "map_file open %s", strerror(errno));
+    return NULL;
+  }
+
+  zip_fd = fd;
+  struct stat s;
+  if (fstat(fd, &s) == -1) {
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoMapFile", "map_file fstat %s", strerror(errno));
+    return NULL;
+  }
+
+  zip_size = s.st_size;
+  void *addr = mmap(NULL, zip_size, PROT_READ, MAP_SHARED, fd, 0);
+  if (addr == MAP_FAILED) {
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoMapFile", "map_file mmap %s", strerror(errno));
+    return NULL;
+  }
+
+  return addr;
+}
+
+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 *)((void *)entry + cdir_entry_size(entry));
+  }
+  return NULL;
+}
+
+static uint32_t simple_write(int fd, const void *buf, uint32_t count)
+{
+  uint32_t out_offset = 0;
+  while (out_offset < count) {
+    uint32_t written = write(fd, buf + out_offset,
+                             count - out_offset);
+    if (written == -1) {
+      if (errno == EAGAIN || errno == EWOULDBLOCK)
+        continue;
+      else {
+        __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "simple_write failed");
+        break;
+      }
+    }
+
+    out_offset += written;
+  }
+  return out_offset;
+}
+
+#define NS_EXPORT __attribute__ ((visibility("default")))
+
+#define SHELL_WRAPPER0(name) \
+typedef void (*name ## _t)(JNIEnv *, jclass); \
+static name ## _t f_ ## name; \
+extern "C" NS_EXPORT void JNICALL \
+Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc) \
+{ \
+  f_ ## name(jenv, jc); \
+}
+
+#define SHELL_WRAPPER1(name,type1) \
+typedef void (*name ## _t)(JNIEnv *, jclass, type1 one); \
+static name ## _t f_ ## name; \
+extern "C" NS_EXPORT void JNICALL \
+Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc, type1 one) \
+{ \
+  f_ ## name(jenv, jc, one); \
+}
+
+#define SHELL_WRAPPER2(name,type1,type2) \
+typedef void (*name ## _t)(JNIEnv *, jclass, type1 one, type2 two); \
+static name ## _t f_ ## name; \
+extern "C" NS_EXPORT void JNICALL \
+Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc, type1 one, type2 two) \
+{ \
+  f_ ## name(jenv, jc, one, two); \
+}
+
+#define SHELL_WRAPPER3(name,type1,type2,type3) \
+typedef void (*name ## _t)(JNIEnv *, jclass, type1 one, type2 two, type3 three); \
+static name ## _t f_ ## name; \
+extern "C" NS_EXPORT void JNICALL \
+Java_org_mozilla_gecko_GeckoAppShell_ ## name(JNIEnv *jenv, jclass jc, type1 one, type2 two, type3 three) \
+{ \
+  f_ ## name(jenv, jc, one, two, three); \
+}
+
+SHELL_WRAPPER0(nativeInit)
+SHELL_WRAPPER1(nativeRun, jstring)
+SHELL_WRAPPER1(notifyGeckoOfEvent, jobject)
+SHELL_WRAPPER1(setSurfaceView, jobject)
+SHELL_WRAPPER2(setInitialSize, int, int)
+SHELL_WRAPPER0(onResume)
+SHELL_WRAPPER0(onLowMemory)
+SHELL_WRAPPER3(callObserver, jstring, jstring, jstring)
+SHELL_WRAPPER1(removeObserver, jstring)
+
+static void * xul_handle = NULL;
+static time_t apk_mtime = 0;
+#ifdef DEBUG
+extern "C" int extractLibs = 1;
+#else
+extern "C" int extractLibs = 0;
+#endif
+
+static void
+extractFile(const char * path, const struct cdir_entry *entry, void * data)
+{
+  uint32_t size = letoh32(entry->uncompressed_size);
+
+  struct stat status;
+  if (!stat(path, &status) &&
+      status.st_size == size &&
+      apk_mtime < status.st_mtime)
+    return;
+
+  int fd = open(path, O_CREAT | O_NOATIME | O_TRUNC | O_RDWR, S_IRWXU);
+  if (fd == -1) {
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't open %s to decompress library", path);
+    return;
+  }
+
+  void * buf = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
+                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+  if (buf == (void *)-1) {
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't mmap decompression buffer");
+    return;
+  }
+
+  z_stream strm = {
+    next_in: (Bytef *)data,
+    avail_in: letoh32(entry->compressed_size),
+    total_in: 0,
+
+    next_out: (Bytef *)buf,
+    avail_out: 4096,
+    total_out: 0
+  };
+
+  int ret;
+  ret = inflateInit2(&strm, -MAX_WBITS);
+  if (ret != Z_OK)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflateInit failed: %s", strm.msg);
+
+  while ((ret = inflate(&strm, Z_SYNC_FLUSH)) != Z_STREAM_END) {
+    simple_write(fd, buf, 4096 - strm.avail_out);
+    strm.next_out = (Bytef *)buf;
+    strm.avail_out = 4096;
+  }
+  simple_write(fd, buf, 4096 - strm.avail_out);
+
+  if (ret != Z_STREAM_END)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflate failed: %s", strm.msg);
+
+  if (strm.total_out != size)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "extracted %d, expected %d!", strm.total_out, size);
+
+  ret = inflateEnd(&strm);
+  if (ret != Z_OK)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflateEnd failed: %s", strm.msg);
+
+  close(fd);
+  munmap(buf, 4096);
+}
+
+static void
+extractLib(const struct cdir_entry *entry, void * data, void * dest)
+{
+  z_stream strm = {
+    next_in: (Bytef *)data,
+    avail_in: letoh32(entry->compressed_size),
+    total_in: 0,
+
+    next_out: (Bytef *)dest,
+    avail_out: letoh32(entry->uncompressed_size),
+    total_out: 0
+  };
+
+  int ret;
+  ret = inflateInit2(&strm, -MAX_WBITS);
+  if (ret != Z_OK)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflateInit failed: %s", strm.msg);
+
+  ret = inflate(&strm, Z_SYNC_FLUSH);
+  if (ret != Z_STREAM_END)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflate failed: %s", strm.msg);
+
+  ret = inflateEnd(&strm);
+  if (ret != Z_OK)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "inflateEnd failed: %s", strm.msg);
+
+  if (strm.total_out != letoh32(entry->uncompressed_size))
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "File not fully uncompressed! %d / %d", strm.total_out, letoh32(entry->uncompressed_size));
+}
+
+static void * mozload(const char * path, void *zip,
+                      struct cdir_entry *cdir_start, uint16_t cdir_entries)
+{
+#ifdef DEBUG
+  struct timeval t0, t1;
+  gettimeofday(&t0, 0);
+#endif
+
+  struct cdir_entry *entry = find_cdir_entry(cdir_start, cdir_entries, path);
+  struct local_file_header *file = (struct local_file_header *)(zip + letoh32(entry->offset));
+  void * data = ((void *)&file->data) + letoh16(file->filename_size) + letoh16(file->extra_field_size);
+  void * handle;
+
+  if (extractLibs) {
+    char fullpath[256];
+    snprintf(fullpath, 256, "/data/data/org.mozilla.fennec/%s", path + 4);
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "resolved %s to %s", path, fullpath);
+    extractFile(fullpath, entry, data);
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: 1", fullpath);
+    handle = __wrap_dlopen(fullpath, RTLD_LAZY);
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: 2", fullpath);
+    if (!handle)
+      __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't load %s because %s", fullpath, __wrap_dlerror());
+#ifdef DEBUG
+    gettimeofday(&t1, 0);
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: spent %d", path,
+                        (((long long)t1.tv_sec * 1000000LL) +
+                          (long long)t1.tv_usec) -
+                        (((long long)t0.tv_sec * 1000000LL) +
+                          (long long)t0.tv_usec));
+#endif
+    return handle;
+  }
+
+  size_t offset = letoh32(entry->offset) + sizeof(*file) + letoh16(file->filename_size) + letoh16(file->extra_field_size);
+
+  int fd = zip_fd;
+  void * buf = NULL;
+  if (letoh16(file->compression) == DEFLATE) {
+    fd = -1;
+    buf = mmap(NULL, letoh32(entry->uncompressed_size),
+               PROT_READ | PROT_WRITE | PROT_EXEC,
+               MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+    if (buf == (void *)-1) {
+      __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't mmap decompression buffer");
+      return NULL;
+    }
+
+    offset = 0;
+
+    extractLib(entry, data, buf);
+    data = buf;
+  }
+
+#ifdef DEBUG
+  __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loading %s with len %d and offset %d", path, letoh32(entry->uncompressed_size), offset);
+#endif
+
+  handle = moz_mapped_dlopen(path, RTLD_LAZY, fd, data,
+                             letoh32(entry->uncompressed_size), offset);
+  if (!handle)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't load %s because %s", path, __wrap_dlerror());
+  if (buf)
+    munmap(buf, letoh32(entry->uncompressed_size));
+
+#ifdef DEBUG
+  gettimeofday(&t1, 0);
+  __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "%s: spent %d", path, (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
+               (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec));
+#endif
+
+  return handle;
+}
+
+extern "C" void simple_linker_init(void);
+
+static void
+loadLibs(const char *apkName)
+{
+  simple_linker_init();
+
+  chdir("/data/data/org.mozilla.fennec");
+
+  struct stat status;
+  if (!stat(apkName, &status))
+    apk_mtime = status.st_mtime;
+
+#ifdef DEBUG
+  struct timeval t0, t1;
+  gettimeofday(&t0, 0);
+#endif
+
+  void *zip = map_file(apkName);
+  struct cdir_end *dirend = (struct cdir_end *)(zip + zip_size - sizeof(*dirend));
+  while ((void *)dirend > zip &&
+         letoh32(dirend->signature) != CDIR_END_SIG)
+    dirend = (struct cdir_end *)((void *)dirend - 1);
+  if (letoh32(dirend->signature) != CDIR_END_SIG) {
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't find end of central directory record");
+    return;
+  }
+
+  uint32_t cdir_offset = letoh32(dirend->cdir_offset);
+  uint16_t cdir_entries = letoh16(dirend->cdir_entries);
+
+  struct cdir_entry *cdir_start = (struct cdir_entry *)(zip + cdir_offset);
+
+#define MOZLOAD(name) mozload("lib/lib" name ".so", zip, cdir_start, cdir_entries)
+  MOZLOAD("mozalloc");
+  MOZLOAD("nspr4");
+  MOZLOAD("plc4");
+  MOZLOAD("plds4");
+  MOZLOAD("mozsqlite3");
+  MOZLOAD("nssutil3");
+  MOZLOAD("nss3");
+  MOZLOAD("ssl3");
+  MOZLOAD("smime3");
+  xul_handle = MOZLOAD("xul");
+  MOZLOAD("xpcom");
+  MOZLOAD("nssckbi");
+  MOZLOAD("freebl3");
+  MOZLOAD("softokn3");
+#undef MOZLOAD
+
+  close(zip_fd);
+
+  if (!xul_handle)
+    __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libxul!");
+
+#define GETFUNC(name) f_ ## name = (name ## _t) __wrap_dlsym(xul_handle, "Java_org_mozilla_gecko_GeckoAppShell_" #name)
+  GETFUNC(nativeInit);
+  GETFUNC(nativeRun);
+  GETFUNC(notifyGeckoOfEvent);
+  GETFUNC(setSurfaceView);
+  GETFUNC(setInitialSize);
+  GETFUNC(onResume);
+  GETFUNC(onLowMemory);
+  GETFUNC(callObserver);
+  GETFUNC(removeObserver);
+#undef GETFUNC
+
+#ifdef DEBUG
+  gettimeofday(&t1, 0);
+  __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "spent %d total",
+             (((long long)t1.tv_sec * 1000000LL) + (long long)t1.tv_usec) -
+             (((long long)t0.tv_sec * 1000000LL) + (long long)t0.tv_usec));
+  __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "All libraries loaded!");
+#endif
+}
+
+extern "C" NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_loadLibs(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
+{
+  const char* str;
+  // XXX: java doesn't give us true UTF8, we should figure out something 
+  // better to do here
+  str = jenv->GetStringUTFChars(jApkName, NULL);
+  if (str == NULL)
+    return;
+
+  loadLibs(str);
+  jenv->ReleaseStringUTFChars(jApkName, str);
+}
+
+typedef int GeckoProcessType;
+typedef int nsresult;
+
+extern "C" NS_EXPORT int
+ChildProcessInit(int argc, char* argv[])
+{
+  int i;
+  for (i = 0; i < (argc - 1); i++) {
+    if (strcmp(argv[i], "-omnijar"))
+      continue;
+
+    i = i + 1;
+    break;
+  }
+
+  loadLibs(argv[i]);
+
+  typedef GeckoProcessType (*XRE_StringToChildProcessType_t)(char*);
+  typedef nsresult (*XRE_InitChildProcess_t)(int, char**, GeckoProcessType);
+  XRE_StringToChildProcessType_t fXRE_StringToChildProcessType =
+    (XRE_StringToChildProcessType_t)__wrap_dlsym(xul_handle, "XRE_StringToChildProcessType");
+  XRE_InitChildProcess_t fXRE_InitChildProcess =
+    (XRE_InitChildProcess_t)__wrap_dlsym(xul_handle, "XRE_InitChildProcess");
+
+  GeckoProcessType proctype = fXRE_StringToChildProcessType(argv[--argc]);
+
+  nsresult rv = fXRE_InitChildProcess(argc, argv, proctype);
+  if (rv != 0)
+    return 1;
+
+  return 0;
+}
+
new file mode 100644
--- /dev/null
+++ b/other-licenses/android/Makefile.in
@@ -0,0 +1,77 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Mozilla browser.
+#
+# The Initial Developer of the Original Code is
+#   Mozilla Foundation
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Brad Lassey <blassey@mozilla.com>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+DEPTH		= ../..
+topsrcdir	= @top_srcdir@
+srcdir		= @srcdir@
+VPATH		= @srcdir@
+
+include $(DEPTH)/config/autoconf.mk
+
+MODULE           = mozutils
+LIBRARY_NAME     = mozutils
+FORCE_SHARED_LIB = 1
+DIST_INSTALL     = 1
+
+DEFINES += \
+  -DLINKER_DEBUG=0 \
+  -DANDROID_ARM_LINKER \
+  -DMOZ_LINKER \
+  -DLINKER_TEXT_BASE=0xB0001000 \
+  -DLINKER_AREA_SIZE=0x01000000 \
+  $(NULL)
+
+CPPSRCS = \
+  nsGeckoUtils.cpp \
+  APKOpen.cpp \
+  $(NULL)
+
+CSRCS = \
+  ba.c \
+  debugger.c \
+  dlfcn.c \
+  linker.c \
+  linker_format.c \
+  rt.c \
+  $(NULL)
+
+EXTRA_DSO_LDOPTS += $(ZLIB_LIBS)
+
+WRAP_MALLOC_LIB =
+WRAP_MALLOC_CFLAGS =
+
+include $(topsrcdir)/config/rules.mk
--- a/other-licenses/android/debugger.c
+++ b/other-licenses/android/debugger.c
@@ -32,17 +32,19 @@
 #include <ctype.h>
 #include <signal.h>
 #include <sys/mman.h>
 #include <errno.h>
 
 #include "linker.h"
 
 #include <sys/socket.h>
+#ifndef MOZ_LINKER
 #include <cutils/sockets.h>
+#endif
 
 void notify_gdb_of_libraries();
 
 #define  RETRY_ON_EINTR(ret,cond) \
     do { \
         ret = (cond); \
     } while (ret < 0 && errno == EINTR)
 
@@ -50,18 +52,22 @@ void debugger_signal_handler(int n)
 {
     unsigned tid;
     int s;
 
     /* avoid picking up GC interrupts */
     signal(SIGUSR1, SIG_IGN);
 
     tid = gettid();
+#ifndef MOZ_LINKER
     s = socket_local_client("android:debuggerd",
             ANDROID_SOCKET_NAMESPACE_ABSTRACT, SOCK_STREAM);
+#else
+    s = -1;
+#endif
 
     if(s >= 0) {
         /* debugger knows our pid from the credentials on the
          * local socket but we need to tell it our tid.  It
          * is paranoid and will verify that we are giving a tid
          * that's actually in our process
          */
         int  ret;
--- a/other-licenses/android/dlfcn.c
+++ b/other-licenses/android/dlfcn.c
@@ -8,17 +8,17 @@
  *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <dlfcn.h>
+#include "dlfcn.h"
 #include <pthread.h>
 #include <stdio.h>
 #include "linker.h"
 #include "linker_format.h"
 
 /* This file hijacks the symbols stubbed out in libdl.so. */
 
 #define DL_SUCCESS                    0
@@ -38,48 +38,74 @@ static const char *dl_errors[] = {
     [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found",
     [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global",
 };
 
 #define likely(expr)   __builtin_expect (expr, 1)
 #define unlikely(expr) __builtin_expect (expr, 0)
 
 static pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER;
+extern int extractLibs;
 
 static void set_dlerror(int err)
 {
     format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err],
              linker_get_error());
     dl_err_str = (const char *)&dl_err_buf[0];
-};
+}
 
-void *dlopen(const char *filename, int flag)
+void *__wrap_dlopen(const char *filename, int flag)
 {
+    if (extractLibs)
+        return dlopen(filename, flag);
+
     soinfo *ret;
 
     pthread_mutex_lock(&dl_lock);
     ret = find_library(filename);
     if (unlikely(ret == NULL)) {
         set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
     } else {
         ret->refcount++;
     }
     pthread_mutex_unlock(&dl_lock);
     return ret;
 }
 
-const char *dlerror(void)
+void *moz_mapped_dlopen(const char *filename, int flag,
+                        int fd, void *mem, unsigned int len, unsigned int offset)
 {
+    soinfo *ret;
+
+    pthread_mutex_lock(&dl_lock);
+    ret = find_mapped_library(filename, fd, mem, len, offset);
+    if (unlikely(ret == NULL)) {
+        set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
+    } else {
+        ret->refcount++;
+    }
+    pthread_mutex_unlock(&dl_lock);
+    return ret;
+}
+
+const char *__wrap_dlerror(void)
+{
+    if (extractLibs)
+        return dlerror();
+
     const char *tmp = dl_err_str;
     dl_err_str = NULL;
     return (const char *)tmp;
 }
 
-void *dlsym(void *handle, const char *symbol)
+void *__wrap_dlsym(void *handle, const char *symbol)
 {
+    if (extractLibs)
+        return dlsym(handle, symbol);
+
     soinfo *found;
     Elf32_Sym *sym;
     unsigned bind;
 
     pthread_mutex_lock(&dl_lock);
 
     if(unlikely(handle == 0)) { 
         set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE);
@@ -119,17 +145,17 @@ void *dlsym(void *handle, const char *sy
     else
         set_dlerror(DL_ERR_SYMBOL_NOT_FOUND);
 
 err:
     pthread_mutex_unlock(&dl_lock);
     return 0;
 }
 
-int dladdr(void *addr, Dl_info *info)
+int __wrap_dladdr(void *addr, Dl_info *info)
 {
     int ret = 0;
 
     pthread_mutex_lock(&dl_lock);
 
     /* Determine if this address can be found in any library currently mapped */
     soinfo *si = find_containing_library(addr);
 
@@ -150,93 +176,96 @@ int dladdr(void *addr, Dl_info *info)
         ret = 1;
     }
 
     pthread_mutex_unlock(&dl_lock);
 
     return ret;
 }
 
-int dlclose(void *handle)
+int __wrap_dlclose(void *handle)
 {
+    if (extractLibs)
+        return dlclose(handle);
+
     pthread_mutex_lock(&dl_lock);
     (void)unload_library((soinfo*)handle);
     pthread_mutex_unlock(&dl_lock);
     return 0;
 }
 
 #if defined(ANDROID_ARM_LINKER)
 //                     0000000 00011111 111112 22222222 2333333 333344444444445555555
 //                     0123456 78901234 567890 12345678 9012345 678901234567890123456
 #define ANDROID_LIBDL_STRTAB \
-                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0"
+                      "__wrap_dlopen\0__wrap_dlclose\0__wrap_dlsym\0__wrap_dlerror\0__wrap_dladdr\0dl_unwind_find_exidx\0"
 
 #elif defined(ANDROID_X86_LINKER)
 //                     0000000 00011111 111112 22222222 2333333 3333444444444455
 //                     0123456 78901234 567890 12345678 9012345 6789012345678901
 #define ANDROID_LIBDL_STRTAB \
-                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
+                      "__wrap_dlopen\0__wrap_dlclose\0__wrap_dlsym\0__wrap_dlerror\0__wrap_dladdr\0dl_iterate_phdr\0"
 
 #elif defined(ANDROID_SH_LINKER)
 //                     0000000 00011111 111112 22222222 2333333 3333444444444455
 //                     0123456 78901234 567890 12345678 9012345 6789012345678901
 #define ANDROID_LIBDL_STRTAB \
-                      "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
+                      "__wrap_dlopen\0__wrap_dlclose\0__wrap_dlsym\0__wrap_dlerror\0__wrap_dladdr\0dl_iterate_phdr\0"
 
 #else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */
 #error Unsupported architecture. Only ARM and x86 are presently supported.
 #endif
 
 
 static Elf32_Sym libdl_symtab[] = {
       // total length of libdl_info.strtab, including trailing 0
       // This is actually the the STH_UNDEF entry. Technically, it's
       // supposed to have st_name == 0, but instead, it points to an index
       // in the strtab with a \0 to make iterating through the symtab easier.
     { st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1,
     },
     { st_name: 0,   // starting index of the name in libdl_info.strtab
-      st_value: (Elf32_Addr) &dlopen,
+      st_value: (Elf32_Addr) &__wrap_dlopen,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
-    { st_name: 7,
-      st_value: (Elf32_Addr) &dlclose,
+    { st_name: 14,
+      st_value: (Elf32_Addr) &__wrap_dlclose,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
-    { st_name: 15,
-      st_value: (Elf32_Addr) &dlsym,
+    { st_name: 22,
+      st_value: (Elf32_Addr) &__wrap_dlsym,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
-    { st_name: 21,
-      st_value: (Elf32_Addr) &dlerror,
+    { st_name: 28,
+      st_value: (Elf32_Addr) &__wrap_dlerror,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
-    { st_name: 29,
-      st_value: (Elf32_Addr) &dladdr,
+    { st_name: 36,
+      st_value: (Elf32_Addr) &__wrap_dladdr,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
 #ifdef ANDROID_ARM_LINKER
-    { st_name: 36,
+    { st_name: 43,
       st_value: (Elf32_Addr) &dl_unwind_find_exidx,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
 #elif defined(ANDROID_X86_LINKER)
-    { st_name: 36,
+    { st_name: 43,
       st_value: (Elf32_Addr) &dl_iterate_phdr,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
 #elif defined(ANDROID_SH_LINKER)
-    { st_name: 36,
+    { st_name: 43,
       st_value: (Elf32_Addr) &dl_iterate_phdr,
       st_info: STB_GLOBAL << 4,
       st_shndx: 1,
     },
 #endif
 };
 
 /* Fake out a hash table with a single bucket.
--- a/other-licenses/android/dlfcn.h
+++ b/other-licenses/android/dlfcn.h
@@ -38,16 +38,26 @@ typedef struct {
     void       *dli_fbase;  /* Address at which shared object
                                is loaded */
     const char *dli_sname;  /* Name of nearest symbol with address
                                lower than addr */
     void       *dli_saddr;  /* Exact address of symbol named
                                in dli_sname */
 } Dl_info;
 
+#pragma GCC visibility push(default)
+extern void* moz_mapped_dlopen(const char*  filename, int flag,
+                               int fd, void *mem, unsigned int len, unsigned int offset);
+extern void*        __wrap_dlopen(const char*  filename, int flag);
+extern int          __wrap_dlclose(void*  handle);
+extern const char*  __wrap_dlerror(void);
+extern void*        __wrap_dlsym(void*  handle, const char*  symbol);
+extern int          __wrap_dladdr(void* addr, Dl_info *info);
+#pragma GCC visibility pop
+
 extern void*        dlopen(const char*  filename, int flag);
 extern int          dlclose(void*  handle);
 extern const char*  dlerror(void);
 extern void*        dlsym(void*  handle, const char*  symbol);
 extern int          dladdr(void* addr, Dl_info *info);
 
 enum {
   RTLD_NOW  = 0,
--- a/other-licenses/android/linker.c
+++ b/other-licenses/android/linker.c
@@ -472,21 +472,23 @@ static Elf32_Sym *
         s = _elf_lookup(lsi, elf_hash, name);
         if(s != NULL)
             goto done;
     }
 
     for(d = si->dynamic; *d; d += 2) {
         if(d[0] == DT_NEEDED){
             lsi = (soinfo *)d[1];
+#ifndef MOZ_LINKER
             if (!validate_soinfo(lsi)) {
                 DL_ERR("%5d bad DT_NEEDED pointer in %s",
                        pid, si->name);
                 return NULL;
             }
+#endif
 
             DEBUG("%5d %s: looking up %s in %s\n",
                   pid, si->name, name, lsi->name);
             s = _elf_lookup(lsi, elf_hash, name);
             if ((s != NULL) && (s->st_shndx != SHN_UNDEF))
                 goto done;
         }
     }
@@ -673,16 +675,21 @@ typedef struct {
 /* Returns the requested base address if the library is prelinked,
  * and 0 otherwise.  */
 static unsigned long
 is_prelinked(int fd, const char *name)
 {
     off_t sz;
     prelink_info_t info;
 
+    if (fd < 0) {
+        WARN("Can't do prelinking without fd\n");
+        return 0;
+    }
+
     sz = lseek(fd, -sizeof(prelink_info_t), SEEK_END);
     if (sz < 0) {
         DL_ERR("lseek() failed!");
         return 0;
     }
 
     if (read(fd, &info, sizeof(info)) != sizeof(info)) {
         WARN("Could not read prelink_info_t structure for `%s`\n", name);
@@ -822,17 +829,17 @@ static int reserve_mem_region(soinfo *si
     if (base == MAP_FAILED) {
         DL_ERR("%5d can NOT map (%sprelinked) library '%s' at 0x%08x "
               "as requested, will try general pool: %d (%s)",
               pid, (si->base ? "" : "non-"), si->name, si->base,
               errno, strerror(errno));
         return -1;
     } else if (base != (void *)si->base) {
         DL_ERR("OOPS: %5d %sprelinked library '%s' mapped at 0x%08x, "
-              "not at 0x%08x", pid, (si->base ? "" : "non-"),
+              "not at 0x%08x", pid, (si->ba_index < 0 ? "" : "non-"),
               si->name, (unsigned)base, si->base);
         munmap(base, si->size);
         return -1;
     }
     return 0;
 }
 
 static int
@@ -883,17 +890,17 @@ err:
  *     header: Pointer to a header page that contains the ELF header.
  *             This is needed since we haven't mapped in the real file yet.
  *     si: ptr to soinfo struct describing the shared object.
  *
  * Returns:
  *     0 on success, -1 on failure.
  */
 static int
-load_segments(int fd, void *header, soinfo *si)
+load_segments(int fd, size_t offset, void *header, soinfo *si)
 {
     Elf32_Ehdr *ehdr = (Elf32_Ehdr *)header;
     Elf32_Phdr *phdr = (Elf32_Phdr *)((unsigned char *)header + ehdr->e_phoff);
     unsigned char *base = (unsigned char *)si->base;
     int cnt;
     unsigned len;
     unsigned char *tmp;
     unsigned char *pbase;
@@ -914,19 +921,28 @@ load_segments(int fd, void *header, soin
             /* we want to map in the segment on a page boundary */
             tmp = base + (phdr->p_vaddr & (~PAGE_MASK));
             /* add the # of bytes we masked off above to the total length. */
             len = phdr->p_filesz + (phdr->p_vaddr & PAGE_MASK);
 
             TRACE("[ %d - Trying to load segment from '%s' @ 0x%08x "
                   "(0x%08x). p_vaddr=0x%08x p_offset=0x%08x ]\n", pid, si->name,
                   (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
-            pbase = mmap(tmp, len, PFLAGS_TO_PROT(phdr->p_flags),
-                         MAP_PRIVATE | MAP_FIXED, fd,
-                         phdr->p_offset & (~PAGE_MASK));
+            if (fd == -1) {
+                pbase = mmap(tmp, len, PROT_WRITE,
+                             MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1,
+                             0);
+                if (pbase != MAP_FAILED) {
+                    memcpy(pbase, header + ((phdr->p_offset) & (~PAGE_MASK)), len);
+                    mprotect(pbase, len, PFLAGS_TO_PROT(phdr->p_flags));
+                }
+            } else
+                pbase = mmap(tmp, len, PFLAGS_TO_PROT(phdr->p_flags),
+                             MAP_PRIVATE | MAP_FIXED, fd,
+                             offset + ((phdr->p_offset) & (~PAGE_MASK)));
             if (pbase == MAP_FAILED) {
                 DL_ERR("%d failed to map segment from '%s' @ 0x%08x (0x%08x). "
                       "p_vaddr=0x%08x p_offset=0x%08x", pid, si->name,
                       (unsigned)tmp, len, phdr->p_vaddr, phdr->p_offset);
                 goto fail;
             }
 
             /* If 'len' didn't end on page boundary, and it's a writable
@@ -972,17 +988,17 @@ load_segments(int fd, void *header, soin
                  * the entire region previously, but we just want to be
                  * sure. This will also set the right flags on the region
                  * (though we can probably accomplish the same thing with
                  * mprotect).
                  */
                 extra_base = mmap((void *)tmp, extra_len,
                                   PFLAGS_TO_PROT(phdr->p_flags),
                                   MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS,
-                                  -1, 0);
+                                  -1, offset);
                 if (extra_base == MAP_FAILED) {
                     DL_ERR("[ %5d - failed to extend segment from '%s' @ 0x%08x"
                            " (0x%08x) ]", pid, si->name, (unsigned)tmp,
                           extra_len);
                     goto fail;
                 }
                 /* TODO: Check if we need to memset-0 this region.
                  * Anonymous mappings are zero-filled copy-on-writes, so we
@@ -1144,17 +1160,17 @@ load_library(const char *name)
     si->dynamic = (unsigned *)-1;
     if (alloc_mem_region(si) < 0)
         goto fail;
 
     TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
           pid, name, (void *)si->base, (unsigned) ext_sz);
 
     /* Now actually load the library's segments into right places in memory */
-    if (load_segments(fd, &__header[0], si) < 0) {
+    if (load_segments(fd, 0, &__header[0], si) < 0) {
         if (si->ba_index >= 0) {
             ba_free(&ba_nonprelink, si->ba_index);
             si->ba_index = -1;
         }
         goto fail;
     }
 
     /* this might not be right. Technically, we don't even need this info
@@ -1169,16 +1185,81 @@ load_library(const char *name)
 
 fail:
     if (si) free_info(si);
     close(fd);
     return NULL;
 }
 
 static soinfo *
+load_mapped_library(const char * name, int fd,
+                    void *mem, size_t len, size_t offset)
+{
+    int cnt;
+    unsigned ext_sz;
+    unsigned req_base;
+    const char *bname;
+    soinfo *si = NULL;
+    Elf32_Ehdr *hdr;
+
+    /* Parse the ELF header and get the size of the memory footprint for
+     * the library */
+    req_base = get_lib_extents(fd, name, mem, &ext_sz);
+    if (req_base == (unsigned)-1)
+        goto fail;
+    TRACE("[ %5d - '%s' (%s) wants base=0x%08x sz=0x%08x ]\n", pid, name,
+          (req_base ? "prelinked" : "not pre-linked"), req_base, ext_sz);
+
+    /* Now configure the soinfo struct where we'll store all of our data
+     * for the ELF object. If the loading fails, we waste the entry, but
+     * same thing would happen if we failed during linking. Configuring the
+     * soinfo struct here is a lot more convenient.
+     */
+    bname = strrchr(name, '/');
+    si = alloc_info(bname ? bname + 1 : name);
+    if (si == NULL)
+        goto fail;
+
+    /* Carve out a chunk of memory where we will map in the individual
+     * segments */
+    si->base = req_base;
+    si->size = ext_sz;
+    si->flags = 0;
+    si->entry = 0;
+    si->dynamic = (unsigned *)-1;
+    if (alloc_mem_region(si) < 0)
+        goto fail;
+
+    TRACE("[ %5d allocated memory for %s @ %p (0x%08x) ]\n",
+          pid, name, (void *)si->base, (unsigned) ext_sz);
+
+    /* Now actually load the library's segments into right places in memory */
+    if (load_segments(offset ? fd : -1, offset, mem, si) < 0) {
+        if (si->ba_index >= 0) {
+            ba_free(&ba_nonprelink, si->ba_index);
+            si->ba_index = -1;
+        }
+        goto fail;
+    }
+
+    /* this might not be right. Technically, we don't even need this info
+     * once we go through 'load_segments'. */
+    hdr = (Elf32_Ehdr *)si->base;
+    si->phdr = (Elf32_Phdr *)((unsigned char *)si->base + hdr->e_phoff);
+    si->phnum = hdr->e_phnum;
+    /**/
+
+    return si;
+
+fail:
+    if (si) free_info(si);
+    return NULL;
+}
+
+static soinfo *
 init_library(soinfo *si)
 {
     unsigned wr_offset = 0xffffffff;
 
     /* At this point we know that whatever is loaded @ base is a valid ELF
      * shared library whose segments are properly mapped in. */
     TRACE("[ %5d init_library base=0x%08x sz=0x%08x name='%s') ]\n",
           pid, si->base, si->size, si->name);
@@ -1217,16 +1298,42 @@ soinfo *find_library(const char *name)
 
     TRACE("[ %5d '%s' has not been loaded yet.  Locating...]\n", pid, name);
     si = load_library(name);
     if(si == NULL)
         return NULL;
     return init_library(si);
 }
 
+soinfo *find_mapped_library(const char *name, int fd,
+                            void *mem, size_t len, size_t offset)
+{
+    soinfo *si;
+    const char *bname = strrchr(name, '/');
+    bname = bname ? bname + 1 : name;
+
+    for(si = solist; si != 0; si = si->next){
+        if(!strcmp(bname, si->name)) {
+            if(si->flags & FLAG_ERROR) {
+                DL_ERR("%5d '%s' failed to load previously", pid, bname);
+                return NULL;
+            }
+            if(si->flags & FLAG_LINKED) return si;
+            DL_ERR("OOPS: %5d recursive link to '%s'", pid, si->name);
+            return NULL;
+        }
+    }
+
+    TRACE("[ %5d '%s' has not been loaded yet.  Locating...]\n", pid, name);
+    si = load_mapped_library(name, fd, mem, len, offset);
+    if(si == NULL)
+        return NULL;
+    return init_library(si);
+}
+
 /* TODO: 
  *   notify gdb of unload 
  *   for non-prelinked libraries, find a way to decrement libbase
  */
 static void call_destructors(soinfo *si);
 unsigned unload_library(soinfo *si)
 {
     unsigned *d;
@@ -1797,17 +1904,17 @@ static int link_image(soinfo *si, unsign
         }
     }
 
     if (si->dynamic == (unsigned *)-1) {
         DL_ERR("%5d missing PT_DYNAMIC?!", pid);
         goto fail;
     }
 
-    DEBUG("%5d dynamic = %p\n", pid, si->dynamic);
+    DEBUG("%5d dynamic = 0x%08x\n", pid, si->dynamic);
 
     /* extract useful information from dynamic section */
     for(d = si->dynamic; *d; d++){
         DEBUG("%5d d = %p, d[0] = 0x%08x d[1] = 0x%08x\n", pid, d, d[0], d[1]);
         switch(*d++){
         case DT_HASH:
             si->nbucket = ((unsigned *) (si->base + *d))[0];
             si->nchain = ((unsigned *) (si->base + *d))[1];
@@ -1878,17 +1985,17 @@ static int link_image(soinfo *si, unsign
             break;
         case DT_FINI:
             si->fini_func = (void (*)(void))(si->base + *d);
             DEBUG("%5d %s destructors (fini func) found at %p\n",
                   pid, si->name, si->fini_func);
             break;
         case DT_INIT_ARRAY:
             si->init_array = (unsigned *)(si->base + *d);
-            DEBUG("%5d %s constructors (init_array) found at %p\n",
+            DEBUG("%5d %s constructors (init_array) found at %08x\n",
                   pid, si->name, si->init_array);
             break;
         case DT_INIT_ARRAYSZ:
             si->init_array_count = ((unsigned)*d) / sizeof(Elf32_Addr);
             break;
         case DT_FINI_ARRAY:
             si->fini_array = (unsigned *)(si->base + *d);
             DEBUG("%5d %s destructors (fini_array) found at %p\n",
@@ -1912,45 +2019,49 @@ static int link_image(soinfo *si, unsign
              * it.
              */
             DEBUG("%5d Text segment should be writable during relocation.\n",
                   pid);
             break;
         }
     }
 
-    DEBUG("%5d si->base = 0x%08x, si->strtab = %p, si->symtab = %p\n", 
+    DEBUG("%5d si->base = 0x%08x, si->strtab = %08x, si->symtab = %08x\n", 
            pid, si->base, si->strtab, si->symtab);
 
     if((si->strtab == 0) || (si->symtab == 0)) {
         DL_ERR("%5d missing essential tables", pid);
         goto fail;
     }
 
     /* if this is the main executable, then load all of the preloads now */
     if(si->flags & FLAG_EXE) {
         int i;
         memset(preloads, 0, sizeof(preloads));
         for(i = 0; ldpreload_names[i] != NULL; i++) {
             soinfo *lsi = find_library(ldpreload_names[i]);
+            if(lsi == 0)
+                lsi = dlopen(ldpreload_names[i], RTLD_LAZY);
             if(lsi == 0) {
                 strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
                 DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
                        pid, ldpreload_names[i], si->name, tmp_err_buf);
                 goto fail;
             }
             lsi->refcount++;
             preloads[i] = lsi;
         }
     }
 
     for(d = si->dynamic; *d; d += 2) {
         if(d[0] == DT_NEEDED){
             DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
-            soinfo *lsi = find_library(si->strtab + d[1]);
+            soinfo *lsi = dlopen(si->strtab + d[1], RTLD_LAZY);
+            if(lsi == 0)
+                lsi = find_library(si->strtab + d[1]);
             if(lsi == 0) {
                 strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
                 DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
                        pid, si->strtab + d[1], si->name, tmp_err_buf);
                 goto fail;
             }
             /* Save the soinfo of the loaded DT_NEEDED library in the payload
                of the DT_NEEDED entry itself, so that we can retrieve the
@@ -2077,25 +2188,34 @@ static void parse_preloads(char *path, c
     if (i > 0 && len >= sizeof(ldpreloads_buf) &&
             ldpreloads_buf[sizeof(ldpreloads_buf) - 2] != '\0') {
         ldpreload_names[i - 1] = NULL;
     } else {
         ldpreload_names[i] = NULL;
     }
 }
 
+#ifndef MOZ_LINKER
 int main(int argc, char **argv)
 {
     return 0;
 }
+#endif
 
 #define ANDROID_TLS_SLOTS  BIONIC_TLS_SLOTS
 
 static void * __tls_area[ANDROID_TLS_SLOTS];
 
+#ifdef MOZ_LINKER
+void simple_linker_init(void)
+{
+    pid = getpid();
+    ba_init(&ba_nonprelink);
+}
+#else
 unsigned __linker_init(unsigned **elfdata)
 {
     static soinfo linker_soinfo;
 
     int argc = (int) *elfdata;
     char **argv = (char**) (elfdata + 1);
     unsigned *vecs = (unsigned*) (argv + argc + 1);
     soinfo *si;
@@ -2252,8 +2372,9 @@ unsigned __linker_init(unsigned **elfdat
 #if TIMING || STATS || COUNT_PAGES
     fflush(stdout);
 #endif
 
     TRACE("[ %5d Ready to execute '%s' @ 0x%08x ]\n", pid, si->name,
           si->entry);
     return si->entry;
 }
+#endif
--- a/other-licenses/android/linker.h
+++ b/other-licenses/android/linker.h
@@ -155,18 +155,18 @@ struct soinfo
 extern soinfo libdl_info;
 
 /* these must all be powers of two */
 #ifdef ARCH_SH
 #define LIBBASE 0x60000000
 #define LIBLAST 0x70000000
 #define LIBINC  0x00100000
 #else
-#define LIBBASE 0x80000000
-#define LIBLAST 0x90000000
+#define LIBBASE 0x90000000
+#define LIBLAST 0xA0000000
 #define LIBINC  0x00100000
 #endif
 
 #ifdef ANDROID_ARM_LINKER
 
 #define R_ARM_COPY       20
 #define R_ARM_GLOB_DAT   21
 #define R_ARM_JUMP_SLOT  22
@@ -217,22 +217,25 @@ extern soinfo libdl_info;
 #define DT_PREINIT_ARRAY   32
 #endif
 
 #ifndef DT_PREINIT_ARRAYSZ
 #define DT_PREINIT_ARRAYSZ 33
 #endif
 
 soinfo *find_library(const char *name);
+soinfo *find_mapped_library(const char *name, int fd,
+                            void *mem, size_t len, size_t offset);
 unsigned unload_library(soinfo *si);
 Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
 Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start);
 soinfo *find_containing_library(void *addr);
 Elf32_Sym *find_containing_symbol(void *addr, soinfo *si);
 const char *linker_get_error(void);
+void simple_linker_init(void);
 
 #ifdef ANDROID_ARM_LINKER 
 typedef long unsigned int *_Unwind_Ptr;
 _Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
 #elif defined(ANDROID_X86_LINKER) || defined(ANDROID_SH_LINKER)
 int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
 #endif
 
new file mode 100644
--- /dev/null
+++ b/other-licenses/android/nsGeckoUtils.cpp
@@ -0,0 +1,58 @@
+/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Android code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Brad Lassey <blassey@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <jni.h>
+#include <stdlib.h>
+
+extern "C" {
+  void JNICALL Java_org_mozilla_gecko_GeckoAppShell_putenv(JNIEnv *jenv, jclass, jstring map);
+}
+
+__attribute__ ((visibility("default")))
+void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_putenv(JNIEnv *jenv, jclass, jstring map)
+{
+    const char* str;
+    // XXX: java doesn't give us true UTF8, we should figure out something 
+    // better to do here
+    str = jenv->GetStringUTFChars(map, NULL);
+    if (str == NULL)
+        return;
+    putenv(strdup(str));
+    jenv->ReleaseStringUTFChars(map, str);
+}
+