Bug 1546135 - [geckoview] Use flags in WebExtension constructor. r=esawin,snorp
☠☠ backed out by 358171d00f9a ☠ ☠
authorAgi Sferro <agi@sferro.dev>
Tue, 23 Apr 2019 22:58:50 +0000
changeset 470575 a322ec5c25e6e6ebe0e0bc11c281162408c95982
parent 470574 44a66721dea767d7b832c7b5665121fad4205fe2
child 470576 a66f1ffd23ea29db37a0f1b11141c1fe6699dddb
push id35908
push useraciure@mozilla.com
push dateWed, 24 Apr 2019 04:28:40 +0000
treeherdermozilla-central@c9f0730a57a6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersesawin, snorp
bugs1546135
milestone68.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 1546135 - [geckoview] Use flags in WebExtension constructor. r=esawin,snorp Differential Revision: https://phabricator.services.mozilla.com/D28365
mobile/android/geckoview/api.txt
mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExtensionTest.kt
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtensionEventDispatcher.java
mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
--- a/mobile/android/geckoview/api.txt
+++ b/mobile/android/geckoview/api.txt
@@ -1048,24 +1048,30 @@ package org.mozilla.geckoview {
 
   public final class StorageController {
     ctor public StorageController();
     method @AnyThread public void clearAllSessionContextData();
     method @AnyThread public void clearSessionContextData(@NonNull String);
   }
 
   public class WebExtension {
-    ctor public WebExtension(@NonNull String, @NonNull String, boolean);
+    ctor public WebExtension(@NonNull String, @NonNull String, long);
     ctor public WebExtension(@NonNull String);
     method @UiThread public void setMessageDelegate(@Nullable WebExtension.MessageDelegate, @NonNull String);
-    field public final boolean allowContentMessaging;
+    field public final long flags;
     field @NonNull public final String id;
     field @NonNull public final String location;
   }
 
+  public static class WebExtension.Flags {
+    ctor protected Flags();
+    field public static final long ALLOW_CONTENT_MESSAGING = 1L;
+    field public static final long NONE = 0L;
+  }
+
   @UiThread public static interface WebExtension.MessageDelegate {
     method @Nullable default public void onConnect(@NonNull WebExtension.Port);
     method @Nullable default public GeckoResult<Object> onMessage(@NonNull Object, @NonNull WebExtension.MessageSender);
   }
 
   @UiThread public static class WebExtension.MessageSender {
     ctor protected MessageSender();
     method public boolean isTopLevel();
--- a/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExtensionTest.kt
+++ b/mobile/android/geckoview/src/androidTest/java/org/mozilla/geckoview/test/WebExtensionTest.kt
@@ -105,30 +105,40 @@ class WebExtensionTest : BaseSessionTest
                             message as String, equalTo("response: ${prefix}MessageResponse"))
                     messageResult.complete(null)
                     completed = true
                 }
                 return null
             }
         }
 
-        val messaging = WebExtension(if (background) MESSAGING_BACKGROUND else MESSAGING_CONTENT,
-                "{${UUID.randomUUID()}}", !background)
-        if (background) {
-            messaging.setMessageDelegate(messageDelegate, "browser")
-        } else {
-            sessionRule.session.setMessageDelegate(messageDelegate, "browser");
-        }
-
+        val messaging = createWebExtension(background, messageDelegate)
         sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
         sessionRule.waitForResult(messageResult)
 
         sessionRule.waitForResult(sessionRule.runtime.unregisterWebExtension(messaging))
     }
 
+    private fun createWebExtension(background: Boolean,
+                                   messageDelegate: WebExtension.MessageDelegate): WebExtension {
+        val webExtension: WebExtension
+        val uuid = "{${UUID.randomUUID()}}"
+
+        if (background) {
+            webExtension = WebExtension(MESSAGING_BACKGROUND, uuid, WebExtension.Flags.NONE)
+            webExtension.setMessageDelegate(messageDelegate, "browser")
+        } else {
+            webExtension = WebExtension(MESSAGING_CONTENT, uuid,
+                    WebExtension.Flags.ALLOW_CONTENT_MESSAGING)
+            sessionRule.session.setMessageDelegate(messageDelegate, "browser");
+        }
+
+        return webExtension
+    }
+
     @Test
     @WithDevToolsAPI
     fun contentMessaging() {
         mainSession.loadUri("example.com")
         sessionRule.waitForPageStop()
         testOnMessage(false)
     }
 
@@ -187,23 +197,17 @@ class WebExtensionTest : BaseSessionTest
 
             override fun onMessage(message: Any,
                                    sender: WebExtension.MessageSender): GeckoResult<Any>? {
                 // Ignored for this test
                 return null
             }
         }
 
