From 7ea21d9c6cfae7fbdea5f33906b3ad99de4d711e Mon Sep 17 00:00:00 2001 From: Luca Greco Date: Sat, 19 Aug 2023 17:22:04 +0000 Subject: [PATCH] Bug 1843926 - Add a new ExtensionsProcessEnabled GeckoRuntimeSettings and expose it in GeckoViewExample Settings UI. r=amejiamarmol,geckoview-reviewers,zmckenney Differential Revision: https://phabricator.services.mozilla.com/D183779 --- mobile/android/geckoview/api.txt | 3 + .../geckoview/test/WebExtensionTest.kt | 35 +++++++++ .../geckoview/GeckoRuntimeSettings.java | 34 +++++++++ .../mozilla/geckoview/RuntimeSettings.java | 75 +++++++++++++++++-- .../mozilla/geckoview/doc-files/CHANGELOG.md | 4 +- .../geckoview_example/GeckoViewActivity.java | 12 +++ .../src/main/res/values/strings.xml | 3 + .../src/main/res/xml/settings.xml | 4 + 8 files changed, 164 insertions(+), 6 deletions(-) diff --git a/mobile/android/geckoview/api.txt b/mobile/android/geckoview/api.txt index 5f686cbc6337..03610a90a6da 100644 --- a/mobile/android/geckoview/api.txt +++ b/mobile/android/geckoview/api.txt @@ -835,6 +835,7 @@ package org.mozilla.geckoview { method public boolean getDoubleTapZoomingEnabled(); method public boolean getEnterpriseRootsEnabled(); method @AnyThread @Nullable public ExperimentDelegate getExperimentDelegate(); + method @Nullable public Boolean getExtensionsProcessEnabled(); method public boolean getExtensionsWebAPIEnabled(); method @NonNull public Bundle getExtras(); method public boolean getFontInflationEnabled(); @@ -861,6 +862,7 @@ package org.mozilla.geckoview { method @NonNull public GeckoRuntimeSettings setConsoleOutputEnabled(boolean); method @NonNull public GeckoRuntimeSettings setDoubleTapZoomingEnabled(boolean); method @NonNull public GeckoRuntimeSettings setEnterpriseRootsEnabled(boolean); + method @NonNull public GeckoRuntimeSettings setExtensionsProcessEnabled(boolean); method @NonNull public GeckoRuntimeSettings setExtensionsWebAPIEnabled(boolean); method @NonNull public GeckoRuntimeSettings setFontInflationEnabled(boolean); method @NonNull public GeckoRuntimeSettings setFontSizeFactor(float); @@ -900,6 +902,7 @@ package org.mozilla.geckoview { method @NonNull public GeckoRuntimeSettings.Builder doubleTapZoomingEnabled(boolean); method @NonNull public GeckoRuntimeSettings.Builder enterpriseRootsEnabled(boolean); method @AnyThread @NonNull public GeckoRuntimeSettings.Builder experimentDelegate(@Nullable ExperimentDelegate); + method @NonNull public GeckoRuntimeSettings.Builder extensionsProcessEnabled(boolean); method @NonNull public GeckoRuntimeSettings.Builder extensionsWebAPIEnabled(boolean); method @NonNull public GeckoRuntimeSettings.Builder extras(@NonNull Bundle); method @NonNull public GeckoRuntimeSettings.Builder fontInflation(boolean); diff --git 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 index 14415db892cb..a12872a3e7a9 100644 --- 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 @@ -3091,4 +3091,39 @@ class WebExtensionTest : BaseSessionTest() { equalTo(geckoPrefs[0] as Boolean), ) } + + @Test + fun testExtensionsProcessDisabledByDefault() { + val settings = GeckoRuntimeSettings.Builder() + .build() + + assertThat( + "extensionsProcessEnabled setting default should be null", + settings.extensionsProcessEnabled, + equalTo(null), + ) + + val geckoPrefs = sessionRule.getPrefs( + "extensions.webextensions.remote", + ) + + assertThat( + "extensions.webextensions.remote pref default value should be false", + geckoPrefs[0] as Boolean, + equalTo(false), + ) + } + + @Test + fun testExtensionsProcessControlledFromSettings() { + val settings = GeckoRuntimeSettings.Builder() + .extensionsProcessEnabled(true) + .build() + + assertThat( + "extensionsProcessEnabled setting should be set to true", + settings.extensionsProcessEnabled, + equalTo(true), + ) + } } diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java index cbaea3ddf1c0..0e0ad20e7870 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntimeSettings.java @@ -85,6 +85,18 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { return this; } + /** + * Set whether Extensions Process support should be enabled. + * + * @param flag A flag determining whether Extensions Process support should be enabled. Default + * is false. + * @return This Builder instance. + */ + public @NonNull Builder extensionsProcessEnabled(final boolean flag) { + getSettings().mExtensionsProcess.set(flag); + return this; + } + /** * Set whether JavaScript support should be enabled. * @@ -528,6 +540,8 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { /* package */ final Pref mProcessCount = new Pref<>("dom.ipc.processCount", 2); /* package */ final Pref mExtensionsWebAPIEnabled = new Pref<>("extensions.webapi.enabled", false); + /* package */ final PrefWithoutDefault mExtensionsProcess = + new PrefWithoutDefault("extensions.webextensions.remote"); /* package */ int mPreferredColorScheme = COLOR_SCHEME_SYSTEM; @@ -657,6 +671,26 @@ public final class GeckoRuntimeSettings extends RuntimeSettings { return this; } + /** + * Get whether Extensions Process support is enabled. + * + * @return Whether Extensions Process support is enabled. + */ + public @Nullable Boolean getExtensionsProcessEnabled() { + return mExtensionsProcess.get(); + } + + /** + * Set whether Extensions Process support should be enabled. + * + * @param flag A flag determining whether Extensions Process support should be enabled. + * @return This GeckoRuntimeSettings instance. + */ + public @NonNull GeckoRuntimeSettings setExtensionsProcessEnabled(final boolean flag) { + mExtensionsProcess.commit(flag); + return this; + } + /** * Get whether remote debugging support is enabled. * diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/RuntimeSettings.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/RuntimeSettings.java index 299dec95f133..de981319086f 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/RuntimeSettings.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/RuntimeSettings.java @@ -109,6 +109,10 @@ public abstract class RuntimeSettings implements Parcelable { return mIsSet; } + public boolean hasDefault() { + return true; + } + public void reset() { mValue = defaultValue; mIsSet = false; @@ -128,6 +132,48 @@ public abstract class RuntimeSettings implements Parcelable { } } + /** + * Used to handle pref-based settings that should not have a default value, so that they will be + * controlled by GeckoView only when they are set. + * + *

