Bug 1524673 - Make Marionette part of remote debugging within GeckoView. r=whimboo,snorp
authorNick Alexander <nalexander@mozilla.com>
Mon, 11 Feb 2019 19:35:30 +0000
changeset 458610 a971c53ea2c08f806d5ea1bca5a3c48d68151749
parent 458609 df00bf94c807e0afdd068f052a9c5752de8314a3
child 458611 37bfe206487bba1d7e25fc82362ec82ae659007b
push id77931
push usernalexander@mozilla.com
push dateMon, 11 Feb 2019 23:37:01 +0000
treeherderautoland@a971c53ea2c0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswhimboo, snorp
bugs1524673
milestone67.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 1524673 - Make Marionette part of remote debugging within GeckoView. r=whimboo,snorp Functionally, we want Marionette to be enabled whenever remote debugging enabled and disabled whenever remote debugging is enabled. That's not particularly well supported by Gecko prefs, so we don't try to handle all situations. We force the Marionette pref whenever the remote debugging pref changes; if consumers get themselves into a bad state by fiddling the Marionette pref independently, that's fine: GeckoView will take back control eventually. There are a couple of wrinkles here. The first is that GeckoView and Marionette race to set themselves up in "profile-after-change". We ensure that both are configured before GeckoView notifies "marionette-startup-requested". The second is that the initial value of the Marionette pref is taken from the environment variable MOZ_MARIONETTE; therefore, we set that variable when starting the Gecko thread. Differential Revision: https://phabricator.services.mozilla.com/D17580
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
mobile/android/modules/geckoview/GeckoViewRemoteDebugger.jsm
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
@@ -124,17 +124,18 @@ public class GeckoThread extends Thread 
     @WrapForJNI
     private static int uiThreadId;
 
     private static TelemetryUtils.Timer sInitTimer;
 
     // Main process parameters
     public static final int FLAG_DEBUGGING = 1 << 0; // Debugging mode.
     public static final int FLAG_PRELOAD_CHILD = 1 << 1; // Preload child during main thread start.
-    public static final int FLAG_ENABLE_NATIVE_CRASHREPORTER = 1 << 2; // Enable native crash reporting
+    public static final int FLAG_ENABLE_NATIVE_CRASHREPORTER = 1 << 2; // Enable native crash reporting.
+    public static final int FLAG_ENABLE_MARIONETTE = 1 << 3; // Enable Marionette at startup.
 
     public static final long DEFAULT_TIMEOUT = 5000;
 
     /* package */ static final String EXTRA_ARGS = "args";
     private static final String EXTRA_PREFS_FD = "prefsFd";
     private static final String EXTRA_PREF_MAP_FD = "prefMapFd";
     private static final String EXTRA_IPC_FD = "ipcFd";
     private static final String EXTRA_CRASH_FD = "crashFd";
@@ -456,16 +457,22 @@ public class GeckoThread extends Thread 
         // In Gecko, the native crash reporter is enabled by default in opt builds, and
         // disabled by default in debug builds.
         if ((mInitInfo.flags & FLAG_ENABLE_NATIVE_CRASHREPORTER) == 0 && !BuildConfig.DEBUG_BUILD) {
             env.add(0, "MOZ_CRASHREPORTER_DISABLE=1");
         } else if ((mInitInfo.flags & FLAG_ENABLE_NATIVE_CRASHREPORTER) != 0 && BuildConfig.DEBUG_BUILD) {
             env.add(0, "MOZ_CRASHREPORTER=1");
         }
 