-        val messaging = WebExtension(if (background) MESSAGING_BACKGROUND else MESSAGING_CONTENT,
-                "{${UUID.randomUUID()}}", !background)
-        if (background) {
-            messaging.setMessageDelegate(messageDelegate, "browser")
-        } else {
-            sessionRule.session.setMessageDelegate(messageDelegate, "browser");
-        }
+        val messaging = createWebExtension(background, messageDelegate)
 
         sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
         sessionRule.waitForResult(result)
         sessionRule.waitForResult(sessionRule.runtime.unregisterWebExtension(messaging))
     }
 
     @Test
     @WithDevToolsAPI
@@ -275,23 +279,17 @@ class WebExtensionTest : BaseSessionTest
                                    sender: WebExtension.MessageSender): GeckoResult<Any>? {
                 Assert.assertEquals(messaging, sender.webExtension)
 
                 // Ignored for this test
                 return null
             }
         }
 
-        messaging = WebExtension(if (background) MESSAGING_BACKGROUND else MESSAGING_CONTENT,
-                "{${UUID.randomUUID()}}", !background)
-        if (background) {
-            messaging.setMessageDelegate(messageDelegate, "browser")
-        } else {
-            sessionRule.session.setMessageDelegate(messageDelegate, "browser");
-        }
+        messaging = createWebExtension(background, messageDelegate)
 
         sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
         sessionRule.waitForResult(result)
         sessionRule.waitForResult(sessionRule.runtime.unregisterWebExtension(messaging))
     }
 
     @Test
     @WithDevToolsAPI
@@ -361,23 +359,17 @@ class WebExtensionTest : BaseSessionTest
                         result.complete(null)
                     }
                 }
 
                 return null
             }
         }
 
-        messaging = WebExtension(if (background) MESSAGING_BACKGROUND else MESSAGING_CONTENT,
-                "{${UUID.randomUUID()}}", !background)
-        if (background) {
-            messaging.setMessageDelegate(messageDelegate, "browser")
-        } else {
-            sessionRule.session.setMessageDelegate(messageDelegate, "browser");
-        }
+        messaging = createWebExtension(background, messageDelegate)
 
         sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
         sessionRule.waitForResult(result)
         sessionRule.waitForResult(sessionRule.runtime.unregisterWebExtension(messaging))
     }
 
     @Test
     @WithDevToolsAPI
@@ -436,17 +428,17 @@ class WebExtensionTest : BaseSessionTest
                     fail()
                 }
 
                 return null
             }
         }
 
         messaging = WebExtension("resource://android/assets/web_extensions/messaging-iframe/",
-                "{${UUID.randomUUID()}}", true)
+                "{${UUID.randomUUID()}}", WebExtension.Flags.ALLOW_CONTENT_MESSAGING)
         sessionRule.session.setMessageDelegate(messageDelegate, "browser");
 
         sessionRule.waitForResult(sessionRule.runtime.registerWebExtension(messaging))
         sessionRule.waitForResult(portTopLevel)
         sessionRule.waitForResult(portIframe)
         sessionRule.waitForResult(messageTopLevel)
         sessionRule.waitForResult(messageIframe)
         sessionRule.waitForResult(sessionRule.runtime.unregisterWebExtension(messaging))
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java
@@ -335,17 +335,18 @@ public final class GeckoRuntime implemen
             public void sendSuccess(final Object response) {
                 complete(null);
             }
         };
 
         final GeckoBundle bundle = new GeckoBundle(3);
         bundle.putString("locationUri", webExtension.location);
         bundle.putString("id", webExtension.id);
