Bug 683127 part 11 - Hook the new linker in Android initialization. r=blassey
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 20 Jan 2012 09:49:07 +0100
changeset 85165 27e66973c882c3d33e051b00bfec2e9eeb75d923
parent 85164 41c7ad654949db5393d22a95d8dd4d233d47f244
child 85166 7469527224bf3058483c5718ff2ff09a4c21fc95
push idunknown
push userunknown
push dateunknown
reviewersblassey
bugs683127
milestone12.0a1
Bug 683127 part 11 - Hook the new linker in Android initialization. r=blassey
configure.in
mozglue/android/APKOpen.cpp
mozglue/android/Makefile.in
mozglue/android/SQLiteBridge.cpp
mozglue/linker/dladdr.h
--- a/configure.in
+++ b/configure.in
@@ -9046,17 +9046,27 @@ if test -z "$MOZ_NATIVE_NSPR"; then
         ac_configure_args="$ac_configure_args --disable-optimize"
     fi
     if test -n "$HAVE_64BIT_OS"; then
         ac_configure_args="$ac_configure_args --enable-64bit"
     fi
     if test -n "$USE_ARM_KUSER"; then
         ac_configure_args="$ac_configure_args --with-arm-kuser"
     fi
+    if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a $ac_cv_func_dladdr = no ; then
+      # dladdr is supported by the new linker, even when the system linker doesn't
+      # support it. Trick nspr into using dladdr when it's not supported.
+      _SAVE_CPPFLAGS="$CPPFLAGS"
+      export CPPFLAGS="-include $_topsrcdir/mozglue/linker/dladdr.h $CPPFLAGS"
+    fi
     AC_OUTPUT_SUBDIRS(nsprpub)
+    if test -n "$MOZ_LINKER" -a -z "$MOZ_OLD_LINKER" -a $ac_cv_func_dladdr = no; then
+      unset CPPFLAGS
+      CPPFLAGS="$_SAVE_CFLAGS"
+    fi
     ac_configure_args="$_SUBDIR_CONFIG_ARGS"
 fi
 
 if test -z "$MOZ_NATIVE_NSPR"; then
     # Hack to deal with the fact that we use NSPR_CFLAGS everywhere
     AC_MSG_WARN([Recreating autoconf.mk with updated nspr-config output])
     if test "$OS_ARCH" != "WINNT"; then
        NSPR_LIBS=`./nsprpub/config/nspr-config --prefix=$LIBXUL_DIST --exec-prefix=$MOZ_BUILD_ROOT/dist --libdir=$LIBXUL_DIST/lib --libs`
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -48,27 +48,32 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <sys/limits.h>
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
-#include <endian.h>
 #include <unistd.h>
 #include <zlib.h>
+#ifdef MOZ_OLD_LINKER
 #include <linux/ashmem.h>
+#include <endian.h>
+#endif
 #include "dlfcn.h"
 #include "APKOpen.h"
 #include <sys/time.h>
 #include <sys/resource.h>
 #include "Zip.h"
 #include "sqlite3.h"
 #include "SQLiteBridge.h"