+        if (!isChildProcess() && ((mInitInfo.flags & FLAG_ENABLE_MARIONETTE) != 0)) {
+            // The presence of this environment variable determines the initial
+            // value of `marionette.enabled`.
+            env.add(0, "MOZ_MARIONETTE=1");
+        }
+
         GeckoLoader.setupGeckoEnvironment(context, context.getFilesDir().getPath(), env, mInitInfo.prefs);
 
         // And go.
         GeckoLoader.nativeRun(args,
                               mInitInfo.extras.getInt(EXTRA_PREFS_FD, -1),
                               mInitInfo.extras.getInt(EXTRA_PREF_MAP_FD, -1),
                               mInitInfo.extras.getInt(EXTRA_IPC_FD, -1),
                               mInitInfo.extras.getInt(EXTRA_CRASH_FD, -1),
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
@@ -182,16 +182,20 @@ public final class GeckoRuntime implemen
         if (settings.getUseContentProcessHint()) {
             flags |= GeckoThread.FLAG_PRELOAD_CHILD;
         }
 
         if (settings.getPauseForDebuggerEnabled()) {
             flags |= GeckoThread.FLAG_DEBUGGING;
         }
 
+        if (settings.getRemoteDebuggingEnabled()) {
+            flags |= GeckoThread.FLAG_ENABLE_MARIONETTE;
+        }
+
         final Class<?> crashHandler = settings.getCrashHandler();
         if (crashHandler != null) {
             try {
                 final ServiceInfo info = context.getPackageManager().getServiceInfo(new ComponentName(context, crashHandler), 0);
                 if (info.processName.equals(getProcessName(context))) {
                     throw new IllegalArgumentException("Crash handler service must run in a separate process");
                 }
 
--- a/mobile/android/modules/geckoview/GeckoViewRemoteDebugger.jsm
+++ b/mobile/android/modules/geckoview/GeckoViewRemoteDebugger.jsm
@@ -42,16 +42,35 @@ var GeckoViewRemoteDebugger = {
       this.onDisable();
     }
   },
 
   onInit() {
     debug `onInit`;
     this._isEnabled = false;
     this._usbDebugger = new USBRemoteDebugger();
+
+    // For GeckoView-consuming Apps (including Fennec), we want "remote
+    // debugging" to encapsulate "Marionette" completely.  It's possible for
+    // consumers to manage the Marionette pref independently, but we don't
+    // condone or accommodate such management.
+    Services.prefs.setBoolPref("marionette.enabled", false);
+
+    // We never want Marionette to set prefs recommended for automation.
+    Services.prefs.setBoolPref("marionette.prefs.recommended", false);
+
+    // This lets Marionette start listening (when it's enabled).  Both
+    // GeckoView and Marionette do most of their initialization in
+    // "profile-after-change", and there is no order enforced between
+    // them.  Therefore we defer asking Marionette to startup until
+    // after all "profile-after-change" handlers (including this one)
+    // have completed.
+    Services.tm.dispatchToMainThread(() => {
+        Services.obs.notifyObservers(null, "marionette-startup-requested");
+    });
   },
 
   onEnable() {
     if (this._isEnabled) {
       return;
     }
 
     debug `onEnable`;
@@ -70,34 +89,38 @@ var GeckoViewRemoteDebugger = {
     // If package name isn't available, it will be "@firefox-debugger-socket".
 
     const env = Cc["@mozilla.org/process/environment;1"]
               .getService(Ci.nsIEnvironment);
     let packageName = env.get("MOZ_ANDROID_PACKAGE_NAME");
     if (packageName) {
       packageName = packageName + "/";
     } else {
-      warn `Missing env MOZ_ANDROID_PACKAGE_NAME. Unable to get pacakge name`;
+      warn `Missing env MOZ_ANDROID_PACKAGE_NAME. Unable to get package name`;
     }
 
     this._isEnabled = true;
     this._usbDebugger.stop();
 
     const portOrPath = packageName + "firefox-debugger-socket";
     this._usbDebugger.start(portOrPath);
+
+    Services.prefs.setBoolPref("marionette.enabled", true);
   },
 
   onDisable() {
     if (!this._isEnabled) {
       return;
     }
 
     debug `onDisable`;
     this._isEnabled = false;
     this._usbDebugger.stop();
+
+    Services.prefs.setBoolPref("marionette.enabled", false);
   },
 };
 
 class USBRemoteDebugger {
   start(aPortOrPath) {
     try {
       const AuthenticatorType = DebuggerServer.Authenticators.get("PROMPT");
       const authenticator = new AuthenticatorType.Server();