When no value is set for a PrefWithoutDefault, its value on the GeckoView side is expected + * to be null, and the value set on the Gecko side to stay set to the either the prefs file + * included in the GeckoView build, or the user prefs file created by the xpcshell and mochitest + * test harness. + */ + /* package */ class PrefWithoutDefault extends Pref { + public PrefWithoutDefault(@NonNull final String name) { + super(name, null); + } + + public boolean hasDefault() { + return false; + } + + public @Nullable T get() { + if (!isSet()) { + return null; + } + return super.get(); + } + + public void commit() { + if (!isSet()) { + // Only add to the bundle prefs and + // propagate to Gecko when explicitly set. + return; + } + super.commit(); + } + + private void addToBundle(final GeckoBundle bundle) { + if (!isSet()) { + return; + } + super.addToBundle(bundle); + } + } + private RuntimeSettings mParent; private final ArrayList mChildren; private final ArrayList> mPrefs; @@ -231,7 +277,15 @@ public abstract class RuntimeSettings implements Parcelable { */ /* package */ void commitResetPrefs() { final ArrayList names = new ArrayList(); - forAllPrefs(pref -> names.add(pref.name)); + forAllPrefs( + pref -> { + // Do not reset prefs that don't have a default value + // and are not set. + if (!pref.hasDefault() && !pref.isSet()) { + return; + } + names.add(pref.name); + }); final GeckoBundle data = new GeckoBundle(1); data.putStringArray("names", names); @@ -257,10 +311,21 @@ public abstract class RuntimeSettings implements Parcelable { @SuppressWarnings("checkstyle:javadocmethod") public void readFromParcel(final @NonNull Parcel source) { for (final Pref pref : mPrefs) { - // We know this is safe. - @SuppressWarnings("unchecked") - final Pref uncheckedPref = (Pref) pref; - uncheckedPref.commit(source.readValue(getClass().getClassLoader())); + if (pref.hasDefault()) { + // We know this is safe. + @SuppressWarnings("unchecked") + final Pref uncheckedPref = (Pref) pref; + uncheckedPref.commit(source.readValue(getClass().getClassLoader())); + } else { + // Don't commit PrefWithoutDefault instances where the value read + // from the Parcel is null. + @SuppressWarnings("unchecked") + final PrefWithoutDefault uncheckedPref = (PrefWithoutDefault) pref; + final Object sourceValue = source.readValue(getClass().getClassLoader()); + if (sourceValue != null) { + uncheckedPref.commit(sourceValue); + } + } } } } diff --git 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 index a5a7c1137eaa..1355dd9938e7 100644 --- 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 @@ -24,6 +24,7 @@ exclude: true - Changed [`GeckoSession.AccountSelectorPrompt`][118.8]: added the Provider to which the Account belongs ([bug 1847059]({{bugzilla}}1847059)) - Added [`getExperimentDelegate`][118.9] and [`setExperimentDelegate`][118.10] to the GeckoSession allow GeckoView to get and set the experiment delegate for the session. Default is to use the runtime delegate. - ⚠️ Deprecated [`onGetNimbusFeature`][115.5] by 122, please use `ExperimentDelegate.onGetExperimentFeature` instead. +- Added [`GeckoRuntimeSettings.Builder.extensionsProcessEnabled`][118.11] for setting whether extensions process is enabled. ([bug 1843926]({{bugzilla}}1843926)) [118.1]: {{javadoc_uri}}/ExperimentDelegate.html [118.2]: {{javadoc_uri}}/WebExtension.InstallException.ErrorCodes.html#ERROR_BLOCKLISTED @@ -35,6 +36,7 @@ exclude: true [118.8]: {{javadoc_uri}}/GeckoSession.html#AccountSelectorPrompt [118.9]: {{javadoc_uri}}/GeckoSession.html#getExperimentDelegate() [118.10]: {{javadoc_uri}}/GeckoSession.html#setExperimentDelegate(org.mozilla.geckoview.ExperimentDelegate) +[118.11]: {{javadoc_uri}}/GeckoRuntimeSettings.Builder.html#extensionsProcessEnabled(Boolean) ## v116 - Added [`GeckoSession.didPrintPageContent`][116.1] to included extra print status for a standard print and new `GeckoPrintException.ERROR_NO_PRINT_DELEGATE` @@ -1415,4 +1417,4 @@ to allow adding gecko profiler markers. [65.24]: {{javadoc_uri}}/CrashReporter.html#sendCrashReport(android.content.Context,android.os.Bundle,java.lang.String) [65.25]: {{javadoc_uri}}/GeckoResult.html -[api-version]: fd5137f14714faddcffb5d0ba63dd0cfa6721611 +[api-version]: 5743799f9da8509cfb6546e154f0e2d7989edc72 diff --git a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java index d852cd0c3266..bf6f35abee56 100644 --- a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java +++ b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/GeckoViewActivity.java @@ -650,6 +650,17 @@ public class GeckoViewActivity extends AppCompatActivity } }; + private final BooleanSetting mExtensionsProcessEnabled = + new BooleanSetting( + R.string.key_extensions_process_enabled, + R.bool.extensions_process_enabled_default, + /* reloadCurrentSession */ true) { + @Override + public void setValue(final GeckoRuntimeSettings settings, final Boolean value) { + settings.setExtensionsProcessEnabled(value); + } + }; + private final BooleanSetting mTrackingProtection = new BooleanSetting(R.string.key_tracking_protection, R.bool.tracking_protection_default) { @Override @@ -831,6 +842,7 @@ public class GeckoViewActivity extends AppCompatActivity .preferredColorScheme(mPreferredColorScheme.value()) .telemetryDelegate(new ExampleTelemetryDelegate()) .javaScriptEnabled(mJavascriptEnabled.value()) + .extensionsProcessEnabled(mExtensionsProcessEnabled.value()) .aboutConfigEnabled(true); sGeckoRuntime = GeckoRuntime.create(this, runtimeSettingsBuilder.build()); diff --git a/mobile/android/geckoview_example/src/main/res/values/strings.xml b/mobile/android/geckoview_example/src/main/res/values/strings.xml index 2dbc2a529c4c..0e873f1760d5 100644 --- a/mobile/android/geckoview_example/src/main/res/values/strings.xml +++ b/mobile/android/geckoview_example/src/main/res/values/strings.xml @@ -60,6 +60,9 @@ javascript_enabled true + extensions_process_enabled + false + remote_debugging true diff --git a/mobile/android/geckoview_example/src/main/res/xml/settings.xml b/mobile/android/geckoview_example/src/main/res/xml/settings.xml index a29be429a089..aaedc7408584 100644 --- a/mobile/android/geckoview_example/src/main/res/xml/settings.xml +++ b/mobile/android/geckoview_example/src/main/res/xml/settings.xml @@ -67,5 +67,9 @@ app:key="@string/key_javascript_enabled" app:title="Javascript Enabled" app:defaultValue="@bool/javascript_enabled_default"/> +