From: uazo Date: Thu, 6 Nov 2025 13:21:24 +0000 Subject: Experimental support for extensions on Android Enable experimental support for extensions in Android. The feature is disabled by default: to enable it, go to Settings/Developer Options. A Clear all data used by the extension button is available in App info/Storage and cache/Clear storage to completely remove the extensions folder in case of a crash on startup. License: GPL-2.0-or-later - https://spdx.org/licenses/GPL-2.0-or-later.html --- android_webview/BUILD.gn | 2 +- .../src/partition_alloc/BUILD.gn | 2 + base/android/device_info.cc | 8 +- base/android/device_info.h | 3 +- .../src/org/chromium/base/DeviceInfo.java | 8 +- build/BUILD.gn | 2 +- .../java/templates/BuildConfig.template | 8 +- build/config/android/rules.gni | 4 +- build/config/chrome_build.gni | 7 +- build/config/compiler/BUILD.gn | 2 +- build/config/compiler/pgo/BUILD.gn | 2 +- cc/resources/ui_resource_bitmap.cc | 2 +- chrome/android/BUILD.gn | 4 +- chrome/android/chrome_public_apk_tmpl.gni | 2 +- chrome/android/java/AndroidManifest.xml | 3 - .../java/res/layout/manage_space_activity.xml | 14 +++- .../java/res/xml/developer_preferences.xml | 6 ++ .../browser/ChromeBaseAppCompatActivity.java | 2 +- .../chrome/browser/ChromeTabbedActivity.java | 2 +- .../chrome/browser/app/ChromeActivity.java | 2 +- .../AppMenuPropertiesDelegateImpl.java | 2 +- .../settings/AppearanceSettingsFragment.java | 2 +- .../layouts/LayoutManagerChrome.java | 2 +- .../overlays/strip/StripLayoutUtils.java | 2 +- .../IncognitoCustomTabIntentDataProvider.java | 4 + .../DesktopSiteSettingsIphController.java | 2 +- .../ExternalNavigationDelegateImpl.java | 3 + .../browser/multiwindow/MultiWindowUtils.java | 2 +- .../ChromeSiteSettingsDelegate.java | 2 +- .../site_settings/ManageSpaceActivity.java | 20 +++++ ...InterceptNavigationDelegateClientImpl.java | 2 +- .../browser/tab/RequestDesktopUtils.java | 2 +- .../TabbedAppMenuPropertiesDelegate.java | 2 +- .../tabbed_mode/TabbedRootUiCoordinator.java | 4 +- .../browser/toolbar/ToolbarManager.java | 2 +- chrome/app/extensions_strings.grdp | 7 ++ chrome/app/theme/theme_resources.grd | 4 +- chrome/browser/BUILD.gn | 4 +- chrome/browser/about_flags.cc | 4 + ...chrome_selection_dropdown_menu_delegate.cc | 4 +- .../bookmarks/bar/BookmarkBarUtils.java | 6 +- .../bar/BookmarkBarVisibilityProvider.java | 2 +- .../BrowserControlsUtils.java | 2 +- chrome/browser/browser_process_impl.cc | 2 +- chrome/browser/chrome_browser_field_trials.cc | 76 +++++++++---------- .../chrome_browser_interface_binders_webui.cc | 4 +- .../browser/chrome_content_browser_client.cc | 4 +- chrome/browser/devtools/BUILD.gn | 2 +- chrome/browser/download/BUILD.gn | 2 +- .../chrome_download_manager_delegate.cc | 2 +- .../download_offline_content_provider.cc | 4 +- chrome/browser/extensions/BUILD.gn | 3 +- .../chrome_extensions_api_client_android.cc | 2 +- .../extensions/api/identity/web_auth_flow.cc | 6 +- .../extensions/api/identity/web_auth_flow.h | 4 +- .../browser/extensions/api/tabs/tabs_api.cc | 3 + .../extensions/api/tabs/tabs_event_router.cc | 22 +++++- .../browser_extension_window_controller.cc | 19 ++++- .../browser_extension_window_controller.h | 6 +- .../extensions/extension_management.cc | 8 +- .../browser/extensions/extension_management.h | 2 +- .../browser/extensions/extension_tab_util.cc | 9 ++- chrome/browser/extensions/extension_util.cc | 11 +++ .../chrome/browser/feed/FeedFeatures.java | 2 +- .../feedback/DeviceInfoFeedbackSource.java | 2 +- chrome/browser/finds/core/finds_tab_helper.cc | 2 +- .../browser/flags/ChromeFeatureList.java | 6 +- chrome/browser/glic/public/features.cc | 2 +- .../glic/service/glic_instance_impl.cc | 2 +- .../browser/incognito/IncognitoUtils.java | 2 +- chrome/browser/media/router/BUILD.gn | 4 +- .../browser/media/router/discovery/BUILD.gn | 2 +- .../media/router/media_router_feature.cc | 10 +-- .../media/router/media_router_feature.h | 2 +- .../media/webrtc/webrtc_event_log_manager.cc | 4 +- .../NtpCustomizationUtils.java | 2 +- .../browser/open_in_app/OpenInAppUtils.java | 2 +- .../policy_value_and_status_aggregator.cc | 2 +- ...hrome_browser_main_extra_parts_profiles.cc | 2 +- .../profiles/off_the_record_profile_impl.cc | 5 +- chrome/browser/profiles/profile_destroyer.cc | 2 +- chrome/browser/resources/BUILD.gn | 2 +- chrome/browser/resources/discards/BUILD.gn | 2 +- .../resources/extensions/detail_view.css | 6 ++ .../resources/extensions/extensions.html | 8 +- .../resources/extensions/item_list.css | 10 +++ .../browser/resources/extensions/manager.css | 4 + .../resources/extensions/toolbar.html.ts | 7 -- .../sessions/session_restore_android.cc | 4 +- ...omeProvidedSharingOptionsProviderBase.java | 4 +- chrome/browser/startup_data.cc | 6 +- chrome/browser/startup_data.h | 6 +- .../common/task_manager_features.cc | 2 +- chrome/browser/ui/BUILD.gn | 4 +- .../browser/ui/android/context_menu_helper.cc | 12 ++- .../browser/ui/android/context_menu_helper.h | 4 +- .../desktop_site/DesktopSiteUtils.java | 4 +- .../TopControlsLockCoordinator.java | 2 +- chrome/browser/ui/android/extensions/BUILD.gn | 4 +- .../extensions/extension_actions_bridge.cc | 23 ++++++ .../extensions/extension_actions_bridge.h | 1 + .../extensions/extensions_toolbar_android.cc | 1 + .../res/layout/extensions_menu_footer.xml | 3 +- .../extensions/java/res/values/dimens.xml | 1 + .../ui/extensions/ExtensionActionsBridge.java | 6 ++ .../extensions/windowing/internal/BUILD.gn | 2 +- .../extension_window_controller_bridge.cc | 17 +++-- .../extension_window_controller_bridge.h | 2 +- .../Enable-extensions-Android.grdp | 15 ++++ .../Extensions-Android.grdp | 9 +++ .../browser/ui/android/tab_model/tab_model.cc | 2 +- .../android/tab_model/tab_model_test_helper.h | 2 +- .../toolbar/java/res/layout/toolbar_phone.xml | 6 ++ .../extensions/ExtensionsMenuCoordinator.java | 8 +- .../ExtensionsMenuItemProperties.java | 4 + .../ExtensionsMenuItemViewBinder.java | 2 + .../extensions/ExtensionsMenuMediator.java | 9 ++- .../ExtensionsToolbarCoordinatorImpl.java | 9 ++- chrome/browser/ui/browser_window/BUILD.gn | 2 +- .../ChromeAndroidTaskTrackerFactory.java | 2 +- chrome/browser/ui/prefs/BUILD.gn | 4 +- chrome/browser/ui/prefs/prefs_tab_helper.cc | 8 +- .../browser/ui/webui/chrome_web_ui_configs.cc | 4 +- .../browser/ui/webui/current_channel_logo.cc | 3 +- .../browser/ui/webui/discards/discards_ui.cc | 8 +- chrome/chrome_paks.gni | 2 +- chrome/common/chrome_features.cc | 2 +- chrome/common/chrome_switches.cc | 2 +- chrome/common/chrome_switches.h | 2 +- chrome/common/extensions/api/api_sources.gni | 7 ++ chrome/common/webui_url_constants.cc | 2 +- chrome/common/webui_url_constants.h | 2 +- .../sandbox_status_extension_android.cc | 3 +- .../sandbox_status_extension_android.h | 1 + chrome/test/BUILD.gn | 22 +++--- chrome/version.gni | 4 +- .../core/browser/host_content_settings_map.cc | 6 ++ .../embedder_support/view/ContentView.java | 2 +- .../embedder_support/user_agent_utils.cc | 14 ++-- components/local_state/local_state_utils.cc | 2 +- .../browser/android/media_router_android.cc | 2 +- .../browser/android/media_router_android.h | 2 +- .../media_router/browser/media_router.h | 4 +- .../policy/CombinedPolicyProvider.java | 8 +- .../components/policy/PolicyCacheUpdater.java | 2 +- .../android/policy_cache_updater_android.cc | 4 +- .../cloud/user_policy_signin_service_base.cc | 2 +- .../configuration_policy_handler_list.cc | 4 +- .../common/cloud/cloud_policy_constants.cc | 2 +- components/policy/core/common/features.cc | 2 +- .../policy/core/common/policy_merger.cc | 4 +- .../installable/installable_icon_fetcher.cc | 6 +- .../installable/installable_icon_fetcher.h | 2 +- .../version/resources/about_version.html | 2 +- .../selection/selection_popup_controller.cc | 5 ++ .../selection/selection_popup_controller.h | 1 + content/browser/browser_main_loop.cc | 2 +- .../render_widget_host_view_android.cc | 2 +- .../browser/ContentUiEventHandler.java | 7 +- .../SelectionPopupControllerImpl.java | 5 ++ content/public/common/content_features.cc | 4 +- .../render_frame_media_playback_options.cc | 2 +- .../about_flags_cc/Extensions-Android.inc | 12 +++ .../about_flags_cc/Webstore-protection.inc | 8 +- ...ntal-support-for-extensions-on-Android.inc | 1 + extensions/browser/BUILD.gn | 4 +- ...browser_context_keyed_service_factories.cc | 2 +- extensions/browser/api/system_cpu/BUILD.gn | 2 +- .../api/web_request/permission_helper.cc | 2 +- extensions/browser/extension_frame_host.cc | 8 ++ extensions/browser/extension_host.cc | 24 +++++- extensions/buildflags/BUILD.gn | 3 +- extensions/buildflags/buildflags.gni | 4 +- extensions/common/api/schema.gni | 2 +- extensions/common/command.cc | 2 +- extensions/common/extension_features.cc | 10 ++- extensions/common/extension_features.h | 6 +- extensions/common/extension_l10n_util.cc | 6 ++ extensions/common/features/feature.cc | 2 +- .../default_locale_handler.cc | 3 + .../renderer/bindings/api_binding_util.cc | 2 +- gpu/config/gpu_finch_features.cc | 4 +- .../chromium/media/AudioManagerAndroid.java | 2 +- net/features.gni | 4 +- skia/features.gni | 2 +- third_party/blink/common/features.cc | 4 +- .../renderer/modules/modules_initializer.cc | 4 +- third_party/libvpx/BUILD.gn | 2 +- tools/grit/grit_args.gni | 3 +- .../cpp_bundle_generator.py | 2 +- .../chromium/ui/base/SelectFileDialog.java | 2 +- .../ui/widget/PopupSpecCalculator.java | 9 ++- .../ui/test/util/UiDisableIfSkipCheck.java | 8 +- .../chromium/ui/test/util/UiRestriction.java | 4 +- ui/base/accelerators/command.cc | 2 +- ui/base/device_form_factor_android.cc | 2 +- ui/gl/features.gni | 2 +- ui/resources/ui_resources.grd | 2 +- ui/webui/resources/BUILD.gn | 2 +- .../cr_components/cr_shortcut_input/BUILD.gn | 2 +- .../cr_components/managed_footnote/BUILD.gn | 2 +- ui/webui/resources/cr_elements/BUILD.gn | 2 +- .../cr_elements/cr_toolbar/cr_toolbar.css | 3 + ui/webui/resources/css/BUILD.gn | 2 +- 204 files changed, 657 insertions(+), 325 deletions(-) create mode 100644 chrome/browser/ui/android/strings/cromite_android_chrome_strings_grd/Enable-extensions-Android.grdp create mode 100644 chrome/browser/ui/android/strings/cromite_android_chrome_strings_grd/Extensions-Android.grdp create mode 100644 cromite_flags/chrome/browser/about_flags_cc/Extensions-Android.inc create mode 100644 cromite_flags/chrome/browser/flags/android/chrome_feature_list_cc/Experimental-support-for-extensions-on-Android.inc diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn --- a/android_webview/BUILD.gn +++ b/android_webview/BUILD.gn @@ -1315,7 +1315,7 @@ declare_args() { # logic more easily on an emulator, so the decision to use the arm64 # orderfile for x64 (instead of arm32) is somewhat arbitrary. We just # needed to use some real orderfile. - if (is_desktop_android && current_cpu == "x64") { + if (is_desktop_android_false && current_cpu == "x64") { # For Android Desktop x64, orderfile is disabled, see # https://crbug.com/422005929. webview_orderfile_path = "" diff --git a/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn b/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn --- a/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn +++ b/base/allocator/partition_allocator/src/partition_alloc/BUILD.gn @@ -171,6 +171,8 @@ pa_buildflag_header("buildflags") { "HAS_64_BIT_POINTERS=$has_64_bit_pointers", "HAS_MEMORY_TAGGING=$has_memory_tagging", "IS_ANDROID=$is_android", + "IS_DESKTOP_ANDROID_FALSE=false", + "IS_DESKTOP_ANDROID_CROMITE=$is_desktop_android_cromite", "IS_CASTOS=$is_castos", "IS_CHROMEOS=$is_chromeos", "IS_DEBUG=$partition_alloc_is_debug", diff --git a/base/android/device_info.cc b/base/android/device_info.cc --- a/base/android/device_info.cc +++ b/base/android/device_info.cc @@ -103,10 +103,14 @@ bool is_foldable() { return get_device_info().isFoldable; } -bool is_desktop() { +bool is_desktop_cromite() { return get_device_info().isDesktop; } +bool is_desktop_false() { + return false; +} + // Available only on Android T+. int32_t vulkan_deqp_level() { return get_device_info().vulkanDeqpLevel; @@ -122,7 +126,7 @@ bool is_xr() { // check) as a first choice, but fall back to this if not feasible. bool is_tablet() { return was_launched_on_large_display() && !is_tv() && !is_automotive() && - !is_desktop() && !is_xr(); + !is_desktop_false() && !is_xr(); } // This returns the cached value during initial startup. If you need this diff --git a/base/android/device_info.h b/base/android/device_info.h --- a/base/android/device_info.h +++ b/base/android/device_info.h @@ -29,7 +29,8 @@ BASE_EXPORT void Set(const IDeviceInfo& info); BASE_EXPORT bool is_tv(); BASE_EXPORT bool is_automotive(); BASE_EXPORT bool is_foldable(); -BASE_EXPORT bool is_desktop(); +BASE_EXPORT bool is_desktop_cromite(); +BASE_EXPORT bool is_desktop_false(); // Available only on Android T+. BASE_EXPORT int32_t vulkan_deqp_level(); BASE_EXPORT bool is_xr(); diff --git a/base/android/java/src/org/chromium/base/DeviceInfo.java b/base/android/java/src/org/chromium/base/DeviceInfo.java --- a/base/android/java/src/org/chromium/base/DeviceInfo.java +++ b/base/android/java/src/org/chromium/base/DeviceInfo.java @@ -152,10 +152,14 @@ public final class DeviceInfo { return getInstance().mIDeviceInfo.isFoldable; } - public static boolean isDesktop() { + public static boolean isDesktopCromite() { return getInstance().mIDeviceInfo.isDesktop; } + public static boolean isDesktopFalse() { + return false; + } + public static int getVulkanDeqpLevel() { return getInstance().mIDeviceInfo.vulkanDeqpLevel; } @@ -320,7 +324,7 @@ public final class DeviceInfo { mIDeviceInfo.isDesktop = (sIsDesktopForTesting != null) ? sIsDesktopForTesting - : (BuildConfig.IS_DESKTOP_ANDROID + : (BuildConfig.IS_DESKTOP_ANDROID_FALSE && pm.hasSystemFeature(PackageManager.FEATURE_PC)) || CommandLine.getInstance() .hasSwitch(BaseSwitches.FORCE_DESKTOP_ANDROID); diff --git a/build/BUILD.gn b/build/BUILD.gn --- a/build/BUILD.gn +++ b/build/BUILD.gn @@ -128,7 +128,7 @@ buildflag_header("ios_buildflags") { # buildflag_header("android_buildflags") { header = "android_buildflags.h" - flags = [ "IS_DESKTOP_ANDROID=$is_desktop_android" ] + flags = [ "IS_DESKTOP_ANDROID_CROMITE=$is_desktop_android_cromite", "IS_DESKTOP_ANDROID_FALSE=false" ] } if (build_with_chromium) { diff --git a/build/android/java/templates/BuildConfig.template b/build/android/java/templates/BuildConfig.template --- a/build/android/java/templates/BuildConfig.template +++ b/build/android/java/templates/BuildConfig.template @@ -110,10 +110,12 @@ public class BuildConfig { // DeviceInfo.java since this is the source of truth for isDesktop check. // (TODO: crbug.com/430983585) Clean up this flag once the desktop // build is fully functional. -#if defined(_IS_DESKTOP_ANDROID) - public static boolean IS_DESKTOP_ANDROID = true; +#if defined(_IS_DESKTOP_ANDROID_CROMITE) + public static boolean IS_DESKTOP_ANDROID_CROMITE = true; + public static boolean IS_DESKTOP_ANDROID_FALSE; #else - public static boolean IS_DESKTOP_ANDROID; + public static boolean IS_DESKTOP_ANDROID_CROMITE; + public static boolean IS_DESKTOP_ANDROID_FALSE; #endif // Use to check if proguard is enabled for the current build. diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni @@ -2048,8 +2048,8 @@ if (!is_robolectric && enable_java_templates) { } else { defines += [ "_LOGTAG_PREFIX=cr_" ] } - if (is_desktop_android) { - defines += [ "_IS_DESKTOP_ANDROID" ] + if (is_desktop_android_cromite) { + defines += [ "_IS_DESKTOP_ANDROID_CROMITE" ] } if (enable_javaless_renderers) { diff --git a/build/config/chrome_build.gni b/build/config/chrome_build.gni --- a/build/config/chrome_build.gni +++ b/build/config/chrome_build.gni @@ -34,7 +34,8 @@ declare_args() { # Set to true to set defaults that enable features on Android that are more # typically available on desktop. - is_desktop_android = false + is_desktop_android_cromite = is_android + is_desktop_android_false = false if (is_android) { # By default, Trichrome channels are compiled using separate package names. @@ -56,12 +57,12 @@ is_internal_chrome_branded = enable_src_internal && is_chrome_branded # Ensure !is_android implies !is_high_end_android. is_high_end_android = is_high_end_android && is_android -if (is_desktop_android) { +if (is_desktop_android_cromite) { assert(target_os == "android", "Target must be Android to use is_desktop_android.") # Disable for non-android secondary toolchains. - is_desktop_android = is_android + is_desktop_android_cromite = is_android } declare_args() { diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -242,7 +242,7 @@ if (is_android) { # logic more easily on an emulator, so the decision to use the arm64 # orderfile for x64 (instead of arm32) is somewhat arbitrary. We just # needed to use some real orderfile. - if (is_desktop_android && current_cpu == "x64") { + if (is_desktop_android_false && current_cpu == "x64") { # For Android Desktop x64, orderfile is disabled, see # https://crbug.com/422005929. chrome_orderfile_path = "" diff --git a/build/config/compiler/pgo/BUILD.gn b/build/config/compiler/pgo/BUILD.gn --- a/build/config/compiler/pgo/BUILD.gn +++ b/build/config/compiler/pgo/BUILD.gn @@ -78,7 +78,7 @@ config("pgo_optimization_flags") { _pgo_target = "linux" } else if (is_android) { # Use |current_cpu| and not |target_cpu|; for Android we may built both. - if (is_desktop_android && current_cpu == "x64") { + if (is_desktop_android_false && current_cpu == "x64") { _pgo_target = "android-desktop-x64" } else if (current_cpu == "arm64") { _pgo_target = "android-arm64" diff --git a/cc/resources/ui_resource_bitmap.cc b/cc/resources/ui_resource_bitmap.cc --- a/cc/resources/ui_resource_bitmap.cc +++ b/cc/resources/ui_resource_bitmap.cc @@ -101,7 +101,7 @@ UIResourceBitmap::UIResourceBitmap(const SkBitmap& skbitmap) { #if BUILDFLAG(IS_ANDROID) SkBitmap copy; if (features::ShouldEnableDrDc() || - base::android::device_info::is_desktop()) { + base::android::device_info::is_desktop_false()) { // On android desktop, where JavaBitmap ensures 4 byte alignment, uploading // ALPHA_8 to angle_vulkan_image_backing may fail because it expects 1 byte // alignment stride. Workaround via copying it to N32. diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn @@ -991,7 +991,7 @@ if (_is_default_toolchain) { "//chrome/browser/password_entry_edit/android/internal:java", ] - if (is_desktop_android) { + if (is_desktop_android_cromite) { deps += [ "//chrome/browser/ui/android/extensions/windowing/internal:java" ] } else { @@ -2394,7 +2394,7 @@ if (_is_default_toolchain) { "//components/embedder_support/android:virtual_structure_javatests", ] - if (is_desktop_android) { + if (is_desktop_android_cromite) { deps += [ "//chrome/browser/ui/android/extensions/windowing/internal:javatests", diff --git a/chrome/android/chrome_public_apk_tmpl.gni b/chrome/android/chrome_public_apk_tmpl.gni --- a/chrome/android/chrome_public_apk_tmpl.gni +++ b/chrome/android/chrome_public_apk_tmpl.gni @@ -39,7 +39,7 @@ default_chrome_public_jinja_variables = [ "enable_vr=$enable_vr", "enable_openxr=$enable_openxr", "enable_arcore=$enable_arcore", - "is_desktop_android=$is_desktop_android", + "is_desktop_android_cromite=$is_desktop_android_cromite", "enable_screen_capture=$enable_screen_capture", "zygote_preload_class=org.chromium.content_public.app.ZygotePreload", ] diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml --- a/chrome/android/java/AndroidManifest.xml +++ b/chrome/android/java/AndroidManifest.xml @@ -550,9 +550,6 @@ by a child template that "extends" this file. android:theme="@style/Theme.Chromium.TabbedMode" android:exported="true" android:launchMode="singleTask" - {% if is_desktop_android == "true" %} - android:persistableMode="persistAcrossReboots" - {% endif %} {# We can only use blocks once in Jinja, for future substitutions we use self.supports_video_persistence(). #} {% block supports_video_persistence %} diff --git a/chrome/android/java/res/layout/manage_space_activity.xml b/chrome/android/java/res/layout/manage_space_activity.xml --- a/chrome/android/java/res/layout/manage_space_activity.xml +++ b/chrome/android/java/res/layout/manage_space_activity.xml @@ -94,5 +94,17 @@ found in the LICENSE file. android:id="@+id/clear_all_data" android:text="@string/storage_management_clear_all_data_button" style="@style/ManageSpaceActivityButton" /> + + + + +