Bug 794982 - Extract non-libxul native JNI functions from GeckoAppShell. r=glandium, cpeterson
authorKartikaya Gupta <kgupta@mozilla.com>
Thu, 07 Feb 2013 09:37:06 -0500
changeset 121127 5044d9a352ef5cb7e3bbcffaaf133e53116f0da3
parent 121126 99751bd8c759f8c21e0b3573fb6625b268e60dd7
child 121128 8373b1ce47f029484144d386f2e2b91654a4d5db
push id22606
push userkgupta@mozilla.com
push dateThu, 07 Feb 2013 14:37:13 +0000
treeherdermozilla-inbound@8373b1ce47f0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersglandium, cpeterson
bugs794982
milestone21.0a1
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 794982 - Extract non-libxul native JNI functions from GeckoAppShell. r=glandium, cpeterson
mobile/android/base/App.java.in
mobile/android/base/FilePickerResultHandler.java
mobile/android/base/GeckoApp.java
mobile/android/base/GeckoAppShell.java
mobile/android/base/GeckoThread.java
mobile/android/base/Makefile.in
mobile/android/base/NSSBridge.java
mobile/android/base/ProfileMigrator.java
mobile/android/base/RobocopAPI.java
mobile/android/base/db/GeckoProvider.java.in
mobile/android/base/mozglue/GeckoLoader.java.in
mozglue/android/APKOpen.cpp
mozglue/android/nsGeckoUtils.cpp
--- a/mobile/android/base/App.java.in
+++ b/mobile/android/base/App.java.in
@@ -51,17 +51,10 @@ public class App extends BrowserApp {
 #ifdef MOZ_PROFILING
         if (item.getItemId() == R.id.toggle_profiling) {
             GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("ToggleProfiling", null));
             return true;
         }
 #endif
         return super.onOptionsItemSelected(item);
     }
+}
 
-#ifdef MOZ_LINKER_EXTRACT
-    @Override
-    public boolean linkerExtract() {
-        return true;
-    }
-#endif
-};
-
--- a/mobile/android/base/FilePickerResultHandler.java
+++ b/mobile/android/base/FilePickerResultHandler.java
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
+import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.util.ActivityResultHandler;
 
 import android.app.Activity;
 import android.content.ContentResolver;
 import android.content.Intent;
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.OpenableColumns;
@@ -57,17 +58,17 @@ abstract class FilePickerResultHandler i
             int period;
             if (name == null || (period = name.lastIndexOf('.')) == -1) {
                 String mimeType = cr.getType(uri);
                 fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType);
             } else {
                 fileExt = name.substring(period);
                 fileName = name.substring(0, period);
             }
-            File file = File.createTempFile(fileName, fileExt, GeckoAppShell.getGREDir(GeckoApp.mAppContext));
+            File file = File.createTempFile(fileName, fileExt, GeckoLoader.getGREDir(GeckoApp.mAppContext));
             FileOutputStream fos = new FileOutputStream(file);
             InputStream is = cr.openInputStream(uri);
             byte[] buf = new byte[4096];
             int len = is.read(buf);
             while (len != -1) {
                 fos.write(buf, 0, len);
                 len = is.read(buf);
             }
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -7,16 +7,17 @@ package org.mozilla.gecko;
 
 import org.mozilla.gecko.background.announcements.AnnouncementsBroadcastService;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PluginLayer;
 import org.mozilla.gecko.gfx.PointUtils;
+import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.ui.PanZoomController;
 import org.mozilla.gecko.util.GeckoAsyncTask;
 import org.mozilla.gecko.util.GeckoBackgroundThread;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.GeckoEventResponder;
 import org.mozilla.gecko.updater.UpdateServiceHelper;
 import org.mozilla.gecko.updater.UpdateService;
 
@@ -1485,17 +1486,17 @@ abstract public class GeckoApp
             return;
         }
 
         // StrictMode is set by defaults resource flag |enableStrictMode|.
         if (getResources().getBoolean(R.bool.enableStrictMode)) {
             enableStrictMode();
         }
 
-        GeckoAppShell.loadMozGlue(this);
+        GeckoLoader.loadMozGlue(this);
         if (sGeckoThread != null) {
             // this happens when the GeckoApp activity is destroyed by android
             // without killing the entire application (see bug 769269)
             mIsRestoringActivity = true;
             Telemetry.HistogramAdd("FENNEC_RESTORING_ACTIVITY", 1);
         }
 
         mMainHandler = new Handler();
@@ -2623,20 +2624,16 @@ abstract public class GeckoApp
         public void setDrawingCacheEnabled(boolean enabled) {
             // Instead of setting drawing cache in the view itself, we simply
             // enable drawing caching on its children. This is mainly used in
             // animations (see PropertyAnimator)
             super.setChildrenDrawnWithCacheEnabled(enabled);
         }
     }
 