+#ifndef MOZ_OLD_LINKER
+#include "ElfLoader.h"
+#endif
 
 /* Android headers don't define RUSAGE_THREAD */
 #ifndef RUSAGE_THREAD
 #define RUSAGE_THREAD 1
 #endif
 
 enum StartupEvent {
 #define mozilla_StartupTimeline_Event(ev, z) ev,
@@ -86,16 +91,17 @@ void StartupTimeline_Record(StartupEvent
 static struct mapping_info * lib_mapping = NULL;
 
 NS_EXPORT const struct mapping_info *
 getLibraryMapping()
 {
   return lib_mapping;
 }
 
+#ifdef MOZ_OLD_LINKER
 static int
 createAshmem(size_t bytes, const char *name)
 {
   int fd = open("/" ASHMEM_NAME_DEF, O_RDWR, 0600);
   if (fd < 0)
     return -1;
 
   char buf[ASHMEM_NAME_LEN];
@@ -104,16 +110,17 @@ createAshmem(size_t bytes, const char *n
   /*ret = */ioctl(fd, ASHMEM_SET_NAME, buf);
 
   if (!ioctl(fd, ASHMEM_SET_SIZE, bytes))
     return fd;
 
   close(fd);
   return -1;
 }
+#endif
 
 #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); \
@@ -299,16 +306,17 @@ SHELL_WRAPPER3(notifySmsDeleted, jboolea
 SHELL_WRAPPER3(notifySmsDeleteFailed, jint, jint, jlong)
 SHELL_WRAPPER2(notifyNoMessageInList, jint, jlong)
 SHELL_WRAPPER8(notifyListCreated, jint, jint, jstring, jstring, jstring, jlong, jint, jlong)
 SHELL_WRAPPER7(notifyGotNextMessage, jint, jstring, jstring, jstring, jlong, jint, jlong)
 SHELL_WRAPPER3(notifyReadingMessageListFailed, jint, jint, jlong)
 
 static void * xul_handle = NULL;
 static void * sqlite_handle = NULL;
+#ifdef MOZ_OLD_LINKER
 static time_t apk_mtime = 0;
 #ifdef DEBUG
 extern "C" int extractLibs = 1;
 #else
 extern "C" int extractLibs = 0;
 #endif
 
 static void
@@ -370,16 +378,17 @@ extractFile(const char * path, Zip::Stre
   close(fd);
 #ifdef ANDROID_ARM_LINKER
   /* We just extracted data that is going to be executed in the future.
    * We thus need to ensure Instruction and Data cache coherency. */
   cacheflush((unsigned) buf, (unsigned) buf + size, 0);
 #endif
   munmap(buf, size);
 }
+#endif
 
 static void
 extractLib(Zip::Stream &s, void * dest)
 {
   z_stream strm = {
     next_in: (Bytef *)s.GetBuffer(),
     avail_in: s.GetSize(),
     total_in: 0,
@@ -410,16 +419,17 @@ static int cache_count = 0;
 static struct lib_cache_info *cache_mapping = NULL;
 
 NS_EXPORT const struct lib_cache_info *
 getLibraryCache()
 {
   return cache_mapping;
 }
 
+#ifdef MOZ_OLD_LINKER
 static void
 ensureLibCache()
 {
   if (!cache_mapping)
     cache_mapping = (struct lib_cache_info *)calloc(MAX_LIB_CACHE_ENTRIES,
                                                     sizeof(*cache_mapping));
 }
 
@@ -570,17 +580,19 @@ static void * mozload(const char * path,
 #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;
 }
+#endif
 
+#ifdef MOZ_CRASHREPORTER
 static void *
 extractBuf(const char * path, Zip *zip)
 {
   Zip::Stream s;
   if (!zip->GetStream(path, &s))
     return NULL;
 
   void * buf = malloc(s.GetUncompressedSize());
@@ -590,16 +602,17 @@ extractBuf(const char * path, Zip *zip)
   }
   if (s.GetType() == Zip::Stream::DEFLATE)
     extractLib(s, buf);
   else
     memcpy(buf, s.GetBuffer(), s.GetUncompressedSize());
 
   return buf;
 }
+#endif
 
 static int mapping_count = 0;
 static char *file_ids = NULL;
 
 #define MAX_MAPPING_INFO 32
 
 extern "C" void
 report_mapping(char *name, void *base, uint32_t len, uint32_t offset)
@@ -613,53 +626,66 @@ report_mapping(char *name, void *base, u
   info->len = len;
   info->offset = offset;
 
   char * entry = strstr(file_ids, name);
   if (entry)
     info->file_id = strndup(entry + strlen(name) + 1, 32);
 }
 
+#ifdef MOZ_OLD_LINKER
 extern "C" void simple_linker_init(void);
+#endif
 
 static void
 loadGeckoLibs(const char *apkName)
 {
   chdir(getenv("GRE_HOME"));
 
+#ifdef MOZ_OLD_LINKER
   struct stat status;
   if (!stat(apkName, &status))
     apk_mtime = status.st_mtime;
+#endif
 
   struct timeval t0, t1;
   gettimeofday(&t0, 0);
   struct rusage usage1;
   getrusage(RUSAGE_THREAD, &usage1);
   
   Zip *zip = new Zip(apkName);
 
 #ifdef MOZ_CRASHREPORTER
   file_ids = (char *)extractBuf("lib.id", zip);
 #endif
 
+#ifndef MOZ_OLD_LINKER
+  char *file = new char[strlen(apkName) + sizeof("!/libxpcom.so")];
+  sprintf(file, "%s!/libxpcom.so", apkName);
+  __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY);
+  // libxul.so is pulled from libxpcom.so, so we don't need to give the full path
+  xul_handle = __wrap_dlopen("libxul.so", RTLD_GLOBAL | RTLD_LAZY);
+  delete[] file;
+#else
 #define MOZLOAD(name) mozload("lib" name ".so", zip)
   MOZLOAD("mozalloc");
   MOZLOAD("nspr4");
   MOZLOAD("plc4");
   MOZLOAD("plds4");
   MOZLOAD("nssutil3");
   MOZLOAD("nss3");
   MOZLOAD("ssl3");
   MOZLOAD("smime3");
   xul_handle = MOZLOAD("xul");
   MOZLOAD("xpcom");
   MOZLOAD("nssckbi");
   MOZLOAD("freebl3");
   MOZLOAD("softokn3");
 #undef MOZLOAD
+#endif
 
   delete zip;
 
 #ifdef MOZ_CRASHREPORTER
   free(file_ids);
   file_ids = NULL;
 #endif
 
@@ -710,32 +736,41 @@ loadGeckoLibs(const char *apkName)
   StartupTimeline_Record(LINKER_INITIALIZED, &t0);
   StartupTimeline_Record(LIBRARIES_LOADED, &t1);
 }
 
 static void loadSQLiteLibs(const char *apkName)
 {
   chdir(getenv("GRE_HOME"));
 
+#ifdef MOZ_OLD_LINKER
   simple_linker_init();
 
   struct stat status;
   if (!stat(apkName, &status))
     apk_mtime = status.st_mtime;
+#endif
 
   Zip *zip = new Zip(apkName);
   lib_mapping = (struct mapping_info *)calloc(MAX_MAPPING_INFO, sizeof(*lib_mapping));
 
 #ifdef MOZ_CRASHREPORTER
   file_ids = (char *)extractBuf("lib.id", zip);
 #endif
 
+#ifndef MOZ_OLD_LINKER
+  char *file = new char[strlen(apkName) + sizeof("!/mozsqlite3.so")];
+  sprintf(file, "%s!/mozsqlite3.so", apkName);
+  __wrap_dlopen(file, RTLD_GLOBAL | RTLD_LAZY);
+  delete [] file;
+#else
 #define MOZLOAD(name) mozload("lib" name ".so", zip)
   sqlite_handle = MOZLOAD("mozsqlite3");
 #undef MOZLOAD
+#endif
 
   delete zip;
 
 #ifdef MOZ_CRASHREPORTER
   free(file_ids);
   file_ids = NULL;
 #endif
 
@@ -756,18 +791,23 @@ Java_org_mozilla_gecko_GeckoAppShell_loa
     return;
 
   loadGeckoLibs(str);
   jenv->ReleaseStringUTFChars(jApkName, str);
 }
 
 extern "C" NS_EXPORT void JNICALL
 Java_org_mozilla_gecko_GeckoAppShell_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
-  if (jShouldExtract)
+  if (jShouldExtract) {
+#ifdef MOZ_OLD_LINKER
     extractLibs = 1;
+#else
+    putenv("MOZ_LINKER_EXTRACT=1");
+#endif
+  }
 
   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;
 
@@ -785,17 +825,19 @@ ChildProcessInit(int argc, char* argv[])
   for (i = 0; i < (argc - 1); i++) {
     if (strcmp(argv[i], "-greomni"))
       continue;
 
     i = i + 1;
     break;
   }
 
+#ifdef MOZ_OLD_LINKER
   fillLibCache(argv[argc - 1]);
+#endif
   loadSQLiteLibs(argv[i]);
   loadGeckoLibs(argv[i]);
 
   // don't pass the last arg - it's only recognized by the lib cache
   argc--;
 
   typedef GeckoProcessType (*XRE_StringToChildProcessType_t)(char*);
   typedef nsresult (*XRE_InitChildProcess_t)(int, char**, GeckoProcessType);
--- a/mozglue/android/Makefile.in
+++ b/mozglue/android/Makefile.in
@@ -55,16 +55,17 @@ CPPSRCS = \
   APKOpen.cpp \
   SQLiteBridge.cpp \
   $(NULL)
 
 LOCAL_INCLUDES += -I$(srcdir)/../linker
 LOCAL_INCLUDES += -I$(topsrcdir)/toolkit/components/startup
 LOCAL_INCLUDES += -I$(topsrcdir)/db/sqlite3/src
 ifdef MOZ_OLD_LINKER
+DEFINES += -DMOZ_OLD_LINKER
 LOCAL_INCLUDES += -I$(topsrcdir)/other-licenses/android
 ifeq ($(CPU_ARCH),arm)
 DEFINES += -DANDROID_ARM_LINKER
 endif
 endif
 
 EXPORTS = APKOpen.h
 
--- a/mozglue/android/SQLiteBridge.cpp
+++ b/mozglue/android/SQLiteBridge.cpp
@@ -34,16 +34,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include <stdlib.h>
 #include <jni.h>
 #include <android/log.h>
 #include "dlfcn.h"
 #include "APKOpen.h"
+#include "ElfLoader.h"
 #include "SQLiteBridge.h"
 
 #ifdef DEBUG
 #define LOG(x...) __android_log_print(ANDROID_LOG_INFO, "GeckoJNI", x)
 #else
 #define LOG(x...)
 #endif
 
new file mode 100644
--- /dev/null
+++ b/mozglue/linker/dladdr.h
@@ -0,0 +1,49 @@
+/* ***** 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 an ELF linker.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Mike Hommey <mh@glandium.org>
+ *
+ * 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 <dlfcn.h>
+
+#ifndef HAVE_DLADDR
+typedef struct {
+  const char *dli_fname;
+  void *dli_fbase;
+  const char *dli_sname;
+  void *dli_saddr;
+} Dl_info;
+extern int dladdr(void *addr, Dl_info *info) __attribute__((weak));
+#define HAVE_DLADDR 1
+#endif