-        bundle.putBoolean("allowContentMessaging", webExtension.allowContentMessaging);
+        bundle.putBoolean("allowContentMessaging",
+                (webExtension.flags & WebExtension.Flags.ALLOW_CONTENT_MESSAGING) > 0);
 
         mWebExtensionDispatcher.registerWebExtension(webExtension);
 
         EventDispatcher.getInstance().dispatch("GeckoView:RegisterWebExtension",
                 bundle, result);
 
         return result;
     }
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoSession.java
@@ -396,17 +396,17 @@ public class GeckoSession implements Par
      * If a delegate is already present, this delegate will replace the
      * existing one.
      *
      * This message delegate will be responsible for handling messaging between
      * a WebExtension content script running on the {@link GeckoSession}.
      *
      * Note: To receive messages from content scripts, the WebExtension needs
      * to explicitely allow it in {@link WebExtension#WebExtension} by setting
-     * {@link WebExtension#allowContentMessaging} to <code>true</code>.
+     * {@link WebExtension.Flags#ALLOW_CONTENT_MESSAGING}.
      *
      * @param delegate {@link WebExtension.MessageDelegate} that will receive
      *                 messages from this session.
      * @param nativeApp which native app id this message delegate will handle
      *                  messaging for.
      * @see WebExtension#setMessageDelegate
      */
     @AnyThread
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtension.java
@@ -6,16 +6,18 @@ import android.support.annotation.Nullab
 import android.support.annotation.UiThread;
 import android.util.Log;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.util.GeckoBundle;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.UUID;
 
 /**
  * Represents a WebExtension that may be used by GeckoView.
  */
@@ -34,26 +36,47 @@ public class WebExtension {
      * <code>/assets/web_extensions/my_webextension/</code> in the APK.
      */
     public final @NonNull String location;
     /**
      * Unique identifier for this WebExtension
      */
     public final @NonNull String id;
     /**
-     * Whether content scripts can send messages to the browser or not.
+     * {@link Flags} for this WebExtension.
      */
-    public final boolean allowContentMessaging;
+    public final @WebExtensionFlags long flags;
     /**
      * Delegates that handle messaging between this WebExtension and the app.
      */
     /* package */ final @NonNull Map<String, MessageDelegate> messageDelegates;
 
     private final static String LOGTAG = "WebExtension";
 
+    public static class Flags {
+        /*
+         * Default flags for this WebExtension.
+         */
+        public static final long NONE = 0;
+        /**
+         * Set this flag if you want to enable content scripts messaging.
+         * To listen to such messages you can use
+         * {@link WebExtension#setMessageDelegate}.
+         */
+        public static final long ALLOW_CONTENT_MESSAGING = 1 << 0;
+
+        // Do not instantiate this class.
+        protected Flags() {}
+    }
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(flag = true,
+            value = { Flags.NONE, Flags.ALLOW_CONTENT_MESSAGING })
+    /* package */ @interface WebExtensionFlags {}
+
     /**
      * Builds a WebExtension instance that can be loaded in GeckoView using
      * {@link GeckoRuntime#registerWebExtension}
      *
      * @param location The WebExtension install location. It must be either a
      *                 <code>resource:</code> URI to a folder inside the APK or
      *                 a <code>file:</code> URL to a <code>.xpi</code> file.
      * @param id Unique identifier for this WebExtension. This identifier must
@@ -90,42 +113,40 @@ public class WebExtension {
      *           See also: <ul>
      *           <li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/browser_specific_settings">
      *                  WebExtensions/manifest.json/browser_specific_settings
      *               </a>
      *           <li><a href="https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/WebExtensions_and_the_Add-on_ID#When_do_you_need_an_add-on_ID">
      *                  WebExtensions/WebExtensions_and_the_Add-on_ID
      *               </a>
      *           </ul>
-     * @param allowContentMessaging Whether content scripts are allowed to send
-     *      messages to the browser or not.  To listen to such messages you can
-     *      use {@link #setMessageDelegate(MessageDelegate, String)}.
+     * @param flags {@link Flags} for this WebExtension.
      */
     public WebExtension(final @NonNull String location, final @NonNull String id,
-                        final boolean allowContentMessaging) {
+                        final @WebExtensionFlags long flags) {
         this.location = location;
         this.id = id;
-        this.allowContentMessaging = allowContentMessaging;
+        this.flags = flags;
         this.messageDelegates = new HashMap<>();
     }
 
     /**
      * Builds a WebExtension instance that can be loaded in GeckoView using
      * {@link GeckoRuntime#registerWebExtension}
      * The <code>id</code> for this web extension will be automatically
      * generated.
      *
      * All messaging from the web extension will be ignored.
      *
      * @param location The WebExtension install location. It must be either a
      *                 <code>resource:</code> URI to a folder inside the APK or
      *                 a <code>file:</code> URL to a <code>.xpi</code> file.
      */
     public WebExtension(final @NonNull String location) {
-        this(location, "{" + UUID.randomUUID().toString() + "}", false);
+        this(location, "{" + UUID.randomUUID().toString() + "}", Flags.NONE);
     }
 
     /**
      * Defines the message delegate for a Native App.
      *
      * This message delegate will receive messages from the background script
      * for the native app specified in <code>nativeApp</code>.
      *
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtensionEventDispatcher.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/WebExtensionEventDispatcher.java
@@ -139,17 +139,17 @@ import java.util.Map;
         if (callback != null) {
             callback.sendSuccess(true);
         }
     }
 
     private WebExtension.MessageDelegate getDelegate(
             final String nativeApp, final WebExtension.MessageSender sender,
             final EventCallback callback) {
-        if (!sender.webExtension.allowContentMessaging &&
+        if ((sender.webExtension.flags & WebExtension.Flags.ALLOW_CONTENT_MESSAGING) == 0 &&
                 sender.environmentType == WebExtension.MessageSender.ENV_TYPE_CONTENT_SCRIPT) {
             callback.sendError("This NativeApp can't receive messages from Content Scripts.");
             return null;
         }
 
         WebExtension.MessageDelegate delegate = null;
 
         if (sender.session != null) {
--- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/doc-files/CHANGELOG.md
@@ -299,9 +299,9 @@ exclude: true
 [65.23]: ../GeckoSession.FinderResult.html
 
 - Update [`CrashReporter#sendCrashReport`][65.24] to return the crash ID as a
   [`GeckoResult<String>`][65.25].
 
 [65.24]: ../CrashReporter.html#sendCrashReport-android.content.Context-android.os.Bundle-java.lang.String-
 [65.25]: ../GeckoResult.html
 
-[api-version]: 3b910c2e6b3df9bd9926cf4e54b37a5a08bdb64a
+[api-version]: d51e6bd6f7fe004cbe5856e892ec538e2404c3fc