Bug 1404144 - 3. Add flag to preload child process during main GeckoThread startup; r?snorp
We need to wait for GeckoThread to load the Gecko libs in the main
process before we can launch any child processes, so that the child
process doesn't try to extract libs, which can conflict with any
extraction going on in the main process.
MozReview-Commit-ID: 2gUd2R1TUBI
--- a/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/GeckoApp.java
@@ -1126,20 +1126,20 @@ public abstract class GeckoApp extends G
// also happen if we're not the first activity to run within a session.
mIsRestoringActivity = true;
Telemetry.addToHistogram("FENNEC_RESTORING_ACTIVITY", 1);
} else {
final String action = intent.getAction();
final String args = GeckoApplication.addDefaultGeckoArgs(
intent.getStringExtra("args"));
+ final int flags = ACTION_DEBUG.equals(action) ? GeckoThread.FLAG_DEBUGGING : 0;
sAlreadyLoaded = true;
- GeckoThread.initMainProcess(/* profile */ null, args,
- /* debugging */ ACTION_DEBUG.equals(action));
+ GeckoThread.initMainProcess(/* profile */ null, args, flags);
// Speculatively pre-fetch the profile in the background.
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
getProfile();
}
});
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
@@ -3,16 +3,17 @@
* 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.annotation.RobocopTarget;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.mozglue.GeckoLoader;
+import org.mozilla.gecko.process.GeckoProcessManager;
import org.mozilla.gecko.util.GeckoBundle;
import org.mozilla.gecko.util.FileUtils;
import org.mozilla.gecko.util.ThreadUtils;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Handler;
@@ -111,65 +112,68 @@ public class GeckoThread extends Thread
private static MessageQueue msgQueue;
@WrapForJNI
private static int uiThreadId;
private boolean mInitialized;
private String[] mArgs;
// Main process parameters
+ public static final int FLAG_DEBUGGING = 1; // Debugging mode.
+ public static final int FLAG_PRELOAD_CHILD = 2; // Preload child during main thread start.
+
private GeckoProfile mProfile;
private String mExtraArgs;
- private boolean mDebugging;
+ private int mFlags;
// Child process parameters
private int mCrashFileDescriptor = -1;
private int mIPCFileDescriptor = -1;
GeckoThread() {
setName("Gecko");
}
@WrapForJNI
private static boolean isChildProcess() {
return INSTANCE.mIPCFileDescriptor != -1;
}
private synchronized boolean init(final GeckoProfile profile, final String[] args,
- final String extraArgs, final boolean debugging,
+ final String extraArgs, final int flags,
final int crashFd, final int ipcFd) {
ThreadUtils.assertOnUiThread();
uiThreadId = android.os.Process.myTid();
if (mInitialized) {
return false;
}
mProfile = profile;
mArgs = args;
mExtraArgs = extraArgs;
- mDebugging = debugging;
+ mFlags = flags;
mCrashFileDescriptor = crashFd;
mIPCFileDescriptor = ipcFd;
mInitialized = true;
notifyAll();
return true;
}
public static boolean initMainProcess(final GeckoProfile profile, final String extraArgs,
- final boolean debugging) {
- return INSTANCE.init(profile, /* args */ null, extraArgs, debugging,
+ final int flags) {
+ return INSTANCE.init(profile, /* args */ null, extraArgs, flags,
/* crashFd */ -1, /* ipcFd */ -1);
}
public static boolean initChildProcess(final String[] args, final int crashFd,
final int ipcFd) {
return INSTANCE.init(/* profile */ null, args, /* extraArgs */ null,
- /* debugging */ false, crashFd, ipcFd);
+ /* flags */ 0, crashFd, ipcFd);
}
private static boolean canUseProfile(final Context context, final GeckoProfile profile,
final String profileName, final File profileDir) {
if (profileDir != null && !profileDir.isDirectory()) {
return false;
}
@@ -214,17 +218,17 @@ public class GeckoThread extends Thread
if (profile != null) {
// We already have a compatible profile.
return true;
}
// We haven't initialized yet; okay to initialize now.
return initMainProcess(GeckoProfile.get(context, profileName, profileDir),
- args, /* debugging */ false);
+ args, /* flags */ 0);
}
public static boolean launch() {
ThreadUtils.assertOnUiThread();
if (checkAndSetState(State.INITIAL, State.LAUNCHED)) {
INSTANCE.start();
return true;
@@ -359,38 +363,48 @@ public class GeckoThread extends Thread
// Keep this IdleHandler
return true;
}
};
Looper.myQueue().addIdleHandler(idleHandler);
initGeckoEnvironment();
+ if ((mFlags & FLAG_PRELOAD_CHILD) != 0) {
+ ThreadUtils.postToBackgroundThread(new Runnable() {
+ @Override
+ public void run() {
+ // Preload the content ("tab") child process.
+ GeckoProcessManager.getInstance().preload("tab");
+ }
+ });
+ }
+
// Wait until initialization before calling Gecko entry point.
synchronized (this) {
while (!mInitialized) {
try {
wait();
} catch (final InterruptedException e) {
}
}
}
final String[] args = isChildProcess() ? mArgs : getMainProcessArgs();
- if (mDebugging) {
+ if ((mFlags & FLAG_DEBUGGING) != 0) {
try {
Thread.sleep(5 * 1000 /* 5 seconds */);
} catch (final InterruptedException e) {
}
}
Log.w(LOGTAG, "zerdatime " + SystemClock.elapsedRealtime() + " - runGecko");
- if (mDebugging) {
+ if ((mFlags & FLAG_DEBUGGING) != 0) {
Log.i(LOGTAG, "RunGecko - args = " + TextUtils.join(" ", args));
}
// And go.
GeckoLoader.nativeRun(args, mCrashFileDescriptor, mIPCFileDescriptor);
// And... we're done.
final boolean restarting = isState(State.RESTARTING);
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoView.java
@@ -15,16 +15,17 @@ import java.util.Set;
import org.mozilla.gecko.annotation.ReflectionTarget;
import org.mozilla.gecko.annotation.WrapForJNI;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.mozglue.JNIObject;
import org.mozilla.gecko.util.ActivityUtils;
import org.mozilla.gecko.util.BundleEventListener;
import org.mozilla.gecko.util.EventCallback;
import org.mozilla.gecko.util.GeckoBundle;
+import org.mozilla.gecko.util.ThreadUtils;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.database.Cursor;
import android.net.Uri;
@@ -457,41 +458,44 @@ public class GeckoView extends LayerView
}
/**
* Preload GeckoView by starting Gecko in the background, if Gecko is not already running.
*
* @param context Activity or Application Context for starting GeckoView.
*/
public static void preload(final Context context) {
- preload(context, /* geckoArgs */ null);
+ preload(context, /* geckoArgs */ null, /* multiprocess */ false);
}
/**
* Preload GeckoView by starting Gecko with the specified arguments in the background,
* if Gecko is not already running.
*
* @param context Activity or Application Context for starting GeckoView.
- * @param geckoArgs Arguments to be passed to Gecko, if Gecko is not already running
+ * @param geckoArgs Arguments to be passed to Gecko, if Gecko is not already running.
+ * @param multiprocess True if child process in multiprocess mode should be preloaded.
*/
- public static void preload(final Context context, final String geckoArgs) {
+ public static void preload(final Context context, final String geckoArgs,
+ final boolean multiprocess) {
final Context appContext = context.getApplicationContext();
if (GeckoAppShell.getApplicationContext() == null) {
GeckoAppShell.setApplicationContext(appContext);
}
- if (GeckoThread.initMainProcess(/* profile */ null,
- geckoArgs,
- /* debugging */ false)) {
+ final int flags = multiprocess ? GeckoThread.FLAG_PRELOAD_CHILD : 0;
+ if (GeckoThread.initMainProcess(/* profile */ null, geckoArgs, flags)) {
GeckoThread.launch();
}
}
private void init(final Context context, final GeckoViewSettings settings) {
- preload(context);
+ final boolean multiprocess = settings != null &&
+ settings.getBoolean(GeckoViewSettings.USE_MULTIPROCESS);
+ preload(context, /* geckoArgs */ null, multiprocess);
initializeView();
mListener.registerListeners();
if (settings == null) {
mSettings = new GeckoViewSettings(getEventDispatcher());
} else {
mSettings = settings;