-    public boolean linkerExtract() {
-        return false;
-    }
-
     private class FullScreenHolder extends FrameLayout {
 
         public FullScreenHolder(Context ctx) {
             super(ctx);
         }
 
         @Override
         public void addView(View view, int index) {
--- a/mobile/android/base/GeckoAppShell.java
+++ b/mobile/android/base/GeckoAppShell.java
@@ -5,21 +5,21 @@
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.gfx.BitmapUtils;
 import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.GfxInfoThread;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.TouchEventHandler;
+import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.util.EventDispatcher;
 import org.mozilla.gecko.util.GeckoBackgroundThread;
 import org.mozilla.gecko.util.GeckoEventListener;
 
-import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.ActivityNotFoundException;
 import android.content.ClipData;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
@@ -44,17 +44,16 @@ import android.location.Criteria;
 import android.location.Location;
 import android.location.LocationManager;
 import android.media.MediaScannerConnection;
 import android.media.MediaScannerConnection.MediaScannerConnectionClient;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
 import android.net.Uri;
 import android.os.Build;
-import android.os.Environment;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
 import android.os.StatFs;
 import android.os.SystemClock;
 import android.os.Vibrator;
 import android.provider.Settings;
@@ -78,24 +77,20 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.lang.reflect.Field;
 import java.net.URL;
 import java.nio.ByteBuffer;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.text.NumberFormat;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Locale;
 import java.util.NoSuchElementException;
 import java.util.StringTokenizer;
 import java.util.concurrent.SynchronousQueue;
 import java.net.ProxySelector;
 import java.net.Proxy;
 import java.net.URI;
 
 public class GeckoAppShell
@@ -123,29 +118,19 @@ public class GeckoAppShell
     static public final int WPL_STATE_IS_DOCUMENT = 0x00020000;
     static public final int WPL_STATE_IS_NETWORK = 0x00040000;
 
     public static final String SHORTCUT_TYPE_WEBAPP = "webapp";
     public static final String SHORTCUT_TYPE_BOOKMARK = "bookmark";
 
     static private final boolean LOGGING = false;
 
-    static private File sCacheFile = null;
-    static private int sFreeSpace = -1;
     static File sHomeDir = null;
     static private int sDensityDpi = 0;
 
-    private static final Object sLibLoadingLock = new Object();
-    // Must hold sLibLoadingLock while accessing the following boolean variables.
-    private static boolean sSQLiteLibsLoaded;
-    private static boolean sNSSLibsLoaded;
-    private static boolean sMozGlueLoaded;
-    private static boolean sLibsSetup;
-
-    private static File sGREDir = null;
     private static final EventDispatcher sEventDispatcher = new EventDispatcher();
 
     /* Default colors. */
     private static final float[] DEFAULT_LAUNCHER_ICON_HSV = { 32.0f, 1.0f, 1.0f };
 
     /* Is the value in sVibrationEndTime valid? */
     private static boolean sVibrationMaybePlaying = false;
 
@@ -171,29 +156,24 @@ public class GeckoAppShell
     public static GfxInfoThread sGfxInfoThread = null;
 
     static ActivityHandlerHelper sActivityHelper = new ActivityHandlerHelper();
 
     /* The Android-side API: API methods that Android calls */
 
     // Initialization methods
     public static native void nativeInit();
-    public static native void nativeRun(String args);
 
     // helper methods
     //    public static native void setSurfaceView(GeckoSurfaceView sv);
     public static native void setLayerClient(GeckoLayerClient client);
-    public static native void putenv(String map);
     public static native void onResume();
     public static native void onLowMemory();
     public static native void callObserver(String observerKey, String topic, String data);
     public static native void removeObserver(String observerKey);
-    public static native void loadGeckoLibsNative(String apkName);
-    public static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
-    public static native void loadNSSLibsNative(String apkName, boolean shouldExtract);
     public static native void onChangeNetworkLinkStatus(String status);
     public static native Message getNextMessageFromQueue(MessageQueue queue);
     public static native void onSurfaceTextureFrameAvailable(Object surfaceTexture, int id);
 
     public static void registerGlobalExceptionHandler() {
         Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
             public void uncaughtException(Thread thread, Throwable e) {
                 Log.e(LOGTAG, ">>> REPORTING UNCAUGHT EXCEPTION FROM THREAD "
@@ -301,258 +281,16 @@ public class GeckoAppShell
     public static Handler getGeckoHandler() {
         return sGeckoHandler;
     }
 
     public static Handler getHandler() {
         return GeckoBackgroundThread.getHandler();
     }
 
-    public static File getCacheDir(Context context) {
-        if (sCacheFile == null)
-            sCacheFile = context.getCacheDir();
-        return sCacheFile;
-    }
-
-    public static long getFreeSpace(Context context) {
-        try {
-            if (sFreeSpace == -1) {
-                File cacheDir = getCacheDir(context);
-                if (cacheDir != null) {
-                    StatFs cacheStats = new StatFs(cacheDir.getPath());
-                    sFreeSpace = cacheStats.getFreeBlocks() *
-                        cacheStats.getBlockSize();
-                } else {
-                    Log.w(LOGTAG, "Unable to get cache dir.");
-                }
-            }
-        } catch (Exception e) {
-            Log.w(LOGTAG, "Caught exception while stating cache dir.", e);
-        }
-        return sFreeSpace;
-    }
-
-    public static File getGREDir(Context context) {
-        if (sGREDir == null)
-            sGREDir = new File(context.getApplicationInfo().dataDir);
-        return sGREDir;
-    }
-
-    // java-side stuff
-    public static void loadLibsSetup(Context context) {
-        synchronized (sLibLoadingLock) {
-            if (sLibsSetup) {
-                return;
-            }
-            sLibsSetup = true;
-        }
-
-        // The package data lib directory isn't placed in ld.so's
-        // search path, so we have to manually load libraries that
-        // libxul will depend on.  Not ideal.
-
-        File cacheFile = getCacheDir(context);
-        putenv("GRE_HOME=" + getGREDir(context).getPath());
-
-        // setup the libs cache
-        String linkerCache = System.getenv("MOZ_LINKER_CACHE");
-        if (linkerCache == null) {
-            linkerCache = cacheFile.getPath();
-            GeckoAppShell.putenv("MOZ_LINKER_CACHE=" + linkerCache);
-        }
-
-        if (GeckoApp.mAppContext != null &&
-            GeckoApp.mAppContext.linkerExtract()) {
-            GeckoAppShell.putenv("MOZ_LINKER_EXTRACT=1");
-            // Ensure that the cache dir is world-writable
-            File cacheDir = new File(linkerCache);
-            if (cacheDir.isDirectory()) {
-                cacheDir.setWritable(true, false);
-                cacheDir.setExecutable(true, false);
-                cacheDir.setReadable(true, false);
-            }
-        }
-    }
-
-    private static void setupPluginEnvironment(GeckoApp context) {
-        // setup plugin path directories
-        try {
-            String[] dirs = context.getPluginDirectories();
-            // Check to see if plugins were blocked.
-            if (dirs == null) {
-                GeckoAppShell.putenv("MOZ_PLUGINS_BLOCKED=1");
-                GeckoAppShell.putenv("MOZ_PLUGIN_PATH=");
-                return;
-            }
-
-            StringBuffer pluginSearchPath = new StringBuffer();
-            for (int i = 0; i < dirs.length; i++) {
-                pluginSearchPath.append(dirs[i]);
-                pluginSearchPath.append(":");
-            }
-            GeckoAppShell.putenv("MOZ_PLUGIN_PATH="+pluginSearchPath);
-
-            File pluginDataDir = context.getDir("plugins", 0);
-            GeckoAppShell.putenv("ANDROID_PLUGIN_DATADIR=" + pluginDataDir.getPath());
-
-        } catch (Exception ex) {
-            Log.w(LOGTAG, "Caught exception getting plugin dirs.", ex);
-        }
-    }
-
-    private static void setupDownloadEnvironment(GeckoApp context) {
-        try {
-            File downloadDir = null;
-            File updatesDir  = null;
-            if (Build.VERSION.SDK_INT >= 8) {
-                downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
-                updatesDir  = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
-            }
-            if (downloadDir == null) {
-                downloadDir = new File(Environment.getExternalStorageDirectory().getPath(), "download");
-            }
-            if (updatesDir == null) {
-                updatesDir = downloadDir;
-            }
-            GeckoAppShell.putenv("DOWNLOADS_DIRECTORY=" + downloadDir.getPath());
-            GeckoAppShell.putenv("UPDATES_DIRECTORY="   + updatesDir.getPath());
-        }
-        catch (Exception e) {
-            Log.w(LOGTAG, "No download directory found.", e);
-        }
-    }
-
-    public static void setupGeckoEnvironment(Context context) {
-        GeckoProfile profile = GeckoProfile.get(context);
-
-        setupPluginEnvironment((GeckoApp) context);
-        setupDownloadEnvironment((GeckoApp) context);
-
-        // profile home path
-        GeckoAppShell.putenv("HOME=" + profile.getFilesDir().getPath());
-
-        // setup the tmp path
-        File f = context.getDir("tmp", Context.MODE_WORLD_READABLE |
-                                 Context.MODE_WORLD_WRITEABLE );
-        if (!f.exists())
-            f.mkdirs();
-        GeckoAppShell.putenv("TMPDIR=" + f.getPath());
-
-        // setup the downloads path
-        f = Environment.getDownloadCacheDirectory();
-        GeckoAppShell.putenv("EXTERNAL_STORAGE=" + f.getPath());
-
-        // setup the app-specific cache path
-        f = context.getCacheDir();
-        GeckoAppShell.putenv("CACHE_DIRECTORY=" + f.getPath());
-
-        /* We really want to use this code, but it requires bumping up the SDK to 17 so for now
-           we will use reflection. See https://bugzilla.mozilla.org/show_bug.cgi?id=811763#c11
-        
-        if (Build.VERSION.SDK_INT >= 17) {
-            android.os.UserManager um = (android.os.UserManager)context.getSystemService(Context.USER_SERVICE);
-            if (um != null) {
-                GeckoAppShell.putenv("MOZ_ANDROID_USER_SERIAL_NUMBER=" + um.getSerialNumberForUser(android.os.Process.myUserHandle()));
-            } else {
-                Log.d(LOGTAG, "Unable to obtain user manager service on a device with SDK version " + Build.VERSION.SDK_INT);
-            }
-        }
-        */
-        try {
-            Object userManager = context.getSystemService("user");
-            if (userManager != null) {
-                // if userManager is non-null that means we're running on 4.2+ and so the rest of this
-                // should just work
-                Object userHandle = android.os.Process.class.getMethod("myUserHandle", (Class[])null).invoke(null);
-                Object userSerial = userManager.getClass().getMethod("getSerialNumberForUser", userHandle.getClass()).invoke(userManager, userHandle);
-                GeckoAppShell.putenv("MOZ_ANDROID_USER_SERIAL_NUMBER=" + userSerial.toString());
-            }
-        } catch (Exception e) {
-            // Guard against any unexpected failures
-            Log.d(LOGTAG, "Unable to set the user serial number", e);
-        }
-
-        putLocaleEnv();
-    }
-
-    /* This method is referenced by Robocop via reflection. */
-    public static void loadSQLiteLibs(Context context, String apkName) {
-        synchronized (sLibLoadingLock) {
-            if (sSQLiteLibsLoaded) {
-                return;
-            }
-            sSQLiteLibsLoaded = true;
-        }
-
-        loadMozGlue(context);
-        // the extract libs parameter is being removed in bug 732069
-        loadLibsSetup(context);
-        loadSQLiteLibsNative(apkName, false);
-    }
-
-    public static void loadNSSLibs(Context context, String apkName) {
-        synchronized (sLibLoadingLock) {
-            if (sNSSLibsLoaded) {
-                return;
-            }
-            sNSSLibsLoaded = true;
-        }
-
-        loadMozGlue(context);
-        loadLibsSetup(context);
-        loadNSSLibsNative(apkName, false);
-    }
-
-    public static void loadMozGlue(Context context) {
-        synchronized (sLibLoadingLock) {
-            if (sMozGlueLoaded) {
-                return;
-            }
-            sMozGlueLoaded = true;
-        }
-
-        System.loadLibrary("mozglue");
-
-        // When running TestPasswordProvider, we're being called with
-        // a GeckoApplication, which is not an Activity
-        if (!(context instanceof Activity))
-            return;
-
-        Intent i = null;
-        i = ((Activity)context).getIntent();
-
-        // if we have an intent (we're being launched by an activity)
-        // read in any environmental variables from it here
-        String env = i.getStringExtra("env0");
-        Log.d(LOGTAG, "Gecko environment env0: "+ env);
-        for (int c = 1; env != null; c++) {
-            GeckoAppShell.putenv(env);
-            env = i.getStringExtra("env" + c);
-            Log.d(LOGTAG, "env" + c + ": " + env);
-        }
-    }
-
-    public static void loadGeckoLibs(String apkName) {
-        loadLibsSetup(GeckoApp.mAppContext);
-        loadGeckoLibsNative(apkName);
-    }
-
-    private static void putLocaleEnv() {
-        GeckoAppShell.putenv("LANG=" + Locale.getDefault().toString());
-        NumberFormat nf = NumberFormat.getInstance();
-        if (nf instanceof DecimalFormat) {
-            DecimalFormat df = (DecimalFormat)nf;
-            DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
-
-            GeckoAppShell.putenv("LOCALE_DECIMAL_POINT=" + dfs.getDecimalSeparator());
-            GeckoAppShell.putenv("LOCALE_THOUSANDS_SEP=" + dfs.getGroupingSeparator());
-            GeckoAppShell.putenv("LOCALE_GROUPING=" + (char)df.getGroupingSize());
-        }
-    }
-
     public static void runGecko(String apkPath, String args, String url, String type) {
         Looper.prepare();
         sGeckoHandler = new Handler();
 
         // run gecko -- it will spawn its own thread
         GeckoAppShell.nativeInit();
 
         // Tell Gecko where the target byte buffer is for rendering
@@ -572,17 +310,17 @@ public class GeckoAppShell
 
         GeckoApp.mAppContext.runOnUiThread(new Runnable() {
                 public void run() {
                     geckoLoaded();
                 }
             });
 
         // and go
-        GeckoAppShell.nativeRun(combinedArgs);
+        GeckoLoader.nativeRun(combinedArgs);
     }
 
     // Called on the UI thread after Gecko loads.
     private static void geckoLoaded() {
         GeckoEditable editable = new GeckoEditable();
         // install the gecko => editable listener
         mEditableListener = editable;
     }
--- a/mobile/android/base/GeckoThread.java
+++ b/mobile/android/base/GeckoThread.java
@@ -1,16 +1,17 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.gfx.GfxInfoThread;
+import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.util.GeckoEventListener;
 
 import org.json.JSONObject;
 
 import android.content.Intent;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.os.SystemClock;
@@ -43,20 +44,26 @@ public class GeckoThread extends Thread 
 
     private String initGeckoEnvironment() {
         // At some point while loading the gecko libs our default locale gets set
         // so just save it to locale here and reset it as default after the join
         Locale locale = Locale.getDefault();
 
         GeckoApp app = GeckoApp.mAppContext;
         String resourcePath = app.getApplication().getPackageResourcePath();
-        GeckoAppShell.setupGeckoEnvironment(app);
-        GeckoAppShell.loadSQLiteLibs(app, resourcePath);
-        GeckoAppShell.loadNSSLibs(app, resourcePath);
-        GeckoAppShell.loadGeckoLibs(resourcePath);
+        String[] pluginDirs = null;
+        try {
+            pluginDirs = app.getPluginDirectories();
+        } catch (Exception e) {
+            Log.w(LOGTAG, "Caught exception getting plugin dirs.", e);
+        }
+        GeckoLoader.setupGeckoEnvironment(app, pluginDirs, GeckoProfile.get(app).getFilesDir().getPath());
+        GeckoLoader.loadSQLiteLibs(app, resourcePath);
+        GeckoLoader.loadNSSLibs(app, resourcePath);
+        GeckoLoader.loadGeckoLibs(app, resourcePath);
 
         Locale.setDefault(locale);
 
         Resources res = app.getBaseContext().getResources();
         Configuration config = res.getConfiguration();
         config.locale = locale;
         res.updateConfiguration(config, res.getDisplayMetrics());
 
--- a/mobile/android/base/Makefile.in
+++ b/mobile/android/base/Makefile.in
@@ -15,16 +15,20 @@ DIRS = locales
 DIST_FILES = package-name.txt
 
 include $(topsrcdir)/mobile/android/base/android-services-files.mk
 
 MOZGLUE_JAVA_FILES := \
   mozglue/DirectBufferAllocator.java \
   $(NULL)
 
+MOZGLUE_PP_JAVA_FILES := \
+  mozglue/GeckoLoader.java \
+  $(NULL)
+
 UTIL_JAVA_FILES := \
   ActivityResultHandler.java \
   ActivityResultHandlerMap.java \
   GeckoAsyncTask.java \
   GeckoBackgroundThread.java \
   GeckoEventListener.java \
   GeckoEventResponder.java \
   GeckoJarReader.java \
@@ -317,16 +321,17 @@ endif
 
 ifdef MOZ_LINKER_EXTRACT
 DEFINES += -DMOZ_LINKER_EXTRACT=1
 endif
 
 GARBAGE += \
   AndroidManifest.xml  \
   classes.dex  \
+  $(MOZGLUE_PP_JAVA_FILES) \
   $(FENNEC_PP_JAVA_FILES) \
   $(FENNEC_PP_JAVA_VIEW_FILES) \
   $(SYNC_PP_JAVA_FILES) \
   gecko.ap_  \
   res/values/strings.xml \
   R.java \
   $(FENNEC_PP_XML_FILES) \
   $(SYNC_PP_RES_XML) \
@@ -1195,20 +1200,20 @@ classes.dex: jars/gecko-browser.jar
 	$(DX) --dex --output=classes.dex jars $(ANDROID_COMPAT_LIB)
 
 jars/gecko-browser.jar: jars/gecko-mozglue.jar jars/gecko-util.jar jars/sync-thirdparty.jar $(addprefix $(srcdir)/,$(FENNEC_JAVA_FILES)) $(FENNEC_PP_JAVA_FILES) $(FENNEC_PP_JAVA_VIEW_FILES) $(addprefix $(srcdir)/,$(SYNC_JAVA_FILES)) $(SYNC_PP_JAVA_FILES) R.java
 	@echo "JAR gecko-browser.jar"
 	$(NSINSTALL) -D classes/gecko-browser
 	$(JAVAC) $(JAVAC_FLAGS) -Xlint:all,-deprecation,-fallthrough -d classes/gecko-browser -classpath "jars/gecko-mozglue.jar:jars/gecko-util.jar:jars/sync-thirdparty.jar" $(addprefix $(srcdir)/,$(FENNEC_JAVA_FILES)) $(FENNEC_PP_JAVA_FILES) $(FENNEC_PP_JAVA_VIEW_FILES) $(addprefix $(srcdir)/,$(SYNC_JAVA_FILES)) $(SYNC_PP_JAVA_FILES) R.java
 	$(JAR) cMf jars/gecko-browser.jar -C classes/gecko-browser .
 
-jars/gecko-mozglue.jar: $(addprefix $(srcdir)/,$(MOZGLUE_JAVA_FILES)) jars
+jars/gecko-mozglue.jar: $(addprefix $(srcdir)/,$(MOZGLUE_JAVA_FILES)) $(MOZGLUE_PP_JAVA_FILES) jars
 	@echo "JAR gecko-mozglue.jar"
 	$(NSINSTALL) -D classes/gecko-mozglue
-	$(JAVAC) $(JAVAC_FLAGS) -Xlint:all -d classes/gecko-mozglue $(addprefix $(srcdir)/,$(MOZGLUE_JAVA_FILES))
+	$(JAVAC) $(JAVAC_FLAGS) -Xlint:all -d classes/gecko-mozglue $(addprefix $(srcdir)/,$(MOZGLUE_JAVA_FILES)) $(MOZGLUE_PP_JAVA_FILES)
 	$(JAR) cMf jars/gecko-mozglue.jar -C classes/gecko-mozglue .
 
 jars/gecko-util.jar: $(addprefix $(srcdir)/,$(UTIL_JAVA_FILES)) jars
 	@echo "JAR gecko-util.jar"
 	$(NSINSTALL) -D classes/gecko-util
 	$(JAVAC) $(JAVAC_FLAGS) -Xlint:all,-deprecation -d classes/gecko-util $(addprefix $(srcdir)/,$(UTIL_JAVA_FILES))
 	$(JAR) cMf jars/gecko-util.jar -C classes/gecko-util .
 
@@ -1232,24 +1237,25 @@ PP_RES_XML= \
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
              $(AUTOMATION_PPARGS) $(DEFINES) $(ACDEFINES) $(subst res/,$(srcdir)/resources/,$@).in > $@
 
 # AndroidManifest.xml includes these files, so they need to be marked as dependencies.
 SERVICES_MANIFEST_FRAGMENTS = $(wildcard $(topsrcdir)/mobile/android/services/manifests/*.in)
 
 android-tgts = \
   AndroidManifest.xml \
+  $(MOZGLUE_PP_JAVA_FILES) \
   $(FENNEC_PP_JAVA_FILES) \
   $(SYNC_PP_JAVA_FILES) \
   package-name.txt \
   $(NULL)
 
 android-preqs = \
   Makefile.in \
-  $(call mkdir_deps,db,sync/repositories/android,background/announcements) \
+  $(call mkdir_deps,mozglue,db,sync/repositories/android,background/announcements) \
   $(SERVICES_MANIFEST_FRAGMENTS) \
   WebAppManifestFragment.xml.in \
   WebAppsFragments.java \
   $(NULL)
 
 $(android-tgts): % : %.in $(android-preqs)
 	$(PYTHON) $(topsrcdir)/config/Preprocessor.py \
              $(AUTOMATION_PPARGS) -DOBJDIR="`pwd`" $(DEFINES) $(ACDEFINES) $< > $@
--- a/mobile/android/base/NSSBridge.java
+++ b/mobile/android/base/NSSBridge.java
@@ -1,48 +1,50 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
+import org.mozilla.gecko.mozglue.GeckoLoader;
+
 import android.content.Context;
 
 public class NSSBridge {
     private static final String LOGTAG = "NSSBridge";
 
     private static native String nativeEncrypt(String aDb, String aValue);
     private static native String nativeDecrypt(String aDb, String aValue);
 
     static public String encrypt(Context context, String aValue)
       throws Exception {
         String resourcePath = context.getPackageResourcePath();
-        GeckoAppShell.loadNSSLibs(context, resourcePath);
+        GeckoLoader.loadNSSLibs(context, resourcePath);
 
         String path = GeckoProfile.get(context).getDir().toString();
         return nativeEncrypt(path, aValue);
     }
 
     static public String encrypt(Context context, String profilePath, String aValue)
       throws Exception {
         String resourcePath = context.getPackageResourcePath();
-        GeckoAppShell.loadNSSLibs(context, resourcePath);
+        GeckoLoader.loadNSSLibs(context, resourcePath);
 
         return nativeEncrypt(profilePath, aValue);
     }
 
     static public String decrypt(Context context, String aValue)
       throws Exception {
         String resourcePath = context.getPackageResourcePath();
-        GeckoAppShell.loadNSSLibs(context, resourcePath);
+        GeckoLoader.loadNSSLibs(context, resourcePath);
 
         String path = GeckoProfile.get(context).getDir().toString();
         return nativeDecrypt(path, aValue);
     }
 
     static public String decrypt(Context context, String profilePath, String aValue)
       throws Exception {
         String resourcePath = context.getPackageResourcePath();
-        GeckoAppShell.loadNSSLibs(context, resourcePath);
+        GeckoLoader.loadNSSLibs(context, resourcePath);
 
         return nativeDecrypt(profilePath, aValue);
     }
 }
--- a/mobile/android/base/ProfileMigrator.java
+++ b/mobile/android/base/ProfileMigrator.java
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserContract.Bookmarks;
 import org.mozilla.gecko.db.BrowserContract.Passwords;
 import org.mozilla.gecko.db.LocalBrowserDB;
+import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.sqlite.SQLiteBridge;
 import org.mozilla.gecko.sqlite.SQLiteBridgeException;
 import org.mozilla.gecko.sync.setup.SyncAccounts;
 import org.mozilla.gecko.sync.setup.SyncAccounts.SyncAccountParameters;
 
 import android.accounts.Account;
 import android.content.ContentProviderOperation;
 import android.content.ContentResolver;
@@ -661,17 +662,17 @@ public class ProfileMigrator {
                     }
                 }
             }.execute(mContext);
         }
     }
 
     private class MiscTask implements Runnable {
         protected void cleanupXULLibCache() {
-            File cacheFile = GeckoAppShell.getCacheDir(mContext);
+            File cacheFile = GeckoLoader.getCacheDir(mContext);
             File[] files = cacheFile.listFiles();
             if (files != null) {
                 Iterator<File> cacheFiles = Arrays.asList(files).iterator();
                 while (cacheFiles.hasNext()) {
                     File libFile = cacheFiles.next();
                     if (libFile.getName().endsWith(".so")) {
                         libFile.delete();
                     }
@@ -1268,17 +1269,17 @@ public class ProfileMigrator {
                 setMigratedBookmarks();
                 setMigratedHistory();
                 return;
             }
             File dbFileWal = new File(dbPathWal);
             File dbFileShm = new File(dbPathShm);
 
             SQLiteBridge db = null;
-            GeckoAppShell.loadSQLiteLibs(mContext, mContext.getPackageResourcePath());
+            GeckoLoader.loadSQLiteLibs(mContext, mContext.getPackageResourcePath());
             try {
                 db = new SQLiteBridge(dbPath);
                 if (!checkPlacesSchema(db)) {
                     // Incompatible schema. Bail out.
                     setMigratedBookmarks();
                     setMigratedHistory();
                 } else {
                     // Compatible schema. Let's go.
--- a/mobile/android/base/RobocopAPI.java
+++ b/mobile/android/base/RobocopAPI.java
@@ -1,16 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko;
 
 import org.mozilla.gecko.gfx.GeckoLayerClient;
 import org.mozilla.gecko.gfx.LayerView;
+import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.sqlite.SQLiteBridge;
 import org.mozilla.gecko.util.GeckoEventListener;
 
 import android.app.Activity;
 import android.database.Cursor;
 import android.view.View;
 
 import java.nio.IntBuffer;
@@ -34,16 +35,16 @@ public class RobocopAPI {
         GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent(subject, data));
     }
 
     public void setDrawListener(GeckoLayerClient.DrawListener listener) {
         mGeckoApp.getLayerView().getLayerClient().setDrawListener(listener);
     }
 
     public Cursor querySql(String dbPath, String query) {
-        GeckoAppShell.loadSQLiteLibs(mGeckoApp, mGeckoApp.getApplication().getPackageResourcePath());
+        GeckoLoader.loadSQLiteLibs(mGeckoApp, mGeckoApp.getApplication().getPackageResourcePath());
         return new SQLiteBridge(dbPath).rawQuery(query, null);
     }
 
     public IntBuffer getViewPixels(View view) {
         return ((LayerView)view).getPixels();
     }
 }
--- a/mobile/android/base/db/GeckoProvider.java.in
+++ b/mobile/android/base/db/GeckoProvider.java.in
@@ -9,26 +9,26 @@ import java.io.File;
 import java.io.IOException;
 import java.lang.IllegalArgumentException;
 import java.util.HashMap;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.Random;
 
-import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoEvent;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.GeckoThread;
 import org.mozilla.gecko.db.BrowserContract.CommonColumns;
 import org.mozilla.gecko.db.DBUtils;
 import org.mozilla.gecko.db.BrowserContract.Passwords;
 import org.mozilla.gecko.db.BrowserContract.DeletedPasswords;
 import org.mozilla.gecko.db.BrowserContract.SyncColumns;
 import org.mozilla.gecko.db.BrowserContract;
+import org.mozilla.gecko.mozglue.GeckoLoader;
 import org.mozilla.gecko.sqlite.SQLiteBridge;
 import org.mozilla.gecko.sqlite.SQLiteBridgeException;
 import org.mozilla.gecko.sync.Utils;
 import org.mozilla.gecko.util.GeckoEventListener;
 
 import android.content.ContentProvider;
 import android.content.ContentUris;
 import android.content.ContentValues;
@@ -110,18 +110,18 @@ public abstract class GeckoProvider exte
     }
 
     private SQLiteBridge getDB(Context context, final String databasePath) {
         SQLiteBridge bridge = null;
 
         boolean dbNeedsSetup = true;
         try {
             String resourcePath = context.getPackageResourcePath();
-            GeckoAppShell.loadSQLiteLibs(context, resourcePath);
-            GeckoAppShell.loadNSSLibs(context, resourcePath);
+            GeckoLoader.loadSQLiteLibs(context, resourcePath);
+            GeckoLoader.loadNSSLibs(context, resourcePath);
             bridge = SQLiteBridge.openDatabase(databasePath, null, 0);
             int version = bridge.getVersion();
             dbNeedsSetup = version != mDBVersion;
         } catch (SQLiteBridgeException ex) {
             // close the database
             if (bridge != null)
                 bridge.close();
 
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/mozglue/GeckoLoader.java.in
@@ -0,0 +1,272 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.gecko.mozglue;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+public final class GeckoLoader {
+    private static final String LOGTAG = "GeckoLoader";
+
+    private static File sCacheFile;
+    private static File sGREDir;
+
+    private static final Object sLibLoadingLock = new Object();
+    // Must hold sLibLoadingLock while accessing the following boolean variables.
+    private static boolean sSQLiteLibsLoaded;
+    private static boolean sNSSLibsLoaded;
+    private static boolean sMozGlueLoaded;
+    private static boolean sLibsSetup;
+
+    private GeckoLoader() {
+        // prevent instantiation
+    }
+
+    public static File getCacheDir(Context context) {
+        if (sCacheFile == null) {
+            sCacheFile = context.getCacheDir();
+        }
+        return sCacheFile;
+    }
+
+    public static File getGREDir(Context context) {
+        if (sGREDir == null) {
+            sGREDir = new File(context.getApplicationInfo().dataDir);
+        }
+        return sGREDir;
+    }
+
+    private static void setupPluginEnvironment(Context context, String[] pluginDirs) {
+        // setup plugin path directories
+        try {
+            // Check to see if plugins were blocked.
+            if (pluginDirs == null) {
+                putenv("MOZ_PLUGINS_BLOCKED=1");
+                putenv("MOZ_PLUGIN_PATH=");
+                return;
+            }
+
+            StringBuffer pluginSearchPath = new StringBuffer();
+            for (int i = 0; i < pluginDirs.length; i++) {
+                pluginSearchPath.append(pluginDirs[i]);
+                pluginSearchPath.append(":");
+            }
+            putenv("MOZ_PLUGIN_PATH="+pluginSearchPath);
+
+            File pluginDataDir = context.getDir("plugins", 0);
+            putenv("ANDROID_PLUGIN_DATADIR=" + pluginDataDir.getPath());
+
+        } catch (Exception ex) {
+            Log.w(LOGTAG, "Caught exception getting plugin dirs.", ex);
+        }
+    }
+
+    private static void setupDownloadEnvironment(Context context) {
+        try {
+            File downloadDir = null;
+            File updatesDir  = null;
+            if (Build.VERSION.SDK_INT >= 8) {
+                downloadDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
+                updatesDir  = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
+            }
+            if (downloadDir == null) {
+                downloadDir = new File(Environment.getExternalStorageDirectory().getPath(), "download");
+            }
+            if (updatesDir == null) {
+                updatesDir = downloadDir;
+            }
+            putenv("DOWNLOADS_DIRECTORY=" + downloadDir.getPath());
+            putenv("UPDATES_DIRECTORY="   + updatesDir.getPath());
+        }
+        catch (Exception e) {
+            Log.w(LOGTAG, "No download directory found.", e);
+        }
+    }
+
+    @SuppressWarnings("deprecation") // Context.MODE_WORLD_* is deprecated in android-17
+    private static File getTmpDir(Context context) {
+        return context.getDir("tmp", Context.MODE_WORLD_READABLE |
+                              Context.MODE_WORLD_WRITEABLE );
+    }
+
+    public static void setupGeckoEnvironment(Context context, String[] pluginDirs, String profilePath) {
+        setupPluginEnvironment(context, pluginDirs);
+        setupDownloadEnvironment(context);
+
+        // profile home path
+        putenv("HOME=" + profilePath);
+
+        // setup the tmp path
+        File f = getTmpDir(context);
+        if (!f.exists()) {
+            f.mkdirs();
+        }
+        putenv("TMPDIR=" + f.getPath());
+
+        // setup the downloads path
+        f = Environment.getDownloadCacheDirectory();
+        putenv("EXTERNAL_STORAGE=" + f.getPath());
+
+        // setup the app-specific cache path
+        f = context.getCacheDir();
+        putenv("CACHE_DIRECTORY=" + f.getPath());
+
+        /* We really want to use this code, but it requires bumping up the SDK to 17 so for now
+           we will use reflection. See https://bugzilla.mozilla.org/show_bug.cgi?id=811763#c11
+        
+        if (Build.VERSION.SDK_INT >= 17) {
+            android.os.UserManager um = (android.os.UserManager)context.getSystemService(Context.USER_SERVICE);
+            if (um != null) {
+                putenv("MOZ_ANDROID_USER_SERIAL_NUMBER=" + um.getSerialNumberForUser(android.os.Process.myUserHandle()));
+            } else {
+                Log.d(LOGTAG, "Unable to obtain user manager service on a device with SDK version " + Build.VERSION.SDK_INT);
+            }
+        }
+        */
+        try {
+            Object userManager = context.getSystemService("user");
+            if (userManager != null) {
+                // if userManager is non-null that means we're running on 4.2+ and so the rest of this
+                // should just work
+                Object userHandle = android.os.Process.class.getMethod("myUserHandle", (Class[])null).invoke(null);
+                Object userSerial = userManager.getClass().getMethod("getSerialNumberForUser", userHandle.getClass()).invoke(userManager, userHandle);
+                putenv("MOZ_ANDROID_USER_SERIAL_NUMBER=" + userSerial.toString());
+            }
+        } catch (Exception e) {
+            // Guard against any unexpected failures
+            Log.d(LOGTAG, "Unable to set the user serial number", e);
+        }
+
+        putLocaleEnv();
+    }
+
+    private static void loadLibsSetup(Context context) {
+        synchronized (sLibLoadingLock) {
+            if (sLibsSetup) {
+                return;
+            }
+            sLibsSetup = true;
+        }
+
+        // The package data lib directory isn't placed in ld.so's
+        // search path, so we have to manually load libraries that
+        // libxul will depend on.  Not ideal.
+
+        File cacheFile = getCacheDir(context);
+        putenv("GRE_HOME=" + getGREDir(context).getPath());
+
+        // setup the libs cache
+        String linkerCache = System.getenv("MOZ_LINKER_CACHE");
+        if (linkerCache == null) {
+            linkerCache = cacheFile.getPath();
+            putenv("MOZ_LINKER_CACHE=" + linkerCache);
+        }
+
+#ifdef MOZ_LINKER_EXTRACT
+        putenv("MOZ_LINKER_EXTRACT=1");
+        // Ensure that the cache dir is world-writable
+        File cacheDir = new File(linkerCache);
+        if (cacheDir.isDirectory()) {
+            cacheDir.setWritable(true, false);
+            cacheDir.setExecutable(true, false);
+            cacheDir.setReadable(true, false);
+        }
+#endif
+    }
+
+    public static void loadSQLiteLibs(Context context, String apkName) {
+        synchronized (sLibLoadingLock) {
+            if (sSQLiteLibsLoaded) {
+                return;
+            }
+            sSQLiteLibsLoaded = true;
+        }
+
+        loadMozGlue(context);
+        // the extract libs parameter is being removed in bug 732069
+        loadLibsSetup(context);
+        loadSQLiteLibsNative(apkName, false);
+    }
+
+    public static void loadNSSLibs(Context context, String apkName) {
+        synchronized (sLibLoadingLock) {
+            if (sNSSLibsLoaded) {
+                return;
+            }
+            sNSSLibsLoaded = true;
+        }
+
+        loadMozGlue(context);
+        loadLibsSetup(context);
+        loadNSSLibsNative(apkName, false);
+    }
+
+    public static void loadMozGlue(Context context) {
+        synchronized (sLibLoadingLock) {
+            if (sMozGlueLoaded) {
+                return;
+            }
+            sMozGlueLoaded = true;
+        }
+
+        System.loadLibrary("mozglue");
+
+        // When running TestPasswordProvider, we're being called with
+        // a GeckoApplication, which is not an Activity
+        if (!(context instanceof Activity))
+            return;
+
+        Intent i = null;
+        i = ((Activity)context).getIntent();
+
+        // if we have an intent (we're being launched by an activity)
+        // read in any environmental variables from it here
+        String env = i.getStringExtra("env0");
+        Log.d(LOGTAG, "Gecko environment env0: "+ env);
+        for (int c = 1; env != null; c++) {
+            putenv(env);
+            env = i.getStringExtra("env" + c);
+            Log.d(LOGTAG, "env" + c + ": " + env);
+        }
+    }
+
+    public static void loadGeckoLibs(Context context, String apkName) {
+        loadLibsSetup(context);
+        loadGeckoLibsNative(apkName);
+    }
+
+    private static void putLocaleEnv() {
+        putenv("LANG=" + Locale.getDefault().toString());
+        NumberFormat nf = NumberFormat.getInstance();
+        if (nf instanceof DecimalFormat) {
+            DecimalFormat df = (DecimalFormat)nf;
+            DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
+
+            putenv("LOCALE_DECIMAL_POINT=" + dfs.getDecimalSeparator());
+            putenv("LOCALE_THOUSANDS_SEP=" + dfs.getGroupingSeparator());
+            putenv("LOCALE_GROUPING=" + (char)df.getGroupingSize());
+        }
+    }
+
+    // These methods are implemented in mozglue/android/nsGeckoUtils.cpp
+    private static native void putenv(String map);
+
+    // These methods are implemented in mozglue/android/APKOpen.cpp
+    public static native void nativeRun(String args);
+    private static native void loadGeckoLibsNative(String apkName);
+    private static native void loadSQLiteLibsNative(String apkName, boolean shouldExtract);
+    private static native void loadNSSLibsNative(String apkName, boolean shouldExtract);
+}
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -585,34 +585,34 @@ loadNSSLibs(const char *apkName)
     __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Couldn't get a handle to libplc4!");
     return FAILURE;
   }
 
   return setup_nss_functions(nss_handle, nspr_handle, plc_handle);
 }
 
 extern "C" NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_loadGeckoLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName)
+Java_org_mozilla_gecko_mozglue_GeckoLoader_loadGeckoLibsNative(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;
 
   int res = loadGeckoLibs(str);
   if (res != SUCCESS) {
     JNI_Throw(jenv, "java/lang/Exception", "Error loading gecko libraries");
   }
   jenv->ReleaseStringUTFChars(jApkName, str);
 }
 
 extern "C" NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
+Java_org_mozilla_gecko_mozglue_GeckoLoader_loadSQLiteLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
   if (jShouldExtract) {
     putenv("MOZ_LINKER_EXTRACT=1");
   }
 
   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);
@@ -624,17 +624,17 @@ Java_org_mozilla_gecko_GeckoAppShell_loa
   if (rv != SUCCESS) {
       JNI_Throw(jenv, "java/lang/Exception", "Error loading sqlite libraries");
   }
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load sqlite done\n");
   jenv->ReleaseStringUTFChars(jApkName, str);
 }
 
 extern "C" NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_loadNSSLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
