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 266535ecad79
parent 55915 6277ca1ac576
child 55917 a6b6ebdd29a2
push id16337
push usermwu@mozilla.com
push dateFri, 15 Oct 2010 23:41:19 +0000
treeherdermozilla-central@ab6d8c5a300a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstaras, blocking-fennec
bugs588607
milestone2.0b8pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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);
+}
+