+Java_org_mozilla_gecko_mozglue_GeckoLoader_loadNSSLibsNative(JNIEnv *jenv, jclass jGeckoAppShellClass, jstring jApkName, jboolean jShouldExtract) {
   if (jShouldExtract) {
     putenv("MOZ_LINKER_EXTRACT=1");
   }
 
   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);
@@ -648,17 +648,17 @@ Java_org_mozilla_gecko_GeckoAppShell_loa
   }
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Load nss done\n");
   jenv->ReleaseStringUTFChars(jApkName, str);
 }
 
 typedef void (*GeckoStart_t)(void *, const nsXREAppData *);
 
 extern "C" NS_EXPORT void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_nativeRun(JNIEnv *jenv, jclass jc, jstring jargs)
+Java_org_mozilla_gecko_mozglue_GeckoLoader_nativeRun(JNIEnv *jenv, jclass jc, jstring jargs)
 {
   GeckoStart_t GeckoStart;
   xul_dlsym("GeckoStart", &GeckoStart);
   if (GeckoStart == NULL)
     return;
   // XXX: java doesn't give us true UTF8, we should figure out something
   // better to do here
   int len = jenv->GetStringUTFLength(jargs);
--- a/mozglue/android/nsGeckoUtils.cpp
+++ b/mozglue/android/nsGeckoUtils.cpp
@@ -12,17 +12,17 @@
 #endif
 
 #include <stdlib.h>
 #include <fcntl.h>
 
 extern "C"
 __attribute__ ((visibility("default")))
 void JNICALL
-Java_org_mozilla_gecko_GeckoAppShell_putenv(JNIEnv *jenv, jclass, jstring map)
+Java_org_mozilla_gecko_mozglue_GeckoLoader_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));