diff --git a/DEPS b/DEPS index 6a0c0ad..cc154a5 100644 --- a/DEPS +++ b/DEPS
@@ -40,7 +40,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': 'eee4d6e4e8cc5c4c79f065abcc3ce609f71238f9', + 'skia_revision': '0e022297fee80add8d2939145f65d3ee56827d03', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other.
diff --git a/ash/ash_switches.cc b/ash/ash_switches.cc index 369ff26..30fc6c4 100644 --- a/ash/ash_switches.cc +++ b/ash/ash_switches.cc
@@ -40,6 +40,9 @@ const char kAshEnableMagnifierKeyScroller[] = "ash-enable-magnifier-key-scroller"; +// Enables the NightLight feature. +const char kAshEnableNightLight[] = "ash-enable-night-light"; + // Enables the palette on every display, instead of only the internal one. const char kAshEnablePaletteOnAllDisplays[] = "ash-enable-palette-on-all-displays";
diff --git a/ash/ash_switches.h b/ash/ash_switches.h index 4fc51f54..5aecb7b5 100644 --- a/ash/ash_switches.h +++ b/ash/ash_switches.h
@@ -23,6 +23,7 @@ ASH_EXPORT extern const char kAshDisableSmoothScreenRotation[]; ASH_EXPORT extern const char kAshDisableTouchExplorationMode[]; ASH_EXPORT extern const char kAshEnableMagnifierKeyScroller[]; +ASH_EXPORT extern const char kAshEnableNightLight[]; ASH_EXPORT extern const char kAshEnablePaletteOnAllDisplays[]; ASH_EXPORT extern const char kAshEnableScaleSettingsTray[]; ASH_EXPORT extern const char kAshEnableTouchView[];
diff --git a/ash/shell.cc b/ash/shell.cc index 47d5dcf6..661b87f 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -374,6 +374,11 @@ resolution_notification_controller_->DoesNotificationTimeout()); } +NightLightController* Shell::night_light_controller() { + DCHECK(NightLightController::IsFeatureEnabled()); + return night_light_controller_.get(); +} + ShelfModel* Shell::shelf_model() { return shelf_controller_->model(); } @@ -563,8 +568,6 @@ media_controller_(base::MakeUnique<MediaController>()), new_window_controller_(base::MakeUnique<NewWindowController>()), session_controller_(base::MakeUnique<SessionController>()), - night_light_controller_( - base::MakeUnique<NightLightController>(session_controller_.get())), shelf_controller_(base::MakeUnique<ShelfController>()), shell_delegate_(std::move(shell_delegate)), shutdown_controller_(base::MakeUnique<ShutdownController>()), @@ -792,6 +795,11 @@ void Shell::Init(const ShellInitParams& init_params) { const Config config = shell_port_->GetAshConfig(); + if (NightLightController::IsFeatureEnabled()) { + night_light_controller_ = + base::MakeUnique<NightLightController>(session_controller_.get()); + } + blocking_pool_ = init_params.blocking_pool; wallpaper_delegate_ = shell_delegate_->CreateWallpaperDelegate();
diff --git a/ash/shell.h b/ash/shell.h index 897c532..e5a000f8 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -341,9 +341,7 @@ NewWindowController* new_window_controller() { return new_window_controller_.get(); } - NightLightController* night_light_controller() { - return night_light_controller_.get(); - } + NightLightController* night_light_controller(); SessionController* session_controller() { return session_controller_.get(); } ShelfController* shelf_controller() { return shelf_controller_.get(); } ShelfModel* shelf_model();
diff --git a/ash/system/network/network_icon.cc b/ash/system/network/network_icon.cc index 1174c006..ec6cb5c 100644 --- a/ash/system/network/network_icon.cc +++ b/ash/system/network/network_icon.cc
@@ -878,13 +878,15 @@ } } -int GetCellularUninitializedMsg() { +int GetMobileUninitializedMsg() { static base::Time s_uninitialized_state_time; static int s_uninitialized_msg(0); NetworkStateHandler* handler = NetworkHandler::Get()->network_state_handler(); if (handler->GetTechnologyState(NetworkTypePattern::Mobile()) == NetworkStateHandler::TECHNOLOGY_UNINITIALIZED) { + // TODO (lesliewatkins): Add a more descriptive message (e.g. "Enable + // Bluetooth") for Tether technology type. s_uninitialized_msg = IDS_ASH_STATUS_TRAY_INITIALIZING_CELLULAR; s_uninitialized_state_time = base::Time::Now(); return s_uninitialized_msg; @@ -894,7 +896,7 @@ return s_uninitialized_msg; } // There can be a delay between leaving the Initializing state and when - // a Cellular device shows up, so keep showing the initializing + // a Mobile device shows up, so keep showing the initializing // animation for a bit to avoid flashing the disconnect icon. const int kInitializingDelaySeconds = 1; base::TimeDelta dtime = base::Time::Now() - s_uninitialized_state_time; @@ -950,8 +952,8 @@ } } if (!network) { - // If no connecting network, check for cellular initializing. - int uninitialized_msg = GetCellularUninitializedMsg(); + // If no connecting network, check for mobile initializing. + int uninitialized_msg = GetMobileUninitializedMsg(); if (uninitialized_msg != 0) { *image = GetConnectingImage(icon_type, shill::kTypeCellular); if (label)
diff --git a/ash/system/network/network_icon.h b/ash/system/network/network_icon.h index 827cacc..a7b2640 100644 --- a/ash/system/network/network_icon.h +++ b/ash/system/network/network_icon.h
@@ -55,9 +55,9 @@ const chromeos::NetworkState* network, IconType icon_type); -// Updates and returns the appropriate message id if the cellular network +// Updates and returns the appropriate message id if the mobile network // is uninitialized. -ASH_EXPORT int GetCellularUninitializedMsg(); +ASH_EXPORT int GetMobileUninitializedMsg(); // Gets the correct icon and label for |icon_type|. Also sets |animating| // based on whether or not the icon is animating (i.e. connecting).
diff --git a/ash/system/network/network_list.cc b/ash/system/network/network_list.cc index 3f4cff25..f94b2f6 100644 --- a/ash/system/network/network_list.cc +++ b/ash/system/network/network_list.cc
@@ -523,7 +523,7 @@ } // Cellular initializing. - int cellular_message_id = network_icon::GetCellularUninitializedMsg(); + int cellular_message_id = network_icon::GetMobileUninitializedMsg(); if (!cellular_message_id && handler->IsTechnologyEnabled(NetworkTypePattern::Mobile()) && !handler->FirstNetworkByType(NetworkTypePattern::Mobile())) {
diff --git a/ash/system/night_light/night_light_controller.cc b/ash/system/night_light/night_light_controller.cc index 90e3179f..cdbc238a 100644 --- a/ash/system/night_light/night_light_controller.cc +++ b/ash/system/night_light/night_light_controller.cc
@@ -4,9 +4,11 @@ #include "ash/system/night_light/night_light_controller.h" +#include "ash/ash_switches.h" #include "ash/public/cpp/ash_pref_names.h" #include "ash/session/session_controller.h" #include "ash/shell.h" +#include "base/command_line.h" #include "base/time/time.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" @@ -57,6 +59,12 @@ } // static +bool NightLightController::IsFeatureEnabled() { + return base::CommandLine::ForCurrentProcess()->HasSwitch( + ash::switches::kAshEnableNightLight); +} + +// static void NightLightController::RegisterPrefs(PrefRegistrySimple* registry) { registry->RegisterBooleanPref(prefs::kNightLightEnabled, false); registry->RegisterDoublePref(prefs::kNightLightTemperature,
diff --git a/ash/system/night_light/night_light_controller.h b/ash/system/night_light/night_light_controller.h index 8066d7c..bdef68d 100644 --- a/ash/system/night_light/night_light_controller.h +++ b/ash/system/night_light/night_light_controller.h
@@ -35,6 +35,9 @@ explicit NightLightController(SessionController* session_controller); ~NightLightController() override; + // Returns true if the NightLight feature is enabled in the flags. + static bool IsFeatureEnabled(); + static void RegisterPrefs(PrefRegistrySimple* registry); void AddObserver(Observer* observer);
diff --git a/ash/system/night_light/night_light_controller_unittest.cc b/ash/system/night_light/night_light_controller_unittest.cc index 175a01d..8307834d 100644 --- a/ash/system/night_light/night_light_controller_unittest.cc +++ b/ash/system/night_light/night_light_controller_unittest.cc
@@ -7,6 +7,7 @@ #include <cmath> #include <limits> +#include "ash/ash_switches.h" #include "ash/public/cpp/ash_pref_names.h" #include "ash/public/cpp/config.h" #include "ash/public/cpp/session_types.h" @@ -15,6 +16,7 @@ #include "ash/test/ash_test_helper.h" #include "ash/test/test_session_controller_client.h" #include "ash/test/test_shell_delegate.h" +#include "base/command_line.h" #include "base/macros.h" #include "components/prefs/testing_pref_service.h" #include "ui/compositor/layer.h" @@ -76,6 +78,10 @@ // ash::test::AshTestBase: void SetUp() override { + // Explicitly enable the NightLight feature for the tests. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + ash::switches::kAshEnableNightLight); + test::AshTestBase::SetUp(); CreateTestUserSessions(); Shell::RegisterPrefs(user1_pref_service_.registry());
diff --git a/ash/system/night_light/tray_night_light_unittest.cc b/ash/system/night_light/tray_night_light_unittest.cc index 3a8ca56..1491771c 100644 --- a/ash/system/night_light/tray_night_light_unittest.cc +++ b/ash/system/night_light/tray_night_light_unittest.cc
@@ -4,6 +4,7 @@ #include "ash/system/night_light/tray_night_light.h" +#include "ash/ash_switches.h" #include "ash/public/cpp/config.h" #include "ash/shell.h" #include "ash/system/night_light/night_light_controller.h" @@ -11,6 +12,7 @@ #include "ash/test/ash_test_base.h" #include "ash/test/ash_test_helper.h" #include "ash/test/test_shell_delegate.h" +#include "base/command_line.h" #include "base/macros.h" #include "components/prefs/testing_pref_service.h" @@ -27,6 +29,10 @@ // ash::test::AshTestBase: void SetUp() override { + // Explicitly enable the NightLight feature for the tests. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + ash::switches::kAshEnableNightLight); + test::AshTestBase::SetUp(); GetSessionControllerClient()->Reset(); GetSessionControllerClient()->AddUserSession(kFakeUserEmail);
diff --git a/ash/system/tiles/tiles_default_view.cc b/ash/system/tiles/tiles_default_view.cc index dbb5fd4..6a47922 100644 --- a/ash/system/tiles/tiles_default_view.cc +++ b/ash/system/tiles/tiles_default_view.cc
@@ -86,10 +86,12 @@ AddChildView(help_button_); AddChildView(TrayPopupUtils::CreateVerticalSeparator()); - night_light_button_ = new NightLightToggleButton(this); - night_light_button_->SetEnabled(can_show_web_ui); - AddChildView(night_light_button_); - AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + if (NightLightController::IsFeatureEnabled()) { + night_light_button_ = new NightLightToggleButton(this); + night_light_button_->SetEnabled(can_show_web_ui); + AddChildView(night_light_button_); + AddChildView(TrayPopupUtils::CreateVerticalSeparator()); + } lock_button_ = new SystemMenuButton(this, TrayPopupInkDropStyle::HOST_CENTERED, @@ -120,7 +122,8 @@ } else if (sender == help_button_) { ShellPort::Get()->RecordUserMetricsAction(UMA_TRAY_HELP); Shell::Get()->system_tray_controller()->ShowHelp(); - } else if (sender == night_light_button_) { + } else if (NightLightController::IsFeatureEnabled() && + sender == night_light_button_) { ShellPort::Get()->RecordUserMetricsAction(UMA_TRAY_NIGHT_LIGHT); Shell::Get()->night_light_controller()->Toggle(); night_light_button_->Update();
diff --git a/ash/system/tiles/tray_tiles_unittest.cc b/ash/system/tiles/tray_tiles_unittest.cc index 7341f72..6599f48 100644 --- a/ash/system/tiles/tray_tiles_unittest.cc +++ b/ash/system/tiles/tray_tiles_unittest.cc
@@ -4,11 +4,14 @@ #include "ash/system/tiles/tray_tiles.h" +#include "ash/ash_switches.h" +#include "ash/system/night_light/night_light_controller.h" #include "ash/system/night_light/night_light_toggle_button.h" #include "ash/system/tiles/tiles_default_view.h" #include "ash/system/tray/system_menu_button.h" #include "ash/test/ash_test_base.h" #include "ash/test/test_session_controller_client.h" +#include "base/command_line.h" #include "components/user_manager/user_type.h" #include "ui/views/view.h" @@ -23,6 +26,10 @@ ~TrayTilesTest() override {} void SetUp() override { + // Explicitly enable the NightLight feature for the tests. + base::CommandLine::ForCurrentProcess()->AppendSwitch( + ash::switches::kAshEnableNightLight); + test::NoSessionAshTestBase::SetUp(); tray_tiles_.reset(new TrayTiles(GetPrimarySystemTray())); }
diff --git a/ash/system/tray/system_tray.cc b/ash/system/tray/system_tray.cc index 75c9c11..3b09824 100644 --- a/ash/system/tray/system_tray.cc +++ b/ash/system/tray/system_tray.cc
@@ -265,8 +265,10 @@ AddTrayItem(base::WrapUnique(tray_scale_)); AddTrayItem(base::MakeUnique<TrayBrightness>(this)); AddTrayItem(base::MakeUnique<TrayCapsLock>(this)); - tray_night_light_ = new TrayNightLight(this); - AddTrayItem(base::WrapUnique(tray_night_light_)); + if (NightLightController::IsFeatureEnabled()) { + tray_night_light_ = new TrayNightLight(this); + AddTrayItem(base::WrapUnique(tray_night_light_)); + } // TODO(jamescook): Remove this when mash has support for display management // and we have a DisplayManager equivalent. See http://crbug.com/548429 if (Shell::GetAshConfig() != Config::MASH)
diff --git a/base/i18n/rtl.cc b/base/i18n/rtl.cc index 07fd964..2b6bf37 100644 --- a/base/i18n/rtl.cc +++ b/base/i18n/rtl.cc
@@ -9,7 +9,6 @@ #include <algorithm> -#include "base/atomicops.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/i18n/base_i18n_switches.h" @@ -114,8 +113,7 @@ namespace i18n { // Represents the locale-specific ICU text direction. -static subtle::Atomic32 g_icu_text_direction = - static_cast<subtle::Atomic32>(UNKNOWN_DIRECTION); +static TextDirection g_icu_text_direction = UNKNOWN_DIRECTION; // Convert the ICU default locale to a string. std::string GetConfiguredLocale() { @@ -164,10 +162,7 @@ // presence of actual locale data). However, // it does not hurt to have it as a sanity check. DCHECK(U_SUCCESS(error_code)); - subtle::Release_Store( - &g_icu_text_direction, - static_cast<subtle::Atomic32>( - GetTextDirectionForLocaleInStartUp(locale.getName()))); + g_icu_text_direction = UNKNOWN_DIRECTION; } bool IsRTL() { @@ -175,11 +170,11 @@ } bool ICUIsRTL() { - // Note: There is still a race if this is executed between the - // icu::Locale::setDefault and the g_icu_text_direction store - // that happens in SetICUDefaultLocale. - return static_cast<TextDirection>( - subtle::Acquire_Load(&g_icu_text_direction)) == RIGHT_TO_LEFT; + if (g_icu_text_direction == UNKNOWN_DIRECTION) { + const icu::Locale& locale = icu::Locale::getDefault(); + g_icu_text_direction = GetTextDirectionForLocaleInStartUp(locale.getName()); + } + return g_icu_text_direction == RIGHT_TO_LEFT; } TextDirection GetTextDirectionForLocaleInStartUp(const char* locale_name) {
diff --git a/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java b/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java index 179e4d6..2a4b19fb 100644 --- a/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java +++ b/build/android/incremental_install/java/org/chromium/incrementalinstall/ClassLoaderPatcher.java
@@ -221,7 +221,7 @@ private static Object[] makeNativePathElements(File[] paths) throws ReflectiveOperationException { Object[] entries = new Object[paths.length]; - if (Build.VERSION.CODENAME.startsWith("O")) { + if (Build.VERSION.SDK_INT >= 26) { Class<?> entryClazz = Class.forName("dalvik.system.DexPathList$NativeLibraryElement"); for (int i = 0; i < paths.length; ++i) { entries[i] = Reflect.newInstance(entryClazz, paths[i]); @@ -253,7 +253,7 @@ dexFile = Reflect.invokeMethod(clazz, "loadDexFile", file, optimizedDirectory); } Object dexElement; - if (Build.VERSION.CODENAME.startsWith("O")) { + if (Build.VERSION.SDK_INT >= 26) { dexElement = Reflect.newInstance(entryClazz, dexFile, file); } else { dexElement = Reflect.newInstance(entryClazz, emptyDir, false, file, dexFile);
diff --git a/build/check_gn_headers_whitelist.txt b/build/check_gn_headers_whitelist.txt new file mode 100644 index 0000000..d2a8282c --- /dev/null +++ b/build/check_gn_headers_whitelist.txt
@@ -0,0 +1,395 @@ +ash/accelerators/accelerator_controller_delegate.h +ash/accelerators/accelerator_controller_delegate_aura.h +ash/accelerators/accelerator_table.h +ash/ash_export.h +ash/ash_switches.h +ash/frame/header_painter.h +ash/metrics/task_switch_metrics_recorder.h +ash/metrics/task_switch_source.h +ash/metrics/user_metrics_action.h +ash/metrics/user_metrics_recorder.h +ash/public/cpp/ash_public_export.h +ash/public/cpp/config.h +ash/public/cpp/shelf_types.h +ash/session/session_observer.h +ash/shell.h +ash/system/devicetype_utils.h +ash/wm/system_modal_container_event_filter_delegate.h +cc/base/ring_buffer.h +cc/blink/web_blend_mode.h +cc/cc_export.h +cc/input/browser_controls_state.h +cc/input/event_listener_properties.h +cc/input/scrollbar.h +cc/input/scroller_size_metrics.h +cc/layers/performance_properties.h +cc/layers/scrollbar_theme_painter.h +cc/output/bsp_compare_result.h +cc/resources/release_callback_impl.h +cc/resources/return_callback.h +cc/surfaces/surface_observer.h +chrome/browser/android/android_theme_resources.h +chrome/browser/android/resource_id.h +chrome/browser/chromeos/certificate_provider/certificate_info.h +chrome/browser/chromeos/certificate_provider/certificate_provider.h +chrome/browser/chromeos/certificate_provider/certificate_provider_service.h +chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h +chrome/browser/chromeos/certificate_provider/certificate_requests.h +chrome/browser/chromeos/certificate_provider/pin_dialog_manager.h +chrome/browser/chromeos/certificate_provider/sign_requests.h +chrome/browser/chromeos/certificate_provider/thread_safe_certificate_map.h +chrome/browser/chromeos/login/signin/oauth2_login_manager.h +chrome/browser/chromeos/login/signin/oauth2_login_verifier.h +chrome/browser/chromeos/login/signin/oauth2_token_fetcher.h +chrome/browser/chromeos/profiles/profile_helper.h +chrome/browser/chromeos/settings/cros_settings.h +chrome/browser/chromeos/ui/request_pin_view.h +chrome/browser/component_updater/component_installer_errors.h +chrome/browser/download/download_file_icon_extractor.h +chrome/browser/extensions/api/networking_cast_private/chrome_networking_cast_private_delegate.h +chrome/browser/extensions/api/omnibox/omnibox_api_testbase.h +chrome/browser/extensions/api/socket/mock_tcp_client_socket.h +chrome/browser/mac/bluetooth_utility.h +chrome/browser/media/router/mojo/media_route_provider_util_win.h +chrome/browser/media/webrtc/desktop_media_list_ash.h +chrome/browser/media/webrtc/desktop_media_list_observer.h +chrome/browser/media/webrtc/rtp_dump_type.h +chrome/browser/media_galleries/fileapi/file_path_watcher_util.h +chrome/browser/media_galleries/fileapi/iapps_data_provider.h +chrome/browser/media_galleries/fileapi/itunes_data_provider.h +chrome/browser/media_galleries/fileapi/picasa_data_provider.h +chrome/browser/media_galleries/fileapi/safe_iapps_library_parser.h +chrome/browser/media_galleries/media_file_system_context.h +chrome/browser/notifications/displayed_notifications_dispatch_callback.h +chrome/browser/permissions/permission_queue_controller.h +chrome/browser/prefs/active_profile_pref_service.h +chrome/browser/rlz/chrome_rlz_tracker_delegate.h +chrome/browser/signin/easy_unlock_service_observer.h +chrome/browser/ui/android/content_settings/subresource_filter_infobar_delegate.h +chrome/browser/ui/app_icon_loader_delegate.h +chrome/browser/ui/app_list/app_list_syncable_service_factory.h +chrome/browser/ui/ash/ash_util.h +chrome/browser/ui/ash/multi_user/multi_user_util.h +chrome/browser/ui/network_profile_bubble.h +chrome/browser/ui/passwords/manage_passwords_icon.h +chrome/browser/ui/views/frame/browser_header_painter_ash.h +chrome/browser/ui/webui/large_icon_source.h +chrome/common/mac/app_shim_launch.h +chrome/common/mac/app_shim_messages.h +chrome/common/media_galleries/itunes_library.h +chrome/common/media_galleries/picasa_types.h +chrome/install_static/chromium_install_modes.h +chrome/install_static/install_constants.h +chrome/install_static/install_details.h +chrome/install_static/install_modes.h +chrome/install_static/install_util.h +chrome/install_static/test/scoped_install_details.h +chrome/installer/util/browser_distribution.h +chrome/installer/util/google_update_constants.h +chrome/installer/util/google_update_settings.h +chrome/installer/util/util_constants.h +chromeos/chromeos_export.h +chromeos/login/login_state.h +chromeos/login/scoped_test_public_session_login_state.h +chromeos/settings/cros_settings_names.h +chromeos/settings/cros_settings_provider.h +components/browser_watcher/features.h +components/browser_watcher/stability_paths.h +components/cast_certificate/cast_crl_root_ca_cert_der-inc.h +components/cdm/browser/cdm_message_filter_android.h +components/contextual_search/browser/contextual_search_js_api_handler.h +components/cryptauth/connection_finder.h +components/cryptauth/connection_observer.h +components/data_reduction_proxy/core/browser/data_use_group.h +components/data_reduction_proxy/core/browser/data_use_group_provider.h +components/data_use_measurement/core/url_request_classifier.h +components/device_event_log/device_event_log_export.h +components/dom_distiller/core/font_family_list.h +components/dom_distiller/core/theme_list.h +components/login/login_export.h +components/nacl/browser/nacl_browser_delegate.h +components/nacl/renderer/ppb_nacl_private.h +components/omnibox/browser/autocomplete_i18n.h +components/omnibox/browser/autocomplete_provider_client.h +components/omnibox/browser/autocomplete_provider_listener.h +components/password_manager/core/browser/keychain_migration_status_mac.h +components/policy/core/browser/configuration_policy_handler_parameters.h +components/policy/proto/policy_proto_export.h +components/rlz/rlz_tracker_delegate.h +components/session_manager/session_manager_types.h +components/sessions/core/sessions_export.h +components/sync/engine/connection_status.h +components/sync/engine/net/network_time_update_callback.h +components/translate/core/browser/translate_infobar_delegate.h +components/user_manager/user.h +components/user_manager/user_image/user_image.h +components/user_manager/user_manager.h +components/viz/display_compositor/display_provider.h +components/viz/viz_export.h +components/wallpaper/wallpaper_export.h +components/wifi/wifi_export.h +components/wifi/wifi_service.h +content/browser/background_fetch/background_fetch_constants.h +content/browser/service_worker/service_worker_response_type.h +content/common/gpu_stream_constants.h +content/common/mac/attributed_string_coder.h +content/common/mac/font_descriptor.h +content/public/browser/context_factory.h +content/public/browser/media_observer.h +content/renderer/external_popup_menu.h +content/shell/android/shell_descriptors.h +device/media_transfer_protocol/media_transfer_protocol_manager.h +extensions/browser/api/clipboard/clipboard_api.h +extensions/browser/api/networking_config/networking_config_service_factory.h +extensions/browser/api/webcam_private/webcam.h +extensions/browser/api/webcam_private/webcam_private_api.h +extensions/browser/entry_info.h +extensions/browser/extension_event_histogram_value.h +extensions/browser/extension_function_histogram_value.h +google_apis/gcm/base/encryptor.h +google_apis/gcm/base/gcm_export.h +gpu/GLES2/gl2chromium.h +gpu/GLES2/gl2chromium_autogen.h +gpu/GLES2/gl2extchromium.h +gpu/command_buffer/client/context_support.h +gpu/command_buffer/client/gles2_implementation_unittest_autogen.h +gpu/command_buffer/client/gles2_interface_autogen.h +gpu/command_buffer/client/gles2_interface_stub_autogen.h +gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +gpu/command_buffer/client/gpu_control_client.h +gpu/command_buffer/client/ref_counted.h +gpu/command_buffer/client/shared_memory_limits.h +gpu/command_buffer/common/command_buffer_shared.h +gpu/command_buffer/common/gles2_cmd_utils_autogen.h +gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +gpu/command_buffer/common/gpu_memory_allocation.h +gpu/command_buffer/service/gl_stream_texture_image.h +gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions_autogen.h +gpu/command_buffer/service/memory_tracking.h +gpu/command_buffer/service/progress_reporter.h +gpu/gles2_conform_support/gtf/gtf_stubs.h +gpu/gpu_export.h +headless/lib/headless_macros.h +headless/public/headless_tab_socket.h +ipc/ipc_channel_proxy_unittest_messages.h +ipc/ipc_message_null_macros.h +ipc/param_traits_size_macros.h +media/audio/audio_logging.h +media/audio/sounds/test_data.h +media/base/routing_token_callback.h +media/base/video_renderer_sink.h +media/cast/common/mod_util.h +media/cast/net/rtcp/rtcp_session.h +media/filters/ffmpeg_aac_bitstream_converter.h +media/filters/ffmpeg_h264_to_annex_b_bitstream_converter.h +media/filters/h264_to_annex_b_bitstream_converter.h +media/formats/mp4/avc.h +media/formats/mp4/bitstream_converter.h +media/formats/mp4/fourccs.h +media/formats/mp4/rcheck.h +media/formats/mpeg/adts_stream_parser.h +media/formats/mpeg/mpeg1_audio_stream_parser.h +media/formats/mpeg/mpeg_audio_stream_parser_base.h +media/gpu/media_gpu_export.h +mojo/common/mojo_common_export.h +mojo/edk/system/broker_messages.h +mojo/edk/system/system_impl_export.h +mojo/public/cpp/bindings/strong_associated_binding_set.h +mojo/public/cpp/bindings/tests/mojo_test_blink_export.h +mojo/public/cpp/test_support/test_support.h +net/base/winsock_init.h +net/cert/cert_type.h +net/cert/cert_verify_proc_android.h +net/cert/scoped_nss_types.h +net/dns/notify_watcher_mac.h +net/http/http_status_code_list.h +net/http/transport_security_state_static.h +net/quic/core/stream_notifier_interface.h +ppapi/cpp/pass_ref.h +ppapi/lib/gl/include/GLES2/gl2.h +ppapi/lib/gl/include/GLES2/gl2ext.h +ppapi/lib/gl/include/GLES2/gl2platform.h +ppapi/lib/gl/include/KHR/khrplatform.h +ppapi/nacl_irt/irt_manifest.h +ppapi/nacl_irt/public/irt_ppapi.h +ppapi/native_client/src/shared/ppapi_proxy/ppruntime.h +ppapi/native_client/src/untrusted/pnacl_irt_shim/irt_shim_ppapi.h +ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.h +ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_ppapi.h +ppapi/proxy/content_decryptor_private_serializer.h +ppapi/proxy/dispatch_reply_message.h +ppapi/proxy/plugin_proxy_delegate.h +ppapi/proxy/plugin_resource_callback.h +ppapi/proxy/ppapi_proxy_export.h +ppapi/proxy/resource_message_filter.h +ppapi/proxy/video_decoder_constants.h +ppapi/shared_impl/api_id.h +ppapi/shared_impl/dir_contents.h +ppapi/shared_impl/ppapi_shared_export.h +ppapi/shared_impl/singleton_resource_id.h +remoting/base/chromoting_event_log_writer.h +remoting/base/logging.h +remoting/client/display/gl_renderer_delegate.h +remoting/client/display/gl_texture_ids.h +remoting/codec/webrtc_video_encoder.h +remoting/host/linux/x11_keyboard.h +remoting/host/worker_process_ipc_delegate.h +remoting/protocol/audio_source.h +remoting/protocol/audio_stream.h +remoting/protocol/cursor_shape_stub.h +remoting/protocol/message_channel_factory.h +remoting/protocol/test_event_matchers.h +remoting/protocol/video_feedback_stub.h +remoting/protocol/video_stream.h +sandbox/linux/system_headers/capability.h +sdch/linux/config.h +services/service_manager/public/c/main.h +services/ui/ws/ids.h +skia/ext/convolver_mips_dspr2.h +skia/ext/skia_commit_hash.h +skia/ext/texture_handle.h +testing/gmock_mutant.h +third_party/WebKit/Source/bindings/modules/v8/serialization/WebCryptoSubTags.h +third_party/WebKit/Source/core/animation/CSSInterpolationEnvironment.h +third_party/WebKit/Source/core/animation/SVGInterpolationEnvironment.h +third_party/WebKit/Source/core/css/CSSPropertyMetadata.h +third_party/WebKit/Source/core/css/resolver/StyleBuilder.h +third_party/WebKit/Source/core/css/threaded/MultiThreadedTestUtil.h +third_party/WebKit/Source/core/css/zoomAdjustedPixelValue.h +third_party/WebKit/Source/core/dom/ArrayBufferViewHelpers.h +third_party/WebKit/Source/core/editing/FindOptions.h +third_party/WebKit/Source/core/paint/FindPaintOffsetAndVisualRectNeedingUpdate.h +third_party/WebKit/Source/core/style/ShapeValue.h +third_party/WebKit/Source/core/style/TransformOrigin.h +third_party/WebKit/Source/platform/ColorSuggestion.h +third_party/WebKit/Source/platform/EncryptedMediaRequest.h +third_party/WebKit/Source/platform/fonts/FontSelector.h +third_party/WebKit/Source/platform/fonts/Glyph.h +third_party/WebKit/Source/platform/graphics/cpu/arm/WebGLImageConversionNEON.h +third_party/WebKit/Source/platform/graphics/cpu/mips/WebGLImageConversionMSA.h +third_party/WebKit/Source/platform/graphics/paint/PaintImage.h +third_party/WebKit/Source/platform/scheduler/base/task_queue.h +third_party/WebKit/Source/platform/scroll/ScrollerSizeMetrics.h +third_party/WebKit/Source/platform/text/TabSize.h +third_party/WebKit/Source/platform/text/TextDirection.h +third_party/WebKit/Source/platform/transforms/TransformOperation.h +third_party/WebKit/public/platform/WebFeature.h +third_party/WebKit/public/platform/WebFeaturePolicyFeature.h +third_party/WebKit/public/platform/WebSourceLocation.h +third_party/WebKit/public/platform/WebTouchInfo.h +third_party/WebKit/public/platform/modules/media_capabilities/WebMediaCapabilitiesInfo.h +third_party/cacheinvalidation/src/google/cacheinvalidation/impl/build_constants.h +third_party/expat/files/lib/ascii.h +third_party/expat/files/lib/asciitab.h +third_party/expat/files/lib/expat_config.h +third_party/expat/files/lib/expat_external.h +third_party/expat/files/lib/iasciitab.h +third_party/expat/files/lib/internal.h +third_party/expat/files/lib/latin1tab.h +third_party/expat/files/lib/nametab.h +third_party/expat/files/lib/utf8tab.h +third_party/expat/files/lib/xmlrole.h +third_party/expat/files/lib/xmltok.h +third_party/expat/files/lib/xmltok_impl.h +third_party/harfbuzz-ng/src/hb-ot-cbdt-table.hh +third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh +third_party/harfbuzz-ng/src/hb-ot-glyf-table.hh +third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh +third_party/harfbuzz-ng/src/hb-ot-os2-table.hh +third_party/hunspell/src/hunspell/hunvisapi.h +third_party/khronos/EGL/egl.h +third_party/khronos/EGL/eglext.h +third_party/khronos/EGL/eglplatform.h +third_party/khronos/GLES2/gl2.h +third_party/khronos/GLES2/gl2ext.h +third_party/khronos/GLES2/gl2platform.h +third_party/khronos/GLES3/gl3.h +third_party/khronos/GLES3/gl3platform.h +third_party/khronos/KHR/khrplatform.h +third_party/leveldatabase/chromium_logger.h +third_party/libaddressinput/chromium/addressinput_util.h +third_party/libaddressinput/chromium/override/basictypes_override.h +third_party/libphonenumber/phonenumber_api.h +third_party/libudev/libudev0.h +third_party/libudev/libudev1.h +third_party/libvpx/source/config/linux/x64/vp8_rtcd.h +third_party/libvpx/source/config/linux/x64/vp9_rtcd.h +third_party/libvpx/source/config/linux/x64/vpx_config.h +third_party/libvpx/source/config/linux/x64/vpx_dsp_rtcd.h +third_party/libvpx/source/config/linux/x64/vpx_scale_rtcd.h +third_party/libvpx/source/config/nacl/vp8_rtcd.h +third_party/libvpx/source/config/nacl/vp9_rtcd.h +third_party/libvpx/source/config/nacl/vpx_config.h +third_party/libvpx/source/config/nacl/vpx_dsp_rtcd.h +third_party/libvpx/source/config/nacl/vpx_scale_rtcd.h +third_party/libvpx/source/config/vpx_version.h +third_party/libwebp/mux/animi.h +third_party/libwebp/mux/muxi.h +third_party/libwebp/webp/mux.h +third_party/libxslt/src/libxslt/xsltwin32config.h +third_party/opus/src/src/opus_private.h +third_party/opus/src/tests/test_opus_common.h +third_party/protobuf/src/google/protobuf/compiler/csharp/csharp_names.h +third_party/protobuf/src/google/protobuf/compiler/javanano/javanano_params.h +third_party/qcms/src/halffloat.h +third_party/qcms/src/tests/qcms_test_util.h +third_party/qcms/src/tests/timing.h +third_party/snappy/linux/config.h +third_party/speech-dispatcher/libspeechd.h +third_party/sqlite/sqlite3.h +third_party/tcmalloc/chromium/src/addressmap-inl.h +third_party/tcmalloc/chromium/src/base/basictypes.h +third_party/tcmalloc/chromium/src/base/dynamic_annotations.h +third_party/tcmalloc/chromium/src/base/googleinit.h +third_party/tcmalloc/chromium/src/base/linux_syscall_support.h +third_party/tcmalloc/chromium/src/base/spinlock_linux-inl.h +third_party/tcmalloc/chromium/src/base/stl_allocator.h +third_party/tcmalloc/chromium/src/base/thread_annotations.h +third_party/tcmalloc/chromium/src/base/thread_lister.h +third_party/tcmalloc/chromium/src/gperftools/malloc_extension_c.h +third_party/tcmalloc/chromium/src/gperftools/malloc_hook_c.h +third_party/tcmalloc/chromium/src/gperftools/tcmalloc.h +third_party/tcmalloc/chromium/src/heap-profile-stats.h +third_party/tcmalloc/chromium/src/libc_override.h +third_party/tcmalloc/chromium/src/malloc_hook_mmap_linux.h +third_party/tcmalloc/chromium/src/packed-cache-inl.h +third_party/tcmalloc/chromium/src/page_heap_allocator.h +third_party/tcmalloc/chromium/src/pagemap.h +third_party/tcmalloc/chromium/src/stacktrace_config.h +third_party/tcmalloc/chromium/src/stacktrace_x86-inl.h +third_party/tcmalloc/chromium/src/system-alloc.h +third_party/tcmalloc/chromium/src/tcmalloc_guard.h +third_party/wayland/include/config.h +third_party/wayland/include/src/wayland-version.h +third_party/woff2/src/port.h +third_party/yasm/source/config/linux/config.h +third_party/yasm/source/config/linux/libyasm-stdint.h +third_party/zlib/contrib/minizip/crypt.h +tools/battor_agent/battor_protocol_types.h +tools/gn/ordered_set.h +tools/ipc_fuzzer/message_lib/all_message_null_macros.h +ui/accessibility/ax_export.h +ui/app_list/app_list_export.h +ui/app_list/app_list_item.h +ui/app_list/app_list_switches.h +ui/aura/aura_export.h +ui/base/clipboard/clipboard_test_template.h +ui/base/dragdrop/download_file_interface.h +ui/compositor/compositor_constants.h +ui/compositor/layer_owner_delegate.h +ui/events/keycodes/keyboard_codes_posix.h +ui/gfx/overlay_transform.h +ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h +ui/gfx/swap_result.h +ui/gfx/sys_color_change_listener.h +ui/gl/GL/glextchromium.h +ui/gl/gl_bindings_api_autogen_egl.h +ui/gl/gl_bindings_api_autogen_gl.h +ui/gl/gl_bindings_api_autogen_glx.h +ui/gl/gl_bindings_api_autogen_osmesa.h +ui/gl/gpu_preference.h +ui/gl/gpu_switching_observer.h +ui/native_theme/native_theme_export.h +ui/ozone/ozone_base_export.h +ui/ozone/public/ozone_switches.h +ui/shell_dialogs/shell_dialogs_export.h
diff --git a/chrome/VERSION b/chrome/VERSION index 7324bce..65d25b80 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=61 MINOR=0 -BUILD=3121 +BUILD=3122 PATCH=0
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn index 613e668..a0714804 100644 --- a/chrome/browser/BUILD.gn +++ b/chrome/browser/BUILD.gn
@@ -413,6 +413,8 @@ "favicon/favicon_utils.h", "favicon/large_icon_service_factory.cc", "favicon/large_icon_service_factory.h", + "feature_engagement_tracker/feature_engagement_tracker_factory.cc", + "feature_engagement_tracker/feature_engagement_tracker_factory.h", "file_select_helper.cc", "file_select_helper.h", "file_select_helper_mac.mm", @@ -1526,6 +1528,7 @@ "//components/favicon/content", "//components/favicon/core", "//components/favicon_base", + "//components/feature_engagement_tracker", "//components/flags_ui", "//components/gcm_driver", "//components/google/core/browser", @@ -3134,8 +3137,6 @@ "download/download_request_infobar_delegate_android.h", "engagement/site_engagement_service_android.cc", "engagement/site_engagement_service_android.h", - "feature_engagement_tracker/feature_engagement_tracker_factory.cc", - "feature_engagement_tracker/feature_engagement_tracker_factory.h", "geolocation/geolocation_infobar_delegate_android.cc", "geolocation/geolocation_infobar_delegate_android.h", "history/android/android_history_provider_service.cc", @@ -3259,7 +3260,6 @@ "//chrome/browser/android/webapk:proto", "//components/cdm/browser", "//components/data_usage/android", - "//components/feature_engagement_tracker", "//components/payments/content/android", "//components/precache/content", "//components/resources:components_resources",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index 99636416..d36739be 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc
@@ -46,6 +46,8 @@ #include "components/dom_distiller/core/dom_distiller_switches.h" #include "components/error_page/common/error_page_switches.h" #include "components/favicon/core/features.h" +#include "components/feature_engagement_tracker/public/feature_constants.h" +#include "components/feature_engagement_tracker/public/feature_list.h" #include "components/flags_ui/feature_entry.h" #include "components/flags_ui/feature_entry_macros.h" #include "components/flags_ui/flags_storage.h" @@ -107,8 +109,6 @@ #if defined(OS_ANDROID) #include "chrome/browser/android/chrome_feature_list.h" -#include "components/feature_engagement_tracker/public/feature_constants.h" -#include "components/feature_engagement_tracker/public/feature_list.h" #else // OS_ANDROID #include "ui/message_center/message_center_switches.h" #endif // OS_ANDROID @@ -1394,6 +1394,9 @@ proximity_auth::switches::kEnableBluetoothLowEnergyDiscovery)}, #endif // OS_CHROMEOS #if defined(USE_ASH) + {"ash-enable-night-light", flag_descriptions::kEnableNightLightName, + flag_descriptions::kEnableNightLightDescription, kOsAll, + SINGLE_VALUE_TYPE(ash::switches::kAshEnableNightLight)}, {"show-touch-hud", flag_descriptions::kShowTouchHudName, flag_descriptions::kShowTouchHudDescription, kOsAll, SINGLE_VALUE_TYPE(ash::switches::kAshTouchHud)}, @@ -1791,14 +1794,12 @@ flag_descriptions::kChromeHomeSwipeLogicDescription, kOsAndroid, MULTI_VALUE_TYPE(kChromeHomeSwipeLogicChoices)}, #endif // OS_ANDROID -#if defined(OS_ANDROID) {"iph-demo-mode-choice", flag_descriptions::kIphDemoModeChoiceName, - flag_descriptions::kIphDemoModeChoiceDescription, kOsAndroid, + flag_descriptions::kIphDemoModeChoiceDescription, kOsAll, FEATURE_WITH_PARAMS_VALUE_TYPE( feature_engagement_tracker::kIPHDemoMode, feature_engagement_tracker::kIPHDemoModeChoiceVariations, feature_engagement_tracker::kIPHDemoMode.name)}, -#endif // OS_ANDROID {"num-raster-threads", flag_descriptions::kNumRasterThreadsName, flag_descriptions::kNumRasterThreadsDescription, kOsAll, MULTI_VALUE_TYPE(kNumRasterThreadsChoices)}, @@ -1921,12 +1922,6 @@ SINGLE_DISABLE_VALUE_TYPE( chromeos::switches::kDisableCaptivePortalBypassProxy)}, #endif // OS_CHROMEOS -#if defined(OS_ANDROID) - {"enable-seccomp-sandbox-android", - flag_descriptions::kSeccompFilterSandboxAndroidName, - flag_descriptions::kSeccompFilterSandboxAndroidDescription, kOsAndroid, - FEATURE_VALUE_TYPE(features::kSeccompSandboxAndroid)}, -#endif // OS_ANDROID #if defined(OS_CHROMEOS) {"enable-wifi-credential-sync", flag_descriptions::kWifiCredentialSyncName, flag_descriptions::kWifiCredentialSyncDescription, kOsCrOS,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.cc b/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.cc index b1fb522..932ec7c 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.cc +++ b/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.cc
@@ -13,9 +13,9 @@ #include "components/ukm/public/ukm_recorder.h" #include "jni/ContextualSearchRankerLoggerImpl_jni.h" -ContextualSearchRankerLoggerImpl::ContextualSearchRankerLoggerImpl( - JNIEnv* env, - jobject obj) { +ContextualSearchRankerLoggerImpl::ContextualSearchRankerLoggerImpl(JNIEnv* env, + jobject obj) + : ukm_recorder_(nullptr), builder_(nullptr) { java_object_.Reset(env, obj); } @@ -37,6 +37,11 @@ void ContextualSearchRankerLoggerImpl::SetUkmRecorder( ukm::UkmRecorder* ukm_recorder, const GURL& page_url) { + if (!ukm_recorder) { + builder_.reset(); + return; + } + ukm_recorder_ = ukm_recorder; source_id_ = ukm_recorder_->GetNewSourceID(); ukm_recorder_->UpdateSourceURL(source_id_, page_url); @@ -48,12 +53,18 @@ jobject obj, const base::android::JavaParamRef<jstring>& j_feature, jlong j_long) { + if (!builder_) + return; + std::string feature = base::android::ConvertJavaStringToUTF8(env, j_feature); builder_->AddMetric(feature.c_str(), j_long); } void ContextualSearchRankerLoggerImpl::WriteLogAndReset(JNIEnv* env, jobject obj) { + if (!ukm_recorder_) + return; + // Set up another builder for the next record (in case it's needed). builder_ = ukm_recorder_->GetEntryBuilder(source_id_, "ContextualSearch"); }
diff --git a/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h b/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h index 52490590..351b26c5 100644 --- a/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h +++ b/chrome/browser/android/contextualsearch/contextual_search_ranker_logger_impl.h
@@ -48,13 +48,14 @@ // TODO(donnd): write a test, using this to inject a test-ukm-recorder. void SetUkmRecorder(ukm::UkmRecorder* ukm_recorder, const GURL& page_url); - // Used to log URL-keyed metrics. This pointer will outlive |this|. + // Used to log URL-keyed metrics. This pointer will outlive |this|, and may + // be nullptr. ukm::UkmRecorder* ukm_recorder_; // The UKM source ID being used for this session. int32_t source_id_; - // The entry builder for the current record. + // The entry builder for the current record, or nullptr if not yet configured. std::unique_ptr<ukm::UkmEntryBuilder> builder_; // The linked Java object.
diff --git a/chrome/browser/chromeos/status/network_menu.cc b/chrome/browser/chromeos/status/network_menu.cc index 0673559..530ba8af 100644 --- a/chrome/browser/chromeos/status/network_menu.cc +++ b/chrome/browser/chromeos/status/network_menu.cc
@@ -471,7 +471,7 @@ } } else { int initializing_message_id = - ash::network_icon::GetCellularUninitializedMsg(); + ash::network_icon::GetMobileUninitializedMsg(); if (initializing_message_id) { // Initializing cellular modem... AddMessageItem(l10n_util::GetStringUTF16(initializing_message_id));
diff --git a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc index 5fd289d..15b8f360 100644 --- a/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc +++ b/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/test/test_timeouts.h" #include "build/build_config.h" #include "chrome/browser/extensions/browser_action_test_util.h" #include "chrome/browser/extensions/extension_action.h" @@ -37,6 +38,52 @@ namespace extensions { namespace { +// Helper to ensure all extension hosts are destroyed during the test. If a host +// is still alive, the Profile can not be destroyed in +// BrowserProcessImpl::StartTearDown(). TODO(tapted): The existence of this +// helper is probably a bug. Extension hosts do not currently block shutdown the +// way a browser tab does. Maybe they should. See http://crbug.com/729476. +class ExtensionHostWatcher : public content::NotificationObserver { + public: + ExtensionHostWatcher() { + registrar_.Add(this, NOTIFICATION_EXTENSION_HOST_CREATED, + content::NotificationService::AllSources()); + registrar_.Add(this, NOTIFICATION_EXTENSION_HOST_DESTROYED, + content::NotificationService::AllSources()); + } + + void Wait() { + if (created_ == destroyed_) + return; + + base::RunLoop run_loop; + quit_closure_ = run_loop.QuitClosure(); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, quit_closure_, TestTimeouts::action_timeout()); + run_loop.Run(); + } + + int created() const { return created_; } + int destroyed() const { return destroyed_; } + + // NotificationObserver: + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override { + ++(type == NOTIFICATION_EXTENSION_HOST_CREATED ? created_ : destroyed_); + if (!quit_closure_.is_null() && created_ == destroyed_) + quit_closure_.Run(); + } + + private: + content::NotificationRegistrar registrar_; + base::Closure quit_closure_; + int created_ = 0; + int destroyed_ = 0; + + DISALLOW_COPY_AND_ASSIGN(ExtensionHostWatcher); +}; + // chrome.browserAction API tests that interact with the UI in such a way that // they cannot be run concurrently (i.e. openPopup API tests that require the // window be focused/active). @@ -47,10 +94,21 @@ // BrowserTestBase: void SetUpOnMainThread() override { + host_watcher_ = base::MakeUnique<ExtensionHostWatcher>(); ExtensionApiTest::SetUpOnMainThread(); EXPECT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser())); } + void TearDownOnMainThread() override { + // Note browser windows are closed in PostRunTestOnMainThread(), which is + // called after this. But relying on the window close to close the + // extension host can cause flakes. See http://crbug.com/729476. + // Waiting here requires individual tests to ensure their popup has closed. + ExtensionApiTest::TearDownOnMainThread(); + host_watcher_->Wait(); + EXPECT_EQ(host_watcher_->created(), host_watcher_->destroyed()); + } + protected: // Function to control whether to run popup tests for the current platform. // These tests require RunExtensionSubtest to work as expected and the browser @@ -95,6 +153,9 @@ EnsurePopupActive(); } + // Close the popup window directly. + void ClosePopup() { BrowserActionTestUtil(browser()).HidePopup(); } + // Trigger a focus loss to close the popup. void ClosePopupViaFocusLoss() { EXPECT_TRUE(BrowserActionTestUtil(browser()).HasPopup()); @@ -123,6 +184,11 @@ observer.Wait(); base::RunLoop().RunUntilIdle(); } + + private: + std::unique_ptr<ExtensionHostWatcher> host_watcher_; + + DISALLOW_COPY_AND_ASSIGN(BrowserActionInteractiveTest); }; // Tests opening a popup using the chrome.browserAction.openPopup API. This test @@ -160,8 +226,6 @@ EXPECT_TRUE(new_browser != NULL); -// Flaky on non-aura linux http://crbug.com/309749 -#if !(defined(OS_LINUX) && !defined(USE_AURA)) ResultCatcher catcher; { content::WindowedNotificationObserver frame_observer( @@ -173,7 +237,7 @@ EXPECT_TRUE(BrowserActionTestUtil(new_browser).HasPopup()); } ASSERT_TRUE(catcher.GetNextResult()) << message_; -#endif + BrowserActionTestUtil(new_browser).HidePopup(); } // Tests opening a popup in an incognito window. @@ -196,8 +260,9 @@ EXPECT_FALSE(BrowserActionTestUtil(browser()).HasPopup()); #endif // Incognito window should have a popup. - EXPECT_TRUE(BrowserActionTestUtil(BrowserList::GetInstance()->GetLastActive()) - .HasPopup()); + BrowserActionTestUtil test_util(BrowserList::GetInstance()->GetLastActive()); + EXPECT_TRUE(test_util.HasPopup()); + test_util.HidePopup(); } // Tests that an extension can open a popup in the last active incognito window @@ -227,7 +292,9 @@ OpenURLOffTheRecord(profile(), GURL("chrome://newtab/")); listener.WaitUntilSatisfied(); EXPECT_EQ(std::string("opened"), listener.message()); - EXPECT_TRUE(BrowserActionTestUtil(incognito_browser).HasPopup()); + BrowserActionTestUtil test_util(incognito_browser); + EXPECT_TRUE(test_util.HasPopup()); + test_util.HidePopup(); } #if defined(OS_LINUX) @@ -259,6 +326,7 @@ // Return control to javascript to validate that opening a popup fails now. listener.Reply("show another"); ASSERT_TRUE(catcher.GetNextResult()) << message_; + ClosePopup(); } // Test that openPopup does not grant tab permissions like for browser action @@ -278,6 +346,7 @@ SessionTabHelper::IdForTab( browser()->tab_strip_model()->GetActiveWebContents()), APIPermission::kTab)); + ClosePopup(); } // Test that the extension popup is closed when the browser window is focused.
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc index 381a31ee..054f5e6b 100644 --- a/chrome/browser/flag_descriptions.cc +++ b/chrome/browser/flag_descriptions.cc
@@ -353,6 +353,11 @@ "Experiment to have all APIs reflect the layout viewport. This will " "make window.scroll properties relative to the layout viewport."; +const char kIphDemoModeChoiceName[] = "In-Product Help Demo Mode"; + +const char kIphDemoModeChoiceDescription[] = + "Selects the In-Product Help demo mode."; + const char kColorCorrectRenderingName[] = "Color correct rendering"; const char kColorCorrectRenderingDescription[] = @@ -1067,6 +1072,11 @@ "flag. The trace may include personally identifiable information (PII) " "such as the titles and URLs of websites you visit."; +const char kEnableNightLightName[] = "Enable Night Light"; +const char kEnableNightLightDescription[] = + "Enable the Night Light feature to control the color temperature of the " + "screen."; + const char kEnablePictureInPictureName[] = "Enable picture in picture."; const char kEnablePictureInPictureDescription[] = @@ -1980,17 +1990,6 @@ #endif // defined(OS_ANDROID) -// In-Product Help flags - -#if defined(OS_ANDROID) - -const char kIphDemoModeChoiceName[] = "In-Product Help Demo Mode"; - -const char kIphDemoModeChoiceDescription[] = - "Selects the In-Product Help demo mode."; - -#endif // defined(OS_ANDROID) - // Settings window flags const char kSettingsWindowName[] = "Show settings in a window"; @@ -1999,21 +1998,6 @@ "Settings will be shown in a dedicated window instead of as a browser " "tab."; -// Mixed content issue workaround flags - -#if defined(OS_ANDROID) - -// Flag strings for seccomp-bpf sandbox flag. - -const char kSeccompFilterSandboxAndroidName[] = "Seccomp-bpf renderer sandbox"; - -const char kSeccompFilterSandboxAndroidDescription[] = - "Renderers will have a second-layer sandbox provided by seccomp-bpf. " - "This requires kernel features only available on select Android " - "versions."; - -#endif // defined(OS_ANDROID) - // Extension Content Verification const char kExtensionContentVerificationName[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h index 2f609a6..4bc25493 100644 --- a/chrome/browser/flag_descriptions.h +++ b/chrome/browser/flag_descriptions.h
@@ -235,6 +235,9 @@ extern const char kEnableNavigationTracingName[]; extern const char kEnableNavigationTracingDescription[]; +extern const char kEnableNightLightName[]; +extern const char kEnableNightLightDescription[]; + extern const char kEnablePictureInPictureName[]; extern const char kEnablePictureInPictureDescription[]; @@ -403,6 +406,9 @@ extern const char kInertVisualViewportName[]; extern const char kInertVisualViewportDescription[]; +extern const char kIphDemoModeChoiceName[]; +extern const char kIphDemoModeChoiceDescription[]; + extern const char kJavascriptHarmonyName[]; extern const char kJavascriptHarmonyDescription[]; @@ -982,9 +988,6 @@ extern const char kHerbPrototypeChoicesDescription[]; extern const char kHerbPrototypeFlavorElderberry[]; -extern const char kIphDemoModeChoiceName[]; -extern const char kIphDemoModeChoiceDescription[]; - extern const char kLsdPermissionPromptName[]; extern const char kLsdPermissionPromptDescription[]; @@ -1075,9 +1078,6 @@ extern const char kReaderModeHeuristicsAlwaysOff[]; extern const char kReaderModeHeuristicsAlwaysOn[]; -extern const char kSeccompFilterSandboxAndroidName[]; -extern const char kSeccompFilterSandboxAndroidDescription[]; - extern const char kServiceWorkerPaymentAppsName[]; extern const char kServiceWorkerPaymentAppsDescription[];
diff --git a/chrome/browser/resources/settings/device_page/display.html b/chrome/browser/resources/settings/device_page/display.html index b4d7fbc..9e0676c 100644 --- a/chrome/browser/resources/settings/device_page/display.html +++ b/chrome/browser/resources/settings/device_page/display.html
@@ -202,32 +202,34 @@ </div> <!-- Night Light Settings --> - <div class="settings-box"> - <div class="start"> - <h2 id="nightLightLabel">$i18n{displayNightLightLabel}</h2> - <div class="secondary">$i18n{displayNightLightText}</div> - </div> - <settings-toggle-button - id="nightLightToggleButton" - pref="{{prefs.ash.night_light.enabled}}" - aria-labelledby="nightLightLabel"> - </settings-toggle-button> - </div> - <div id="nightLightSettingsDiv" - class="settings-box continuation start layout vertical"> - <!-- Color temperature slider --> - <div class="settings-box embedded continuation"> - <div class="start textarea" id="colorTemperatureLabel"> - $i18n{displayNightLightTemperatureLabel} + <template is="dom-if" if="[[nightLightFeatureEnabled_]]" restamp> + <div class="settings-box"> + <div class="start"> + <h2 id="nightLightLabel">$i18n{displayNightLightLabel}</h2> + <div class="secondary">$i18n{displayNightLightText}</div> </div> - <settings-slider id="colorTemperatureSlider" - aria-labelledby="colorTemperatureLabel" min="0" max="100" scale="100" - label-min="$i18n{displayNightLightTempSliderMinLabel}" - label-max="$i18n{displayNightLightTempSliderMaxLabel}" - pref="{{prefs.ash.night_light.color_temperature}}"> - </settings-slider> + <settings-toggle-button + id="nightLightToggleButton" + pref="{{prefs.ash.night_light.enabled}}" + aria-labelledby="nightLightLabel"> + </settings-toggle-button> </div> - </div> + <div id="nightLightSettingsDiv" + class="settings-box continuation start layout vertical"> + <!-- Color temperature slider --> + <div class="settings-box embedded continuation"> + <div class="start textarea" id="colorTemperatureLabel"> + $i18n{displayNightLightTemperatureLabel} + </div> + <settings-slider id="colorTemperatureSlider" + aria-labelledby="colorTemperatureLabel" min="0" max="100" + scale="100" label-min="$i18n{displayNightLightTempSliderMinLabel}" + label-max="$i18n{displayNightLightTempSliderMaxLabel}" + pref="{{prefs.ash.night_light.color_temperature}}"> + </settings-slider> + </div> + </div> + </template> </template> <script src="display.js"></script>
diff --git a/chrome/browser/resources/settings/device_page/display.js b/chrome/browser/resources/settings/device_page/display.js index 53ef67e..d7c2bd7 100644 --- a/chrome/browser/resources/settings/device_page/display.js +++ b/chrome/browser/resources/settings/device_page/display.js
@@ -81,6 +81,14 @@ }, /** @private */ + nightLightFeatureEnabled_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('nightLightFeatureEnabled'); + } + }, + + /** @private */ unifiedDesktopMode_: { type: Boolean, value: false,
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc b/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc index c265435..be1fa7f 100644 --- a/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc +++ b/chrome/browser/safe_browsing/certificate_reporting_service_browsertest.cc
@@ -388,15 +388,9 @@ ReportExpectation::Successful({{"report1", RetryStatus::RETRIED}})); } -// Failing on some Win and Mac buildbots. See crbug.com/719138. -#if defined(OS_WIN) || defined(OS_MACOSX) -#define MAYBE_DontSendOldReports DISABLED_DontSendOldReports -#else -#define MAYBE_DontSendOldReports DontSendOldReports -#endif // CertificateReportingService should ignore reports older than the report TTL. IN_PROC_BROWSER_TEST_F(CertificateReportingServiceBrowserTest, - MAYBE_DontSendOldReports) { + DontSendOldReports) { SetExpectedHistogramCountOnTeardown(5); base::SimpleTestClock* clock = new base::SimpleTestClock(); @@ -456,6 +450,15 @@ // Send pending reports. report2 should be discarded since it's too old. No // other reports remain. If any report is sent, test teardown will catch it. SendPendingReports(); + + // Let all reports succeed and send a single report. This is to make sure + // that any (incorrectly) pending reports are dropped before the test tear + // down. + test_helper()->SetFailureMode(certificate_reporting_test_utils:: + ReportSendingResult::REPORTS_SUCCESSFUL); + SendReport("report3"); + test_helper()->WaitForRequestsDestroyed( + ReportExpectation::Successful({{"report3", RetryStatus::NOT_RETRIED}})); } // CertificateReportingService should drop old reports from its pending report
diff --git a/chrome/browser/subresource_filter/subresource_filter_unittest.cc b/chrome/browser/subresource_filter/subresource_filter_unittest.cc index 60cc7e4..a98db80 100644 --- a/chrome/browser/subresource_filter/subresource_filter_unittest.cc +++ b/chrome/browser/subresource_filter/subresource_filter_unittest.cc
@@ -30,6 +30,7 @@ #include "components/subresource_filter/content/browser/content_ruleset_service.h" #include "components/subresource_filter/content/browser/content_subresource_filter_driver_factory.h" #include "components/subresource_filter/content/browser/fake_safe_browsing_database_manager.h" +#include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h" #include "components/subresource_filter/core/browser/ruleset_service.h" #include "components/subresource_filter/core/browser/subresource_filter_features.h" #include "components/subresource_filter/core/browser/subresource_filter_features_test_support.h" @@ -44,6 +45,7 @@ namespace { using subresource_filter::testing::ScopedSubresourceFilterConfigurator; using subresource_filter::testing::ScopedSubresourceFilterFeatureToggle; +const char kDisallowedUrl[] = "https://example.test/disallowed.html"; } // namespace // End to end unit test harness of (most of) the browser process portions of the @@ -148,8 +150,7 @@ content::RenderFrameHost* parent) { auto* subframe = content::RenderFrameHostTester::For(parent)->AppendChild("subframe"); - return SimulateNavigateAndCommit( - GURL("https://example.test/disallowed.html"), subframe); + return SimulateNavigateAndCommit(GURL(kDisallowedUrl), subframe); } void ConfigureAsSubresourceFilterOnlyURL(const GURL& url) { @@ -296,3 +297,21 @@ EXPECT_EQ(subresource_filter::ActivationDecision::UNSUPPORTED_SCHEME, driver_factory->GetActivationDecisionForLastCommittedPageLoad()); } + +TEST_F(SubresourceFilterTest, SimpleDisallowedLoad_WithObserver) { + GURL url("https://example.test"); + ConfigureAsSubresourceFilterOnlyURL(url); + + subresource_filter::TestSubresourceFilterObserver observer(web_contents()); + SimulateNavigateAndCommit(url, main_rfh()); + + EXPECT_EQ(subresource_filter::ActivationDecision::ACTIVATED, + observer.GetPageActivation(url).value()); + + EXPECT_FALSE(CreateAndNavigateDisallowedSubframe(main_rfh())); + auto optional_load_policy = + observer.GetSubframeLoadPolicy(GURL(kDisallowedUrl)); + EXPECT_TRUE(optional_load_policy.has_value()); + EXPECT_EQ(subresource_filter::LoadPolicy::DISALLOW, + observer.GetSubframeLoadPolicy(GURL(kDisallowedUrl)).value()); +}
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 21c8ad2..2730606 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -35,6 +35,7 @@ #if defined(OS_CHROMEOS) #include "ash/system/devicetype_utils.h" +#include "ash/system/night_light/night_light_controller.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h" #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" @@ -699,6 +700,9 @@ base::CommandLine::ForCurrentProcess()->HasSwitch( chromeos::switches::kEnableTouchCalibrationSetting)); + html_source->AddBoolean("nightLightFeatureEnabled", + ash::NightLightController::IsFeatureEnabled()); + LocalizedString storage_strings[] = { {"storageTitle", IDS_SETTINGS_STORAGE_TITLE}, {"storageItemInUse", IDS_SETTINGS_STORAGE_ITEM_IN_USE},
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py index ac414e1..859e32f 100755 --- a/chrome/test/chromedriver/test/run_py_tests.py +++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -1968,20 +1968,20 @@ def testDeviceName(self): driver = self.CreateDriver( - mobile_emulation = {'deviceName': 'Google Nexus 5'}) + mobile_emulation = {'deviceName': 'Nexus 5'}) driver.Load(self._http_server.GetUrl() + '/userAgentUseDeviceWidth') self.assertEqual(360, driver.ExecuteScript('return window.screen.width')) self.assertEqual(640, driver.ExecuteScript('return window.screen.height')) body_tag = driver.FindElement('tag name', 'body') self.assertEqual( - 'Mozilla/5.0 (Linux; Android 4.4.4; Nexus 5 Build/KTU84P) ' - 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.114 Mobile ' + 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) ' + 'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Mobile ' 'Safari/537.36', body_tag.GetText()) def testSendKeysToElement(self): driver = self.CreateDriver( - mobile_emulation = {'deviceName': 'Google Nexus 5'}) + mobile_emulation = {'deviceName': 'Nexus 5'}) text = driver.ExecuteScript( 'document.body.innerHTML = \'<input type="text">\';' 'var input = document.getElementsByTagName("input")[0];' @@ -1996,7 +1996,7 @@ def testClickElement(self): driver = self.CreateDriver( - mobile_emulation = {'deviceName': 'Google Nexus 5'}) + mobile_emulation = {'deviceName': 'Nexus 5'}) driver.Load('about:blank') div = driver.ExecuteScript( 'document.body.innerHTML = "<div>old</div>";' @@ -2010,7 +2010,7 @@ def testTapElement(self): driver = self.CreateDriver( - mobile_emulation = {'deviceName': 'Google Nexus 5'}) + mobile_emulation = {'deviceName': 'Nexus 5'}) driver.Load('about:blank') div = driver.ExecuteScript( 'document.body.innerHTML = "<div>old</div>";' @@ -2024,7 +2024,7 @@ def testHasTouchScreen(self): driver = self.CreateDriver( - mobile_emulation = {'deviceName': 'Google Nexus 5'}) + mobile_emulation = {'deviceName': 'Nexus 5'}) self.assertIn('hasTouchScreen', driver.capabilities) self.assertTrue(driver.capabilities['hasTouchScreen']) @@ -2073,14 +2073,14 @@ def testNetworkConnectionEnabled(self): # mobileEmulation must be enabled for networkConnection to be enabled driver = self.CreateDriver( - mobile_emulation={'deviceName': 'Google Nexus 5'}, + mobile_emulation={'deviceName': 'Nexus 5'}, network_connection=True) self.assertTrue(driver.capabilities['mobileEmulationEnabled']) self.assertTrue(driver.capabilities['networkConnectionEnabled']) def testEmulateNetworkConnection4g(self): driver = self.CreateDriver( - mobile_emulation={'deviceName': 'Google Nexus 5'}, + mobile_emulation={'deviceName': 'Nexus 5'}, network_connection=True) # Test 4G connection. connection_type = 0x8 @@ -2091,7 +2091,7 @@ def testEmulateNetworkConnectionMultipleBits(self): driver = self.CreateDriver( - mobile_emulation={'deviceName': 'Google Nexus 5'}, + mobile_emulation={'deviceName': 'Nexus 5'}, network_connection=True) # Connection with 4G, 3G, and 2G bits on. # Tests that 4G takes precedence. @@ -2103,7 +2103,7 @@ def testWifiAndAirplaneModeEmulation(self): driver = self.CreateDriver( - mobile_emulation={'deviceName': 'Google Nexus 5'}, + mobile_emulation={'deviceName': 'Nexus 5'}, network_connection=True) # Connection with both Wifi and Airplane Mode on. # Tests that Wifi takes precedence over Airplane Mode. @@ -2124,7 +2124,7 @@ '/helloworld', respondWithString) driver = self.CreateDriver( - mobile_emulation={'deviceName': 'Google Nexus 5'}, + mobile_emulation={'deviceName': 'Nexus 5'}, network_connection=True) # Set network to online @@ -2158,7 +2158,7 @@ def testNetworkConnectionTypeIsAppliedToAllTabs(self): driver = self.CreateDriver( - mobile_emulation={'deviceName': 'Google Nexus 5'}, + mobile_emulation={'deviceName': 'Nexus 5'}, network_connection=True) driver.Load(self._http_server.GetUrl() +'/chromedriver/page_test.html') window1_handle = driver.GetCurrentWindowHandle()
diff --git a/chromeos/network/network_connect.cc b/chromeos/network/network_connect.cc index 5778905..c3553e2b6 100644 --- a/chromeos/network/network_connect.cc +++ b/chromeos/network/network_connect.cc
@@ -435,31 +435,27 @@ network_handler::ErrorCallback()); return; } - // If we're dealing with a mobile network, then handle SIM lock here. - // SIM locking only applies to cellular, so the code below won't execute - // if |technology| has been explicitly set to WiMAX. - if (technology.MatchesPattern(NetworkTypePattern::Mobile())) { + // If we're dealing with a cellular network, then handle SIM lock here. + // SIM locking only applies to cellular. + if (technology.MatchesPattern(NetworkTypePattern::Cellular())) { const DeviceState* mobile = handler->GetDeviceStateByType(technology); if (!mobile) { NET_LOG_ERROR("SetTechnologyEnabled with no device", log_string); return; } - // The following only applies to cellular. - if (mobile->type() == shill::kTypeCellular) { - if (mobile->IsSimAbsent()) { - // If this is true, then we have a cellular device with no SIM - // inserted. TODO(armansito): Chrome should display a notification here, - // prompting the user to insert a SIM card and restart the device to - // enable cellular. See crbug.com/125171. - NET_LOG_USER("Cannot enable cellular device without SIM.", log_string); - return; - } - if (!mobile->sim_lock_type().empty()) { - // A SIM has been inserted, but it is locked. Let the user unlock it - // via the dialog. - delegate_->ShowMobileSimDialog(); - return; - } + if (mobile->IsSimAbsent()) { + // If this is true, then we have a cellular device with no SIM + // inserted. TODO(armansito): Chrome should display a notification here, + // prompting the user to insert a SIM card and restart the device to + // enable cellular. See crbug.com/125171. + NET_LOG_USER("Cannot enable cellular device without SIM.", log_string); + return; + } + if (!mobile->sim_lock_type().empty()) { + // A SIM has been inserted, but it is locked. Let the user unlock it + // via the dialog. + delegate_->ShowMobileSimDialog(); + return; } } handler->SetTechnologyEnabled(technology, true,
diff --git a/chromeos/network/network_type_pattern.cc b/chromeos/network/network_type_pattern.cc index dbda85ba..0cfe2d5 100644 --- a/chromeos/network/network_type_pattern.cc +++ b/chromeos/network/network_type_pattern.cc
@@ -15,11 +15,9 @@ namespace { const char kPatternDefault[] = "PatternDefault"; -const char kPatternEthernet[] = "PatternEthernet"; const char kPatternWireless[] = "PatternWireless"; const char kPatternMobile[] = "PatternMobile"; const char kPatternNonVirtual[] = "PatternNonVirtual"; -const char kPatternTether[] = "PatternTether"; enum NetworkTypeBitFlag { kNetworkTypeNone = 0, @@ -69,7 +67,8 @@ // static NetworkTypePattern NetworkTypePattern::Mobile() { - return NetworkTypePattern(kNetworkTypeCellular | kNetworkTypeWimax); + return NetworkTypePattern(kNetworkTypeCellular | kNetworkTypeWimax | + kNetworkTypeTether); } // static @@ -133,17 +132,14 @@ std::string NetworkTypePattern::ToDebugString() const { if (Equals(Default())) return kPatternDefault; - if (Equals(Ethernet())) - return kPatternEthernet; if (Equals(Wireless())) return kPatternWireless; if (Equals(Mobile())) return kPatternMobile; if (Equals(NonVirtual())) return kPatternNonVirtual; - if (Equals(Tether())) - return kPatternTether; + // Note: shill_type_to_flag includes kTypeTether. std::string str; for (size_t i = 0; i < arraysize(shill_type_to_flag); ++i) { if (!(pattern_ & shill_type_to_flag[i].bit_flag))
diff --git a/chromeos/network/network_type_pattern.h b/chromeos/network/network_type_pattern.h index 8dd214fc..1fde992b 100644 --- a/chromeos/network/network_type_pattern.h +++ b/chromeos/network/network_type_pattern.h
@@ -17,10 +17,10 @@ // Matches any network. static NetworkTypePattern Default(); - // Matches wireless (WiFi, cellular, etc.) networks + // Matches wireless (WiFi, Cellular, etc.) networks static NetworkTypePattern Wireless(); - // Matches cellular or wimax networks. + // Matches Cellular, WiMAX, or Tether networks. static NetworkTypePattern Mobile(); // Matches non virtual networks.
diff --git a/chromeos/network/network_type_pattern_unittest.cc b/chromeos/network/network_type_pattern_unittest.cc index 142f403b..53f10ea 100644 --- a/chromeos/network/network_type_pattern_unittest.cc +++ b/chromeos/network/network_type_pattern_unittest.cc
@@ -22,7 +22,9 @@ non_virtual_(NetworkTypePattern::NonVirtual()), wimax_(NetworkTypePattern::Wimax()), wireless_(NetworkTypePattern::Wireless()), - tether_(NetworkTypePattern::Tether()) {} + tether_(NetworkTypePattern::Tether()), + vpn_(NetworkTypePattern::VPN()), + wifi_(NetworkTypePattern::WiFi()) {} bool MatchesPattern(const NetworkTypePattern& a, const NetworkTypePattern& b) { @@ -40,21 +42,38 @@ const NetworkTypePattern wimax_; const NetworkTypePattern wireless_; const NetworkTypePattern tether_; + const NetworkTypePattern vpn_; + const NetworkTypePattern wifi_; }; } // namespace TEST_F(NetworkTypePatternTest, MatchesType) { + // Mobile contains Cellular, Wimax, and Tether. EXPECT_TRUE(mobile_.MatchesType(shill::kTypeCellular)); EXPECT_TRUE(mobile_.MatchesType(shill::kTypeWimax)); + EXPECT_TRUE(mobile_.MatchesType(kTypeTether)); EXPECT_FALSE(mobile_.MatchesType(shill::kTypeWifi)); + EXPECT_FALSE(mobile_.MatchesType(shill::kTypeEthernet)); + EXPECT_FALSE(mobile_.MatchesType(shill::kTypeVPN)); + // Wireless contains Wifi, Cellular, and Wimax. EXPECT_TRUE(wireless_.MatchesType(shill::kTypeWifi)); EXPECT_TRUE(wireless_.MatchesType(shill::kTypeCellular)); EXPECT_TRUE(wireless_.MatchesType(shill::kTypeWimax)); EXPECT_FALSE(wireless_.MatchesType(shill::kTypeEthernet)); - + EXPECT_FALSE(wireless_.MatchesType(shill::kTypeVPN)); EXPECT_FALSE(wireless_.MatchesType(kTypeTether)); + + // Non-virtual contains everything except VPN and Tether. + EXPECT_TRUE(non_virtual_.MatchesType(shill::kTypeCellular)); + EXPECT_TRUE(non_virtual_.MatchesType(shill::kTypeWifi)); + EXPECT_TRUE(non_virtual_.MatchesType(shill::kTypeEthernet)); + EXPECT_TRUE(non_virtual_.MatchesType(shill::kTypeWimax)); + EXPECT_FALSE(non_virtual_.MatchesType(shill::kTypeVPN)); + EXPECT_FALSE(non_virtual_.MatchesType(kTypeTether)); + + EXPECT_TRUE(wimax_.MatchesType(shill::kTypeWimax)); EXPECT_FALSE(wimax_.MatchesType(kTypeTether)); } @@ -104,8 +123,15 @@ TEST_F(NetworkTypePatternTest, ToDebugString) { EXPECT_EQ(default_.ToDebugString(), "PatternDefault"); + EXPECT_EQ(wireless_.ToDebugString(), "PatternWireless"); EXPECT_EQ(mobile_.ToDebugString(), "PatternMobile"); - EXPECT_EQ(cellular_.ToDebugString(), "cellular"); + EXPECT_EQ(non_virtual_.ToDebugString(), "PatternNonVirtual"); + EXPECT_EQ(ethernet_.ToDebugString(), shill::kTypeEthernet); + EXPECT_EQ(cellular_.ToDebugString(), shill::kTypeCellular); + EXPECT_EQ(wimax_.ToDebugString(), shill::kTypeWimax); + EXPECT_EQ(tether_.ToDebugString(), kTypeTether); + EXPECT_EQ(wifi_.ToDebugString(), shill::kTypeWifi); + EXPECT_EQ(vpn_.ToDebugString(), shill::kTypeVPN); } } // namespace chromeos
diff --git a/components/BUILD.gn b/components/BUILD.gn index 482b3b8..71bc853 100644 --- a/components/BUILD.gn +++ b/components/BUILD.gn
@@ -85,6 +85,7 @@ "//components/download:unit_tests", "//components/favicon/core:unit_tests", "//components/favicon_base:unit_tests", + "//components/feature_engagement_tracker:unit_tests", "//components/flags_ui:unit_tests", "//components/gcm_driver:unit_tests", "//components/gcm_driver/crypto:unit_tests", @@ -243,7 +244,6 @@ if (is_android) { deps += [ "//components/cdm/browser:unit_tests", - "//components/feature_engagement_tracker:unit_tests", "//components/gcm_driver/instance_id:test_support", "//components/gcm_driver/instance_id/android:instance_id_driver_java", "//components/gcm_driver/instance_id/android:instance_id_driver_test_support_java",
diff --git a/components/browser_watcher/BUILD.gn b/components/browser_watcher/BUILD.gn index 7e459f07..124571da 100644 --- a/components/browser_watcher/BUILD.gn +++ b/components/browser_watcher/BUILD.gn
@@ -126,6 +126,7 @@ "postmortem_minidump_writer_win_unittest.cc", "postmortem_report_collector_unittest.cc", "stability_debugging_win_unittest.cc", + "stability_paths_unittest.cc", "system_session_analyzer_win_unittest.cc", "watcher_client_win_unittest.cc", "watcher_metrics_provider_win_unittest.cc",
diff --git a/components/browser_watcher/features.cc b/components/browser_watcher/features.cc index 399e49b..76ecd82 100644 --- a/components/browser_watcher/features.cc +++ b/components/browser_watcher/features.cc
@@ -11,4 +11,6 @@ const char kInitFlushParam[] = "init_flush"; +const char kCollectPostmortemParam[] = "collect_postmortem"; + } // namespace browser_watcher
diff --git a/components/browser_watcher/features.h b/components/browser_watcher/features.h index 8f3503a6c..5f067f6 100644 --- a/components/browser_watcher/features.h +++ b/components/browser_watcher/features.h
@@ -17,6 +17,10 @@ // flush. extern const char kInitFlushParam[]; +// Name of an experiment parameter that controls whether to collect postmortem +// reports. +extern const char kCollectPostmortemParam[]; + } // namespace browser_watcher #endif // COMPONENTS_BROWSER_WATCHER_FEATURES_H_
diff --git a/components/browser_watcher/postmortem_report_collector.cc b/components/browser_watcher/postmortem_report_collector.cc index ef21d84..80ce8c75 100644 --- a/components/browser_watcher/postmortem_report_collector.cc +++ b/components/browser_watcher/postmortem_report_collector.cc
@@ -6,7 +6,6 @@ #include <utility> -#include "base/files/file_enumerator.h" #include "base/files/file_util.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" @@ -60,102 +59,58 @@ } // namespace +void PostmortemDeleter::Process( + const std::vector<base::FilePath>& stability_files) { + for (const FilePath& file : stability_files) { + if (base::DeleteFile(file, false)) + LogCollectionStatus(UNCLEAN_SHUTDOWN); + else + LogCollectionStatus(DEBUG_FILE_DELETION_FAILED); + } +} + PostmortemReportCollector::PostmortemReportCollector( const std::string& product_name, const std::string& version_number, const std::string& channel_name, + crashpad::CrashReportDatabase* report_database, SystemSessionAnalyzer* analyzer) : product_name_(product_name), version_number_(version_number), channel_name_(channel_name), - system_session_analyzer_(analyzer) {} + report_database_(report_database), + system_session_analyzer_(analyzer) { + DCHECK_NE(nullptr, report_database); +} PostmortemReportCollector::~PostmortemReportCollector() {} -int PostmortemReportCollector::CollectAndSubmitAllPendingReports( - const base::FilePath& debug_info_dir, - const base::FilePath::StringType& debug_file_pattern, - const std::set<base::FilePath>& excluded_debug_files, - crashpad::CrashReportDatabase* report_database) { - DCHECK_NE(true, debug_info_dir.empty()); - DCHECK_NE(true, debug_file_pattern.empty()); - DCHECK_NE(nullptr, report_database); - - // Collect the list of files to harvest. - std::vector<FilePath> debug_files = GetDebugStateFilePaths( - debug_info_dir, debug_file_pattern, excluded_debug_files); - UMA_HISTOGRAM_COUNTS_100("ActivityTracker.Collect.StabilityFileCount", - debug_files.size()); - +void PostmortemReportCollector::Process( + const std::vector<base::FilePath>& stability_files) { // Determine the crashpad client id. crashpad::UUID client_id; - crashpad::Settings* settings = report_database->GetSettings(); + crashpad::Settings* settings = report_database_->GetSettings(); if (settings) { // If GetSettings() or GetClientID() fails client_id will be left at its // default value, all zeroes, which is appropriate. settings->GetClientID(&client_id); } - // Number of unclean shutdowns based on successful collection of stability - // reports. - int unclean_cnt = 0; - // Number of unclean shutdowns that may be attributable to system instability - // based on successful collection of stability reports. This number should be - // smaller or equal to |unclean_cnt|. - int unclean_system_cnt = 0; - - // Process each stability file. - for (const FilePath& file : debug_files) { - bool system_unclean = false; - if (CollectAndSubmitOneReport(client_id, file, report_database, - &system_unclean)) { - ++unclean_cnt; - if (system_unclean) - ++unclean_system_cnt; - } + for (const FilePath& file : stability_files) { + CollectAndSubmitOneReport(client_id, file); } - - UMA_STABILITY_HISTOGRAM_COUNTS_100( - "ActivityTracker.Collect.UncleanShutdownCount", unclean_cnt); - UMA_STABILITY_HISTOGRAM_COUNTS_100( - "ActivityTracker.Collect.UncleanSystemCount", unclean_system_cnt); - - return unclean_cnt; } -std::vector<FilePath> PostmortemReportCollector::GetDebugStateFilePaths( - const FilePath& debug_info_dir, - const FilePath::StringType& debug_file_pattern, - const std::set<FilePath>& excluded_debug_files) { - DCHECK_NE(true, debug_info_dir.empty()); - DCHECK_NE(true, debug_file_pattern.empty()); - - std::vector<FilePath> paths; - base::FileEnumerator enumerator(debug_info_dir, false /* recursive */, - base::FileEnumerator::FILES, - debug_file_pattern); - FilePath path; - for (path = enumerator.Next(); !path.empty(); path = enumerator.Next()) { - if (excluded_debug_files.find(path) == excluded_debug_files.end()) - paths.push_back(path); - } - return paths; -} - -bool PostmortemReportCollector::CollectAndSubmitOneReport( +void PostmortemReportCollector::CollectAndSubmitOneReport( const crashpad::UUID& client_id, - const FilePath& file, - crashpad::CrashReportDatabase* report_database, - bool* system_unclean) { - DCHECK_NE(nullptr, report_database); - DCHECK_NE(nullptr, system_unclean); - *system_unclean = false; + const FilePath& file) { + DCHECK_NE(nullptr, report_database_); + LogCollectionStatus(COLLECTION_ATTEMPT); // Note: the code below involves two notions of report: chrome internal state // reports and the crashpad reports they get wrapped into. - // Collect the data from the debug file to a proto. Note: a non-empty report - // is interpreted here as an unclean exit. + // Collect the data from the debug file to a proto. StabilityReport report_proto; CollectionStatus status = CollectOneReport(file, &report_proto); if (status != SUCCESS) { @@ -164,41 +119,41 @@ if (!base::DeleteFile(file, false)) DLOG(ERROR) << "Failed to delete " << file.value(); LogCollectionStatus(status); - return false; + return; } + // Delete the stability file. If the file cannot be deleted, do not report its + // contents - it will be retried in a future processing run. Note that this + // approach can lead to under reporting and retries. However, under reporting + // is preferable to the over reporting that would happen with a file that + // cannot be deleted. Also note that the crash registration may still fail at + // this point: losing the report in such a case is deemed acceptable. + if (!base::DeleteFile(file, false)) { + DLOG(ERROR) << "Failed to delete " << file.value(); + LogCollectionStatus(DEBUG_FILE_DELETION_FAILED); + return; + } + + LogCollectionStatus(UNCLEAN_SHUTDOWN); + if (report_proto.system_state().session_state() == SystemState::UNCLEAN) + LogCollectionStatus(UNCLEAN_SESSION); + // Prepare a crashpad report. CrashReportDatabase::NewReport* new_report = nullptr; CrashReportDatabase::OperationStatus database_status = - report_database->PrepareNewCrashReport(&new_report); + report_database_->PrepareNewCrashReport(&new_report); if (database_status != CrashReportDatabase::kNoError) { - // Assume this is recoverable: not deleting the file. - DLOG(ERROR) << "PrepareNewCrashReport failed"; LogCollectionStatus(PREPARE_NEW_CRASH_REPORT_FAILED); - return false; + return; } CrashReportDatabase::CallErrorWritingCrashReport - call_error_writing_crash_report(report_database, new_report); + call_error_writing_crash_report(report_database_, new_report); // Write the report to a minidump. if (!WriteReportToMinidump(&report_proto, client_id, new_report->uuid, reinterpret_cast<FILE*>(new_report->handle))) { - // Assume this is not recoverable and delete the file. - if (!base::DeleteFile(file, false)) - DLOG(ERROR) << "Failed to delete " << file.value(); LogCollectionStatus(WRITE_TO_MINIDUMP_FAILED); - return false; - } - - // If the file cannot be deleted, do not report its contents. Note this can - // lead to under reporting and retries. However, under reporting is - // preferable to the over reporting that would happen with a file that - // cannot be deleted. - // TODO(manzagop): metrics for the number of non-deletable files. - if (!base::DeleteFile(file, false)) { - DLOG(ERROR) << "Failed to delete " << file.value(); - LogCollectionStatus(DEBUG_FILE_DELETION_FAILED); - return false; + return; } // Finalize the report wrt the report database. Note that this doesn't trigger @@ -206,18 +161,14 @@ // writing, the delay is on the order of up to 15 minutes). call_error_writing_crash_report.Disarm(); crashpad::UUID unused_report_id; - database_status = report_database->FinishedWritingCrashReport( + database_status = report_database_->FinishedWritingCrashReport( new_report, &unused_report_id); if (database_status != CrashReportDatabase::kNoError) { - DLOG(ERROR) << "FinishedWritingCrashReport failed"; LogCollectionStatus(FINISHED_WRITING_CRASH_REPORT_FAILED); - return false; + return; } LogCollectionStatus(SUCCESS); - if (report_proto.system_state().session_state() == SystemState::UNCLEAN) - *system_unclean = true; - return true; } CollectionStatus PostmortemReportCollector::CollectOneReport(
diff --git a/components/browser_watcher/postmortem_report_collector.h b/components/browser_watcher/postmortem_report_collector.h index 0187181..436c16d4 100644 --- a/components/browser_watcher/postmortem_report_collector.h +++ b/components/browser_watcher/postmortem_report_collector.h
@@ -28,6 +28,15 @@ namespace browser_watcher { +// Deletes stability files. +class PostmortemDeleter { + public: + PostmortemDeleter() = default; + ~PostmortemDeleter() = default; + + void Process(const std::vector<base::FilePath>& stability_files); +}; + // Handles postmortem report collection by establishing the set of stability // files to collect, then for each file: // - extracting a report protocol buffer @@ -39,20 +48,13 @@ PostmortemReportCollector(const std::string& product_name, const std::string& version_number, const std::string& channel_name, + crashpad::CrashReportDatabase* report_database, SystemSessionAnalyzer* analyzer); - virtual ~PostmortemReportCollector(); + ~PostmortemReportCollector(); - // Collects postmortem stability reports from files found in |debug_info_dir|, - // relying on |debug_file_pattern| and |excluded_debug_files|. Reports are - // then wrapped in Crashpad reports, manufactured via |report_database|. - // Returns the number crash reports successfully registered with the reporter. - // TODO(manzagop): consider mechanisms for partial collection if this is to be - // used on a critical path. - int CollectAndSubmitAllPendingReports( - const base::FilePath& debug_info_dir, - const base::FilePath::StringType& debug_file_pattern, - const std::set<base::FilePath>& excluded_debug_files, - crashpad::CrashReportDatabase* report_database); + // Collects postmortem stability reports from |stability_files|. Reports are + // then wrapped in Crashpad reports and registered with the crash database. + void Process(const std::vector<base::FilePath>& stability_files); const std::string& product_name() const { return product_name_; } const std::string& version_number() const { return version_number_; } @@ -81,18 +83,10 @@ PostmortemReportCollectorCollectionFromGlobalTrackerTest, SystemStateTest); - // Virtual for unittesting. - virtual std::vector<base::FilePath> GetDebugStateFilePaths( - const base::FilePath& debug_info_dir, - const base::FilePath::StringType& debug_file_pattern, - const std::set<base::FilePath>& excluded_debug_files); - // Collects a stability file, generates a report and registers it with the - // database. Returns true on success. False otherwise. - bool CollectAndSubmitOneReport(const crashpad::UUID& client_id, - const base::FilePath& file, - crashpad::CrashReportDatabase* report_database, - bool* system_unclean); + // database. + void CollectAndSubmitOneReport(const crashpad::UUID& client_id, + const base::FilePath& file); virtual CollectionStatus CollectOneReport( const base::FilePath& stability_file, @@ -111,6 +105,7 @@ std::string version_number_; std::string channel_name_; + crashpad::CrashReportDatabase* report_database_; // Not owned. SystemSessionAnalyzer* system_session_analyzer_; // Not owned. DISALLOW_COPY_AND_ASSIGN(PostmortemReportCollector);
diff --git a/components/browser_watcher/postmortem_report_collector_unittest.cc b/components/browser_watcher/postmortem_report_collector_unittest.cc index 791a6cb..bd615e6e 100644 --- a/components/browser_watcher/postmortem_report_collector_unittest.cc +++ b/components/browser_watcher/postmortem_report_collector_unittest.cc
@@ -40,6 +40,7 @@ using base::debug::GlobalActivityTracker; using base::debug::ThreadActivityTracker; using base::File; +using base::FilePath; using base::FilePersistentMemoryAllocator; using base::MemoryMappedFile; using base::PersistentMemoryAllocator; @@ -54,6 +55,58 @@ namespace { +TEST(PostmortemDeleterTest, BasicTest) { + base::HistogramTester histogram_tester; + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + // Create three files. + FilePath path_one = temp_dir.GetPath().AppendASCII("a.pma"); + FilePath path_two = temp_dir.GetPath().AppendASCII("b.pma"); + FilePath path_three = temp_dir.GetPath().AppendASCII("c.pma"); + + std::vector<FilePath> stability_files = {path_one, path_two, path_three}; + + for (const FilePath& path : stability_files) { + { + base::ScopedFILE file(base::OpenFile(path, "w")); + ASSERT_NE(file.get(), nullptr); + } + ASSERT_TRUE(base::PathExists(path)); + } + + // Open one stability file to prevent its deletion. + base::ScopedFILE file(base::OpenFile(path_two, "w")); + ASSERT_NE(file.get(), nullptr); + + // Validate deletion and metrics. + PostmortemDeleter deleter; + deleter.Process(stability_files); + + ASSERT_FALSE(base::PathExists(path_one)); + ASSERT_FALSE(base::PathExists(path_three)); + histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status", + UNCLEAN_SHUTDOWN, 2); + + ASSERT_TRUE(base::PathExists(path_two)); + histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status", + DEBUG_FILE_DELETION_FAILED, 1); + + std::vector<CollectionStatus> unexpected_statuses = { + NONE, + SUCCESS, + ANALYZER_CREATION_FAILED, + DEBUG_FILE_NO_DATA, + PREPARE_NEW_CRASH_REPORT_FAILED, + WRITE_TO_MINIDUMP_FAILED, + FINISHED_WRITING_CRASH_REPORT_FAILED, + COLLECTION_ATTEMPT}; + for (CollectionStatus status : unexpected_statuses) { + histogram_tester.ExpectBucketCount("ActivityTracker.Collect.Status", status, + 0); + } +} + const char kProductName[] = "TestProduct"; const char kVersionNumber[] = "TestVersionNumber"; const char kChannelName[] = "TestChannel"; @@ -113,23 +166,17 @@ CrashReportDatabase::OperationStatus(const UUID& uuid)); }; -// Used for testing CollectAndSubmitAllPendingReports. class MockPostmortemReportCollector : public PostmortemReportCollector { public: - MockPostmortemReportCollector() + explicit MockPostmortemReportCollector(CrashReportDatabase* crash_database) : PostmortemReportCollector(kProductName, kVersionNumber, kChannelName, + crash_database, nullptr) {} - MOCK_METHOD3(GetDebugStateFilePaths, - std::vector<base::FilePath>( - const base::FilePath& debug_info_dir, - const base::FilePath::StringType& debug_file_pattern, - const std::set<base::FilePath>&)); MOCK_METHOD2(CollectOneReport, - CollectionStatus(const base::FilePath&, - StabilityReport* report)); + CollectionStatus(const FilePath&, StabilityReport* report)); MOCK_METHOD4(WriteReportToMinidump, bool(StabilityReport* report, const crashpad::UUID& client_id, @@ -164,10 +211,11 @@ } // namespace -class PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest - : public testing::Test { +class PostmortemReportCollectorProcessTest : public testing::Test { public: - void SetUpTest(bool system_session_clean) { + void SetUpTest(bool system_session_clean, bool expect_write_dump) { + collector_.reset(new MockPostmortemReportCollector(&database_)); + // Create a dummy debug file. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); debug_file_ = temp_dir_.GetPath().AppendASCII("foo-1.pma"); @@ -177,29 +225,23 @@ } ASSERT_TRUE(base::PathExists(debug_file_)); - // Expect collection of the debug file paths. - debug_file_pattern_ = FILE_PATH_LITERAL("foo-*.pma"); - std::vector<base::FilePath> debug_files{debug_file_}; - EXPECT_CALL(collector_, - GetDebugStateFilePaths(debug_file_.DirName(), - debug_file_pattern_, no_excluded_files_)) - .Times(1) - .WillOnce(Return(debug_files)); - EXPECT_CALL(database_, GetSettings()).Times(1).WillOnce(Return(nullptr)); // Expect a single collection call. StabilityReport report; report.mutable_system_state()->set_session_state( system_session_clean ? SystemState::CLEAN : SystemState::UNCLEAN); - EXPECT_CALL(collector_, CollectOneReport(debug_file_, _)) + EXPECT_CALL(*collector_, CollectOneReport(debug_file_, _)) .Times(1) .WillOnce(DoAll(SetArgPointee<1>(report), Return(SUCCESS))); + if (!expect_write_dump) + return; + // Expect the call to write the proto to a minidump. This involves // requesting a report from the crashpad database, writing the report, then // finalizing it with the database. - base::FilePath minidump_path = temp_dir_.GetPath().AppendASCII("foo-1.dmp"); + FilePath minidump_path = temp_dir_.GetPath().AppendASCII("foo-1.dmp"); base::File minidump_file( minidump_path, base::File::FLAG_CREATE | base::File::File::FLAG_WRITE); crashpad::UUID new_report_uuid; @@ -211,137 +253,79 @@ .WillOnce(DoAll(SetArgPointee<0>(&crashpad_report_), Return(CrashReportDatabase::kNoError))); - EXPECT_CALL(collector_, + EXPECT_CALL(*collector_, WriteReportToMinidump(_, _, _, minidump_file.GetPlatformFile())) .Times(1) .WillOnce(Return(true)); } void ValidateHistograms(int unclean_cnt, int unclean_system_cnt) { - histogram_tester_.ExpectTotalCount( - "ActivityTracker.Collect.StabilityFileCount", 1); - histogram_tester_.ExpectBucketCount( - "ActivityTracker.Collect.StabilityFileCount", 1, 1); - histogram_tester_.ExpectTotalCount( - "ActivityTracker.Collect.UncleanShutdownCount", 1); - histogram_tester_.ExpectBucketCount( - "ActivityTracker.Collect.UncleanShutdownCount", unclean_cnt, 1); - histogram_tester_.ExpectTotalCount( - "ActivityTracker.Collect.UncleanSystemCount", 1); - histogram_tester_.ExpectBucketCount( - "ActivityTracker.Collect.UncleanSystemCount", unclean_system_cnt, 1); + histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", + UNCLEAN_SHUTDOWN, unclean_cnt); + histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", + UNCLEAN_SESSION, unclean_system_cnt); } void CollectReports(bool is_session_clean) { - SetUpTest(is_session_clean); + SetUpTest(is_session_clean, true); EXPECT_CALL(database_, FinishedWritingCrashReport(&crashpad_report_, _)) .Times(1) .WillOnce(Return(CrashReportDatabase::kNoError)); // Run the test. - int success_cnt = collector_.CollectAndSubmitAllPendingReports( - debug_file_.DirName(), debug_file_pattern_, no_excluded_files_, - &database_); - ASSERT_EQ(1, success_cnt); + std::vector<FilePath> debug_files{debug_file_}; + collector_->Process(debug_files); ASSERT_FALSE(base::PathExists(debug_file_)); } protected: base::HistogramTester histogram_tester_; base::ScopedTempDir temp_dir_; - base::FilePath debug_file_; + FilePath debug_file_; MockCrashReportDatabase database_; - MockPostmortemReportCollector collector_; - base::FilePath::StringType debug_file_pattern_; - std::set<base::FilePath> no_excluded_files_; + std::unique_ptr<MockPostmortemReportCollector> collector_; CrashReportDatabase::NewReport crashpad_report_; }; -TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, - CollectAndSubmitAllPendingReportsCleanSession) { +TEST_F(PostmortemReportCollectorProcessTest, ProcessCleanSession) { CollectReports(true); int expected_unclean = 1; int expected_system_unclean = 0; ValidateHistograms(expected_unclean, expected_system_unclean); } -TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, - CollectAndSubmitAllPendingReportsUncleanSession) { +TEST_F(PostmortemReportCollectorProcessTest, ProcessUncleanSession) { CollectReports(false); int expected_unclean = 1; int expected_system_unclean = 1; ValidateHistograms(expected_unclean, expected_system_unclean); } -TEST_F(PostmortemReportCollectorCollectAndSubmitAllPendingReportsTest, - CollectAndSubmitAllPendingReportsStuckFile) { - SetUpTest(true); +TEST_F(PostmortemReportCollectorProcessTest, ProcessStuckFile) { + bool system_session_clean = true; + bool expect_write_dump = false; + SetUpTest(system_session_clean, expect_write_dump); // Open the stability debug file to prevent its deletion. base::ScopedFILE file(base::OpenFile(debug_file_, "w")); ASSERT_NE(file.get(), nullptr); - // Expect Crashpad is notified of an error writing the crash report. - EXPECT_CALL(database_, ErrorWritingCrashReport(&crashpad_report_)) - .Times(1) - .WillOnce(Return(CrashReportDatabase::kNoError)); - // Run the test. - int success_cnt = collector_.CollectAndSubmitAllPendingReports( - debug_file_.DirName(), debug_file_pattern_, no_excluded_files_, - &database_); - ASSERT_EQ(0, success_cnt); + std::vector<FilePath> debug_files{debug_file_}; + collector_->Process(debug_files); ASSERT_TRUE(base::PathExists(debug_file_)); + histogram_tester_.ExpectBucketCount("ActivityTracker.Collect.Status", + DEBUG_FILE_DELETION_FAILED, 1); int expected_unclean = 0; int expected_system_unclean = 0; ValidateHistograms(expected_unclean, expected_system_unclean); } -TEST(PostmortemReportCollectorTest, GetDebugStateFilePaths) { - base::ScopedTempDir temp_dir; - ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - - // Create files. - std::vector<base::FilePath> expected_paths; - std::set<base::FilePath> excluded_paths; - { - // Matches the pattern. - base::FilePath path = temp_dir.GetPath().AppendASCII("foo1.pma"); - base::ScopedFILE file(base::OpenFile(path, "w")); - ASSERT_NE(file.get(), nullptr); - expected_paths.push_back(path); - - // Matches the pattern, but is excluded. - path = temp_dir.GetPath().AppendASCII("foo2.pma"); - file.reset(base::OpenFile(path, "w")); - ASSERT_NE(file.get(), nullptr); - ASSERT_TRUE(excluded_paths.insert(path).second); - - // Matches the pattern. - path = temp_dir.GetPath().AppendASCII("foo3.pma"); - file.reset(base::OpenFile(path, "w")); - ASSERT_NE(file.get(), nullptr); - expected_paths.push_back(path); - - // Does not match the pattern. - path = temp_dir.GetPath().AppendASCII("bar.baz"); - file.reset(base::OpenFile(path, "w")); - ASSERT_NE(file.get(), nullptr); - } - - PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, nullptr); - EXPECT_THAT( - collector.GetDebugStateFilePaths( - temp_dir.GetPath(), FILE_PATH_LITERAL("foo*.pma"), excluded_paths), - testing::UnorderedElementsAreArray(expected_paths)); -} - TEST(PostmortemReportCollectorTest, CollectEmptyFile) { // Create an empty file. base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - base::FilePath file_path = temp_dir.GetPath().AppendASCII("empty.pma"); + FilePath file_path = temp_dir.GetPath().AppendASCII("empty.pma"); { base::ScopedFILE file(base::OpenFile(file_path, "w")); ASSERT_NE(file.get(), nullptr); @@ -349,8 +333,9 @@ ASSERT_TRUE(PathExists(file_path)); // Validate collection: an empty file cannot suppport an analyzer. + MockCrashReportDatabase crash_db; PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, nullptr); + kChannelName, &crash_db, nullptr); StabilityReport report; ASSERT_EQ(ANALYZER_CREATION_FAILED, collector.CollectOneReport(file_path, &report)); @@ -360,8 +345,7 @@ // Create a file with content we don't expect to be valid for a debug file. base::ScopedTempDir temp_dir; ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); - base::FilePath file_path = - temp_dir.GetPath().AppendASCII("invalid_content.pma"); + FilePath file_path = temp_dir.GetPath().AppendASCII("invalid_content.pma"); { base::ScopedFILE file(base::OpenFile(file_path, "w")); ASSERT_NE(file.get(), nullptr); @@ -376,8 +360,9 @@ // Validate collection: random content appears as though there is not // stability data. + MockCrashReportDatabase crash_db; PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, nullptr); + kChannelName, &crash_db, nullptr); StabilityReport report; ASSERT_NE(SUCCESS, collector.CollectOneReport(file_path, &report)); } @@ -466,11 +451,11 @@ return WrapUnique(new ThreadActivityTracker(mem_base, tracker_mem_size)); } - const base::FilePath& debug_file_path() const { return debug_file_path_; } + const FilePath& debug_file_path() const { return debug_file_path_; } protected: base::ScopedTempDir temp_dir_; - base::FilePath debug_file_path_; + FilePath debug_file_path_; std::unique_ptr<PersistentMemoryAllocator> allocator_; std::unique_ptr<ThreadActivityTracker> tracker_; @@ -506,8 +491,9 @@ user_data->SetInt("some_int", 42); // Validate collection returns the expected report. + MockCrashReportDatabase crash_db; PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, nullptr); + kChannelName, &crash_db, nullptr); StabilityReport report; ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); @@ -594,11 +580,11 @@ debug_file_path_ = temp_dir_.GetPath().AppendASCII("debug.pma"); } - const base::FilePath& debug_file_path() { return debug_file_path_; } + const FilePath& debug_file_path() { return debug_file_path_; } protected: base::ScopedTempDir temp_dir_; - base::FilePath debug_file_path_; + FilePath debug_file_path_; }; TEST_F(PostmortemReportCollectorCollectionFromGlobalTrackerTest, @@ -610,8 +596,9 @@ GlobalActivityTracker::Get()->RecordLogMessage("foo bar"); // Collect the stability report. + MockCrashReportDatabase crash_db; PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, nullptr); + kChannelName, &crash_db, nullptr); StabilityReport report; ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); @@ -643,8 +630,9 @@ process_data.SetStringReference("sref", string2); // Collect the stability report. + MockCrashReportDatabase crash_db; PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, nullptr); + kChannelName, &crash_db, nullptr); StabilityReport report; ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); @@ -712,8 +700,9 @@ process_data.SetString("FieldTrial.foo", "bar"); // Collect the stability report. + MockCrashReportDatabase crash_db; PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, nullptr); + kChannelName, &crash_db, nullptr); StabilityReport report; ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); @@ -753,8 +742,9 @@ GlobalActivityTracker::Get()->RecordModuleInfo(module_info); // Collect the stability report. + MockCrashReportDatabase crash_db; PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, nullptr); + kChannelName, &crash_db, nullptr); StabilityReport report; ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report)); @@ -791,8 +781,9 @@ IsSessionUnclean(base::Time::FromInternalValue(12345LL))) .Times(1) .WillOnce(Return(SystemSessionAnalyzer::CLEAN)); + MockCrashReportDatabase crash_db; PostmortemReportCollector collector(kProductName, kVersionNumber, - kChannelName, &analyzer); + kChannelName, &crash_db, &analyzer); StabilityReport report; ASSERT_EQ(SUCCESS, collector.CollectOneReport(debug_file_path(), &report));
diff --git a/components/browser_watcher/stability_paths.cc b/components/browser_watcher/stability_paths.cc index 329d89c..a8164df 100644 --- a/components/browser_watcher/stability_paths.cc +++ b/components/browser_watcher/stability_paths.cc
@@ -15,6 +15,7 @@ #include "base/debug/activity_tracker.h" #include "base/feature_list.h" #include "base/files/file.h" +#include "base/files/file_enumerator.h" #include "base/files/memory_mapped_file.h" #include "base/metrics/persistent_memory_allocator.h" #include "base/strings/stringprintf.h" @@ -28,6 +29,7 @@ namespace browser_watcher { +using base::FilePath; using base::FilePersistentMemoryAllocator; using base::MemoryMappedFile; using base::PersistentMemoryAllocator; @@ -57,14 +59,14 @@ } // namespace -base::FilePath GetStabilityDir(const base::FilePath& user_data_dir) { +FilePath GetStabilityDir(const FilePath& user_data_dir) { return user_data_dir.AppendASCII("Stability"); } -base::FilePath GetStabilityFileForProcess(base::ProcessId pid, - timeval creation_time, - const base::FilePath& user_data_dir) { - base::FilePath stability_dir = GetStabilityDir(user_data_dir); +FilePath GetStabilityFileForProcess(base::ProcessId pid, + timeval creation_time, + const FilePath& user_data_dir) { + FilePath stability_dir = GetStabilityDir(user_data_dir); constexpr uint64_t kMicrosecondsPerSecond = static_cast<uint64_t>(1E6); int64_t creation_time_us = @@ -76,8 +78,8 @@ } bool GetStabilityFileForProcess(const base::Process& process, - const base::FilePath& user_data_dir, - base::FilePath* file_path) { + const FilePath& user_data_dir, + FilePath* file_path) { DCHECK(file_path); FILETIME creation_time; @@ -92,11 +94,30 @@ return true; } -base::FilePath::StringType GetStabilityFilePattern() { - return base::FilePath::StringType(FILE_PATH_LITERAL("*-*")) + +FilePath::StringType GetStabilityFilePattern() { + return FilePath::StringType(FILE_PATH_LITERAL("*-*")) + base::PersistentMemoryAllocator::kFileExtension; } +std::vector<FilePath> GetStabilityFiles( + const FilePath& stability_dir, + const FilePath::StringType& stability_file_pattern, + const std::set<FilePath>& excluded_stability_files) { + DCHECK_NE(true, stability_dir.empty()); + DCHECK_NE(true, stability_file_pattern.empty()); + + std::vector<FilePath> paths; + base::FileEnumerator enumerator(stability_dir, false /* recursive */, + base::FileEnumerator::FILES, + stability_file_pattern); + FilePath path; + for (path = enumerator.Next(); !path.empty(); path = enumerator.Next()) { + if (excluded_stability_files.find(path) == excluded_stability_files.end()) + paths.push_back(path); + } + return paths; +} + void MarkOwnStabilityFileDeleted(const base::FilePath& user_data_dir) { base::debug::GlobalActivityTracker* global_tracker = base::debug::GlobalActivityTracker::Get();
diff --git a/components/browser_watcher/stability_paths.h b/components/browser_watcher/stability_paths.h index 7941c37..0b2078f 100644 --- a/components/browser_watcher/stability_paths.h +++ b/components/browser_watcher/stability_paths.h
@@ -5,6 +5,9 @@ #ifndef COMPONENTS_BROWSER_WATCHER_STABILITY_PATHS_H_ #define COMPONENTS_BROWSER_WATCHER_STABILITY_PATHS_H_ +#include <set> +#include <vector> + #include "base/files/file_path.h" #include "base/process/process.h" #include "build/build_config.h" @@ -35,6 +38,13 @@ // Returns a pattern that matches file names returned by GetFileForProcess. base::FilePath::StringType GetStabilityFilePattern(); +// Returns files in |stability_dir| that match |stability_file_pattern|, +// excluding those in |excluded_stability_files|. +std::vector<base::FilePath> GetStabilityFiles( + const base::FilePath& stability_dir, + const base::FilePath::StringType& stability_file_pattern, + const std::set<base::FilePath>& excluded_stability_files); + // Sets the current process's stability file's state to deleted (via the // GlobalActivityTracker) and opens the file for deletion. Metrics pertaining to // stability recording are logged.
diff --git a/components/browser_watcher/stability_paths_unittest.cc b/components/browser_watcher/stability_paths_unittest.cc new file mode 100644 index 0000000..4b9eea0 --- /dev/null +++ b/components/browser_watcher/stability_paths_unittest.cc
@@ -0,0 +1,52 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/browser_watcher/stability_paths.h" + +#include "base/files/file_util.h" +#include "base/files/scoped_file.h" +#include "base/files/scoped_temp_dir.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace browser_watcher { + +TEST(StabilityPathsTest, GetStabilityFiles) { + base::ScopedTempDir temp_dir; + ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); + + // Create files. + std::vector<base::FilePath> expected_paths; + std::set<base::FilePath> excluded_paths; + { + // Matches the pattern. + base::FilePath path = temp_dir.GetPath().AppendASCII("foo1.pma"); + base::ScopedFILE file(base::OpenFile(path, "w")); + ASSERT_NE(file.get(), nullptr); + expected_paths.push_back(path); + + // Matches the pattern, but is excluded. + path = temp_dir.GetPath().AppendASCII("foo2.pma"); + file.reset(base::OpenFile(path, "w")); + ASSERT_NE(file.get(), nullptr); + ASSERT_TRUE(excluded_paths.insert(path).second); + + // Matches the pattern. + path = temp_dir.GetPath().AppendASCII("foo3.pma"); + file.reset(base::OpenFile(path, "w")); + ASSERT_NE(file.get(), nullptr); + expected_paths.push_back(path); + + // Does not match the pattern. + path = temp_dir.GetPath().AppendASCII("bar.baz"); + file.reset(base::OpenFile(path, "w")); + ASSERT_NE(file.get(), nullptr); + } + + EXPECT_THAT(GetStabilityFiles(temp_dir.GetPath(), + FILE_PATH_LITERAL("foo*.pma"), excluded_paths), + testing::UnorderedElementsAreArray(expected_paths)); +} + +} // namespace browser_watcher
diff --git a/components/browser_watcher/stability_report_extractor.h b/components/browser_watcher/stability_report_extractor.h index 5ff9033..8049146 100644 --- a/components/browser_watcher/stability_report_extractor.h +++ b/components/browser_watcher/stability_report_extractor.h
@@ -12,7 +12,7 @@ namespace browser_watcher { -// DO NOT CHANGE VALUES. This is logged persistently in a histogram. +// DO NOT REMOVE OR REORDER VALUES. This is logged persistently in a histogram. enum CollectionStatus { NONE = 0, SUCCESS = 1, // Successfully registered a report with Crashpad. @@ -22,7 +22,11 @@ WRITE_TO_MINIDUMP_FAILED = 5, DEBUG_FILE_DELETION_FAILED = 6, FINISHED_WRITING_CRASH_REPORT_FAILED = 7, - COLLECTION_STATUS_MAX = 8 + UNCLEAN_SHUTDOWN = 8, + UNCLEAN_SESSION = 9, + COLLECTION_ATTEMPT = 10, + // New values go here. + COLLECTION_STATUS_MAX = 11 }; // Extracts a stability report from a stability file.
diff --git a/components/browser_watcher/watcher_metrics_provider_win.cc b/components/browser_watcher/watcher_metrics_provider_win.cc index 6376079ba..dcd7881 100644 --- a/components/browser_watcher/watcher_metrics_provider_win.cc +++ b/components/browser_watcher/watcher_metrics_provider_win.cc
@@ -14,6 +14,7 @@ #include "base/bind.h" #include "base/feature_list.h" +#include "base/metrics/field_trial_params.h" #include "base/metrics/histogram.h" #include "base/metrics/histogram_base.h" #include "base/metrics/histogram_macros.h" @@ -223,36 +224,49 @@ done_callback); } +// TODO(manzagop): consider mechanisms for partial collection if this is to be +// used on a critical path. void WatcherMetricsProviderWin::CollectPostmortemReportsOnBlockingPool() { - // Note: the feature controls both instrumentation and collection. + SCOPED_UMA_HISTOGRAM_TIMER("ActivityTracker.Collect.TotalTime"); + bool is_stability_debugging_on = base::FeatureList::IsEnabled(browser_watcher::kStabilityDebuggingFeature); if (!is_stability_debugging_on) { - // TODO(manzagop): delete possible leftover data. - return; + return; // TODO(manzagop): scan for possible data to delete? } - SCOPED_UMA_HISTOGRAM_TIMER("ActivityTracker.Collect.TotalTime"); - if (user_data_dir_.empty() || crash_dir_.empty()) { - LOG(ERROR) << "User data directory or crash directory is unknown."; LogCollectionInitStatus(UNKNOWN_DIR); return; } - // Determine the stability directory and the stability file for the current - // process. + // Determine which files to harvest. base::FilePath stability_dir = GetStabilityDir(user_data_dir_); + base::FilePath current_stability_file; if (!GetStabilityFileForProcess(base::Process::Current(), user_data_dir_, ¤t_stability_file)) { - LOG(ERROR) << "Failed to get the current stability file."; LogCollectionInitStatus(GET_STABILITY_FILE_PATH_FAILED); return; } - const std::set<base::FilePath>& excluded_debug_files = { + const std::set<base::FilePath>& excluded_stability_files = { current_stability_file}; + std::vector<base::FilePath> stability_files = GetStabilityFiles( + stability_dir, GetStabilityFilePattern(), excluded_stability_files); + UMA_HISTOGRAM_COUNTS_100("ActivityTracker.Collect.StabilityFileCount", + stability_files.size()); + + // If postmortem collection is disabled, delete the files. + const bool should_collect = base::GetFieldTrialParamByFeatureAsBool( + browser_watcher::kStabilityDebuggingFeature, + browser_watcher::kCollectPostmortemParam, false); + if (!should_collect) { + PostmortemDeleter deleter; + deleter.Process(stability_files); + return; + } + // Create a database. Note: Chrome already has a g_database in crashpad.cc but // it has internal linkage. Create a new one. std::unique_ptr<crashpad::CrashReportDatabase> crashpad_database = @@ -273,10 +287,8 @@ SystemSessionAnalyzer analyzer(kSystemSessionsToInspect); PostmortemReportCollector collector( base::UTF16ToUTF8(product_name), base::UTF16ToUTF8(version_number), - base::UTF16ToUTF8(channel_name), &analyzer); - collector.CollectAndSubmitAllPendingReports( - stability_dir, GetStabilityFilePattern(), excluded_debug_files, - crashpad_database.get()); + base::UTF16ToUTF8(channel_name), crashpad_database.get(), &analyzer); + collector.Process(stability_files); } } // namespace browser_watcher
diff --git a/components/download/internal/BUILD.gn b/components/download/internal/BUILD.gn index ae5c2ae..f5f2ca7 100644 --- a/components/download/internal/BUILD.gn +++ b/components/download/internal/BUILD.gn
@@ -41,8 +41,13 @@ "proto_conversions.h", "scheduler/battery_listener.cc", "scheduler/battery_listener.h", + "scheduler/device_status.cc", + "scheduler/device_status.h", "scheduler/network_listener.cc", "scheduler/network_listener.h", + "scheduler/scheduler.h", + "scheduler/scheduler_impl.cc", + "scheduler/scheduler_impl.h", "startup_status.cc", "startup_status.h", "stats.cc", @@ -73,6 +78,7 @@ "proto_conversions_unittest.cc", "scheduler/battery_listener_unittest.cc", "scheduler/network_listener_unittest.cc", + "scheduler/scheduler_impl_unittest.cc", ] deps = [
diff --git a/components/download/internal/entry.cc b/components/download/internal/entry.cc index f68d5bf2..6cf6855e 100644 --- a/components/download/internal/entry.cc +++ b/components/download/internal/entry.cc
@@ -12,6 +12,7 @@ Entry::Entry(const DownloadParams& params) : client(params.client), guid(params.guid), + create_time(base::Time::Now()), scheduling_params(params.scheduling_params), request_params(params.request_params) {}
diff --git a/components/download/internal/entry.h b/components/download/internal/entry.h index 7e971c07..e4e787e 100644 --- a/components/download/internal/entry.h +++ b/components/download/internal/entry.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_DOWNLOAD_INTERNAL_ENTRY_H_ #define COMPONENTS_DOWNLOAD_INTERNAL_ENTRY_H_ +#include "base/time/time.h" #include "components/download/public/client.h" #include "components/download/public/clients.h" #include "components/download/public/download_params.h" @@ -52,6 +53,9 @@ // A unique GUID that represents this download. See | base::GenerateGUID()|. std::string guid; + // The time when the entry is created. + base::Time create_time; + // The parameters that determine under what device conditions this download // will occur. SchedulingParams scheduling_params;
diff --git a/components/download/internal/entry_utils.cc b/components/download/internal/entry_utils.cc index c5b38aa..b02ec79 100644 --- a/components/download/internal/entry_utils.cc +++ b/components/download/internal/entry_utils.cc
@@ -35,5 +35,22 @@ return categorized; } +Criteria GetSchedulingCriteria(const Model::EntryList& entries) { + Criteria criteria; + for (auto* const entry : entries) { + DCHECK(entry); + const SchedulingParams& scheduling_params = entry->scheduling_params; + if (scheduling_params.battery_requirements == + SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE) { + criteria.requires_battery_charging = false; + } + if (scheduling_params.network_requirements == + SchedulingParams::NetworkRequirements::NONE) { + criteria.requires_unmetered_network = false; + } + } + return criteria; +} + } // namespace util } // namespace download
diff --git a/components/download/internal/entry_utils.h b/components/download/internal/entry_utils.h index 1d7ac884..7e46cdba 100644 --- a/components/download/internal/entry_utils.h +++ b/components/download/internal/entry_utils.h
@@ -10,6 +10,8 @@ #include <string> #include <vector> +#include "components/download/internal/model.h" +#include "components/download/internal/scheduler/device_status.h" #include "components/download/public/clients.h" namespace download { @@ -31,6 +33,10 @@ const std::set<DownloadClient>& clients, const std::vector<Entry*>& entries); +// Get the least strict scheduling criteria from |entries|, the criteria is used +// to schedule platform background tasks. +Criteria GetSchedulingCriteria(const Model::EntryList& entries); + } // namespace util } // namespace download
diff --git a/components/download/internal/proto/entry.proto b/components/download/internal/proto/entry.proto index d5f9dfed..8241f9fa 100644 --- a/components/download/internal/proto/entry.proto +++ b/components/download/internal/proto/entry.proto
@@ -16,8 +16,10 @@ enum DownloadClient { INVALID = 0; TEST = 1; - OFFLINE_PAGE_PREFETCH = 2; - BOUNDARY = 3; + TEST_2 = 2; + TEST_3 = 3; + OFFLINE_PAGE_PREFETCH = 4; + BOUNDARY = 5; } // Stores the request params, internal state, metrics and metadata associated @@ -42,6 +44,9 @@ optional SchedulingParams scheduling_params = 3; optional RequestParams request_params = 4; - // Internal Tracking State. + // Internal Tracking States. optional State state = 5; + + // Creation time of the entry, measured in milliseconds. + optional int64 create_time = 6; }
diff --git a/components/download/internal/proto_conversions.cc b/components/download/internal/proto_conversions.cc index dc4187a..abe26287 100644 --- a/components/download/internal/proto_conversions.cc +++ b/components/download/internal/proto_conversions.cc
@@ -59,6 +59,10 @@ return protodb::DownloadClient::INVALID; case DownloadClient::TEST: return protodb::DownloadClient::TEST; + case DownloadClient::TEST_2: + return protodb::DownloadClient::TEST_2; + case DownloadClient::TEST_3: + return protodb::DownloadClient::TEST_3; case DownloadClient::OFFLINE_PAGE_PREFETCH: return protodb::DownloadClient::OFFLINE_PAGE_PREFETCH; case DownloadClient::BOUNDARY: @@ -76,6 +80,10 @@ return DownloadClient::INVALID; case protodb::DownloadClient::TEST: return DownloadClient::TEST; + case protodb::DownloadClient::TEST_2: + return DownloadClient::TEST_2; + case protodb::DownloadClient::TEST_3: + return DownloadClient::TEST_3; case protodb::DownloadClient::OFFLINE_PAGE_PREFETCH: return DownloadClient::OFFLINE_PAGE_PREFETCH; case protodb::DownloadClient::BOUNDARY: @@ -244,7 +252,7 @@ SchedulingParamsFromProto(proto.scheduling_params()); entry.request_params = RequestParamsFromProto(proto.request_params()); entry.state = RequestStateFromProto(proto.state()); - + entry.create_time = base::Time::FromInternalValue(proto.create_time()); return entry; } @@ -257,6 +265,7 @@ proto.mutable_scheduling_params()); RequestParamsToProto(entry.request_params, proto.mutable_request_params()); proto.set_state(RequestStateToProto(entry.state)); + proto.set_create_time(entry.create_time.ToInternalValue()); return proto; }
diff --git a/components/download/internal/scheduler/battery_listener.cc b/components/download/internal/scheduler/battery_listener.cc index b015ca1..45a50b4e 100644 --- a/components/download/internal/scheduler/battery_listener.cc +++ b/components/download/internal/scheduler/battery_listener.cc
@@ -9,11 +9,9 @@ namespace download { // Helper function that converts the battery status to battery requirement. -SchedulingParams::BatteryRequirements ToBatteryRequirement( - bool on_battery_power) { - return on_battery_power - ? SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE - : SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE; +BatteryStatus ToBatteryStatus(bool on_battery_power) { + return on_battery_power ? BatteryStatus::NOT_CHARGING + : BatteryStatus::CHARGING; } BatteryListener::BatteryListener() = default; @@ -22,9 +20,8 @@ Stop(); } -SchedulingParams::BatteryRequirements BatteryListener::CurrentBatteryStatus() - const { - return ToBatteryRequirement(base::PowerMonitor::Get()->IsOnBatteryPower()); +BatteryStatus BatteryListener::CurrentBatteryStatus() const { + return ToBatteryStatus(base::PowerMonitor::Get()->IsOnBatteryPower()); } void BatteryListener::Start() { @@ -46,13 +43,12 @@ } void BatteryListener::OnPowerStateChange(bool on_battery_power) { - NotifyBatteryChange(ToBatteryRequirement(on_battery_power)); + NotifyBatteryChange(ToBatteryStatus(on_battery_power)); } -void BatteryListener::NotifyBatteryChange( - SchedulingParams::BatteryRequirements current_battery) { +void BatteryListener::NotifyBatteryChange(BatteryStatus battery_status) { for (auto& observer : observers_) - observer.OnBatteryChange(current_battery); + observer.OnBatteryChange(battery_status); } } // namespace download
diff --git a/components/download/internal/scheduler/battery_listener.h b/components/download/internal/scheduler/battery_listener.h index 2ddc6109..02515dc 100644 --- a/components/download/internal/scheduler/battery_listener.h +++ b/components/download/internal/scheduler/battery_listener.h
@@ -9,6 +9,7 @@ #include "base/observer_list.h" #include "base/power_monitor/power_observer.h" +#include "components/download/internal/scheduler/device_status.h" #include "components/download/public/download_params.h" namespace download { @@ -21,15 +22,14 @@ class Observer { public: // Called when certain battery requirements are meet. - virtual void OnBatteryChange( - SchedulingParams::BatteryRequirements battery_status) = 0; + virtual void OnBatteryChange(BatteryStatus battery_status) = 0; }; BatteryListener(); ~BatteryListener() override; // Retrieves the current minimum battery requirement. - SchedulingParams::BatteryRequirements CurrentBatteryStatus() const; + BatteryStatus CurrentBatteryStatus() const; // Start to listen to battery change. void Start(); @@ -46,7 +46,7 @@ void OnPowerStateChange(bool on_battery_power) override; // Notifies |observers_| about battery requirement change. - void NotifyBatteryChange(SchedulingParams::BatteryRequirements); + void NotifyBatteryChange(BatteryStatus status); // Observers to monitor battery change in download service. base::ObserverList<Observer> observers_;
diff --git a/components/download/internal/scheduler/battery_listener_unittest.cc b/components/download/internal/scheduler/battery_listener_unittest.cc index 3ddacff..2e7d4fe 100644 --- a/components/download/internal/scheduler/battery_listener_unittest.cc +++ b/components/download/internal/scheduler/battery_listener_unittest.cc
@@ -10,6 +10,8 @@ #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +using testing::InSequence; + namespace download { namespace { @@ -17,7 +19,7 @@ class MockObserver : public BatteryListener::Observer { public: - MOCK_METHOD1(OnBatteryChange, void(SchedulingParams::BatteryRequirements)); + MOCK_METHOD1(OnBatteryChange, void(BatteryStatus)); }; class BatteryListenerTest : public testing::Test { @@ -57,14 +59,13 @@ // Ensures observer methods are corrected called. TEST_F(BatteryListenerTest, NotifyObservers) { + InSequence s; listener_->Start(); - EXPECT_CALL(*observer_.get(), - OnBatteryChange(BatteryRequirements::BATTERY_INSENSITIVE)) + EXPECT_CALL(*observer_.get(), OnBatteryChange(BatteryStatus::NOT_CHARGING)) .RetiresOnSaturation(); CallBatteryChange(true); - EXPECT_CALL(*observer_.get(), - OnBatteryChange(BatteryRequirements::BATTERY_SENSITIVE)) + EXPECT_CALL(*observer_.get(), OnBatteryChange(BatteryStatus::CHARGING)) .RetiresOnSaturation(); CallBatteryChange(false); listener_->Stop();
diff --git a/components/download/internal/scheduler/device_status.cc b/components/download/internal/scheduler/device_status.cc new file mode 100644 index 0000000..a88967a --- /dev/null +++ b/components/download/internal/scheduler/device_status.cc
@@ -0,0 +1,64 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/scheduler/device_status.h" + +namespace download { + +DeviceStatus::Result::Result() + : meets_battery_requirement(false), meets_network_requirement(false) {} + +bool DeviceStatus::Result::MeetsRequirements() const { + return meets_battery_requirement && meets_network_requirement; +} + +DeviceStatus::DeviceStatus() + : battery_status(BatteryStatus::NOT_CHARGING), + network_status(NetworkStatus::DISCONNECTED) {} + +bool DeviceStatus::operator==(const DeviceStatus& rhs) { + return network_status == rhs.network_status && + battery_status == rhs.battery_status; +} + +DeviceStatus::Result DeviceStatus::MeetsCondition( + const SchedulingParams& params) const { + DeviceStatus::Result result; + + switch (params.battery_requirements) { + case SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE: + result.meets_battery_requirement = true; + break; + case SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE: + result.meets_battery_requirement = + battery_status == BatteryStatus::CHARGING; + break; + default: + NOTREACHED(); + } + switch (params.network_requirements) { + case SchedulingParams::NetworkRequirements::NONE: + result.meets_network_requirement = + network_status != NetworkStatus::DISCONNECTED; + break; + case SchedulingParams::NetworkRequirements::OPTIMISTIC: + case SchedulingParams::NetworkRequirements::UNMETERED: + result.meets_network_requirement = + network_status == NetworkStatus::UNMETERED; + break; + default: + NOTREACHED(); + } + return result; +} + +Criteria::Criteria() + : requires_battery_charging(true), requires_unmetered_network(true) {} + +bool Criteria::operator==(const Criteria& other) const { + return requires_battery_charging == other.requires_battery_charging && + requires_unmetered_network == other.requires_unmetered_network; +} + +} // namespace download
diff --git a/components/download/internal/scheduler/device_status.h b/components/download/internal/scheduler/device_status.h new file mode 100644 index 0000000..b7a35d2 --- /dev/null +++ b/components/download/internal/scheduler/device_status.h
@@ -0,0 +1,57 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_DEVICE_STATUS_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_DEVICE_STATUS_H_ + +#include "components/download/public/download_params.h" + +namespace download { + +// Battery status used in download service. +enum class BatteryStatus { + CHARGING = 0, + NOT_CHARGING = 1, +}; + +// NetworkStatus should mostly one to one map to +// SchedulingParams::NetworkRequirements. Has coarser granularity than +// network connection type. +enum class NetworkStatus { + DISCONNECTED = 0, + UNMETERED = 1, // WIFI or Ethernet. + METERED = 2, // Mobile networks. +}; + +// Contains battery and network status. +struct DeviceStatus { + DeviceStatus(); + struct Result { + Result(); + bool MeetsRequirements() const; + bool meets_battery_requirement; + bool meets_network_requirement; + }; + + BatteryStatus battery_status; + NetworkStatus network_status; + + bool operator==(const DeviceStatus& rhs); + + // Returns if the current device status meets all the conditions defined in + // the scheduling parameters. + Result MeetsCondition(const SchedulingParams& params) const; +}; + +// The criteria when the background download task should start. +struct Criteria { + Criteria(); + bool operator==(const Criteria& other) const; + bool requires_battery_charging; + bool requires_unmetered_network; +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_DEVICE_STATUS_H_
diff --git a/components/download/internal/scheduler/network_listener.cc b/components/download/internal/scheduler/network_listener.cc index d09d527..3840e4f 100644 --- a/components/download/internal/scheduler/network_listener.cc +++ b/components/download/internal/scheduler/network_listener.cc
@@ -8,24 +8,23 @@ namespace { -// Converts a ConnectionType to NetworkListener::NetworkStatus. -NetworkListener::NetworkStatus ToNetworkStatus( - net::NetworkChangeNotifier::ConnectionType type) { +// Converts a ConnectionType to NetworkStatus. +NetworkStatus ToNetworkStatus(net::NetworkChangeNotifier::ConnectionType type) { switch (type) { case net::NetworkChangeNotifier::CONNECTION_ETHERNET: case net::NetworkChangeNotifier::CONNECTION_WIFI: - return NetworkListener::NetworkStatus::UNMETERED; + return NetworkStatus::UNMETERED; case net::NetworkChangeNotifier::CONNECTION_2G: case net::NetworkChangeNotifier::CONNECTION_3G: case net::NetworkChangeNotifier::CONNECTION_4G: - return NetworkListener::NetworkStatus::METERED; + return NetworkStatus::METERED; case net::NetworkChangeNotifier::CONNECTION_UNKNOWN: case net::NetworkChangeNotifier::CONNECTION_NONE: case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH: - return NetworkListener::NetworkStatus::DISCONNECTED; + return NetworkStatus::DISCONNECTED; } NOTREACHED(); - return NetworkListener::NetworkStatus::DISCONNECTED; + return NetworkStatus::DISCONNECTED; } } // namespace @@ -37,7 +36,7 @@ Stop(); } -NetworkListener::NetworkStatus NetworkListener::CurrentNetworkStatus() const { +NetworkStatus NetworkListener::CurrentNetworkStatus() const { return ToNetworkStatus(net::NetworkChangeNotifier::GetConnectionType()); }
diff --git a/components/download/internal/scheduler/network_listener.h b/components/download/internal/scheduler/network_listener.h index 6b05ffb1..b827909 100644 --- a/components/download/internal/scheduler/network_listener.h +++ b/components/download/internal/scheduler/network_listener.h
@@ -5,6 +5,7 @@ #ifndef COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_NETWORK_LISTENER_H_ #define COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_NETWORK_LISTENER_H_ +#include "components/download/internal/scheduler/device_status.h" #include "net/base/network_change_notifier.h" namespace download { @@ -13,15 +14,6 @@ class NetworkListener : public net::NetworkChangeNotifier::ConnectionTypeObserver { public: - // NetworkStatus should mostly one to one map to - // SchedulingParams::NetworkRequirements. Has coarser granularity than - // network connection type. - enum class NetworkStatus { - DISCONNECTED = 0, - UNMETERED = 1, // WIFI or Ethernet. - METERED = 2, // Mobile networks. - }; - class Observer { public: // Called when network status is changed.
diff --git a/components/download/internal/scheduler/network_listener_unittest.cc b/components/download/internal/scheduler/network_listener_unittest.cc index 4b8165dce..c4fadac 100644 --- a/components/download/internal/scheduler/network_listener_unittest.cc +++ b/components/download/internal/scheduler/network_listener_unittest.cc
@@ -45,7 +45,7 @@ class MockObserver : public NetworkListener::Observer { public: - MOCK_METHOD1(OnNetworkChange, void(NetworkListener::NetworkStatus)); + MOCK_METHOD1(OnNetworkChange, void(NetworkStatus)); }; class NetworkListenerTest : public testing::Test { @@ -69,26 +69,23 @@ network_listener_.AddObserver(&mock_observer_); // Initial states check. - EXPECT_EQ(NetworkListener::NetworkStatus::DISCONNECTED, + EXPECT_EQ(NetworkStatus::DISCONNECTED, network_listener_.CurrentNetworkStatus()); // Network switch between mobile networks, the observer should be notified // only once. - EXPECT_CALL(mock_observer_, - OnNetworkChange(NetworkListener::NetworkStatus::METERED)) + EXPECT_CALL(mock_observer_, OnNetworkChange(NetworkStatus::METERED)) .Times(1) .RetiresOnSaturation(); ChangeNetworkType(ConnectionType::CONNECTION_4G); ChangeNetworkType(ConnectionType::CONNECTION_3G); ChangeNetworkType(ConnectionType::CONNECTION_2G); - EXPECT_EQ(NetworkListener::NetworkStatus::METERED, - network_listener_.CurrentNetworkStatus()); + EXPECT_EQ(NetworkStatus::METERED, network_listener_.CurrentNetworkStatus()); // Network is switched between wifi and ethernet, the observer should be // notified only once. - EXPECT_CALL(mock_observer_, - OnNetworkChange(NetworkListener::NetworkStatus::UNMETERED)) + EXPECT_CALL(mock_observer_, OnNetworkChange(NetworkStatus::UNMETERED)) .Times(1) .RetiresOnSaturation();
diff --git a/components/download/internal/scheduler/scheduler.h b/components/download/internal/scheduler/scheduler.h new file mode 100644 index 0000000..3cb0034 --- /dev/null +++ b/components/download/internal/scheduler/scheduler.h
@@ -0,0 +1,41 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_SCHEDULER_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_SCHEDULER_H_ + +#include "components/download/internal/model.h" +#include "components/download/internal/scheduler/device_status.h" +#include "components/download/public/download_params.h" + +namespace download { + +struct DeviceStatus; + +// The interface that talks to download service to schedule platform background +// download tasks. +class Scheduler { + public: + // Reschedule another background platform task. Called when downloads are + // added or removed or the criteria has changed. + virtual void Reschedule(const Model::EntryList& entries) = 0; + + // Returns the next download that should be processed based on scheduling + // parameters, may return nullptr if no download meets the criteria. + // The sequence of polling on entries with exactly same states is undefined. + virtual Entry* Next(const Model::EntryList& entries, + const DeviceStatus& device_status) = 0; +}; + +// Interface to schedule platform dependent background tasks that can run after +// browser being closed. +class PlatformTaskScheduler { + public: + virtual void ScheduleDownloadTask(const Criteria& criteria) = 0; + virtual void CancelDownloadTask() = 0; +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_CORE_SCHEDULER_H_
diff --git a/components/download/internal/scheduler/scheduler_impl.cc b/components/download/internal/scheduler/scheduler_impl.cc new file mode 100644 index 0000000..1233dda --- /dev/null +++ b/components/download/internal/scheduler/scheduler_impl.cc
@@ -0,0 +1,109 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/scheduler/scheduler_impl.h" + +#include "components/download/internal/entry_utils.h" +#include "components/download/internal/scheduler/device_status.h" +#include "components/download/public/download_params.h" + +namespace download { + +SchedulerImpl::SchedulerImpl(PlatformTaskScheduler* platform_scheduler, + const std::vector<DownloadClient>& clients) + : platform_scheduler_(platform_scheduler), + download_clients_(clients), + current_client_index_(0) { + DCHECK(!clients.empty()); +} + +SchedulerImpl::~SchedulerImpl() = default; + +void SchedulerImpl::Reschedule(const Model::EntryList& entries) { + if (entries.empty()) { + if (platform_scheduler_) + platform_scheduler_->CancelDownloadTask(); + return; + } + + // TODO(xingliu): Figure out if we need to pass the time window to platform + // scheduler, and support NetworkRequirements::OPTIMISTIC. + if (platform_scheduler_) { + platform_scheduler_->CancelDownloadTask(); + platform_scheduler_->ScheduleDownloadTask( + util::GetSchedulingCriteria(entries)); + } +} + +Entry* SchedulerImpl::Next(const Model::EntryList& entries, + const DeviceStatus& device_status) { + std::map<DownloadClient, Entry*> candidates = + FindCandidates(entries, device_status); + + Entry* entry = nullptr; + size_t index = current_client_index_; + + // Finds the next entry to download. + for (size_t i = 0; i < download_clients_.size(); ++i) { + DownloadClient client = + download_clients_[(index + i) % download_clients_.size()]; + Entry* candidate = candidates[client]; + + // Some clients may have no entries, continue to check other clients. + if (!candidate) + continue; + + bool ui_priority = + candidate->scheduling_params.priority == SchedulingParams::Priority::UI; + + // Records the first available candidate. Keep iterating to see if there + // are UI priority entries for other clients. + if (!entry || ui_priority) { + entry = candidate; + DCHECK(entry); + + // Load balancing between clients. + current_client_index_ = (index + i + 1) % download_clients_.size(); + + // UI priority entry will be processed immediately. + if (ui_priority) + break; + } + } + return entry; +} + +std::map<DownloadClient, Entry*> SchedulerImpl::FindCandidates( + const Model::EntryList& entries, + const DeviceStatus& device_status) { + std::map<DownloadClient, Entry*> candidates; + + if (entries.empty()) + return candidates; + + for (auto* const entry : entries) { + DCHECK(entry); + const SchedulingParams& current_params = entry->scheduling_params; + + // Every download needs to pass the state and device status check. + if (entry->state != Entry::State::AVAILABLE || + !device_status.MeetsCondition(current_params).MeetsRequirements()) { + continue; + } + + // Find the most appropriate download based on priority and cancel time. + Entry* candidate = candidates[entry->client]; + if (!candidate || + (current_params.priority > candidate->scheduling_params.priority || + (current_params.priority == candidate->scheduling_params.priority && + entry->scheduling_params.cancel_time < + candidate->scheduling_params.cancel_time))) { + candidates[entry->client] = entry; + } + } + + return candidates; +} + +} // namespace download
diff --git a/components/download/internal/scheduler/scheduler_impl.h b/components/download/internal/scheduler/scheduler_impl.h new file mode 100644 index 0000000..30c2969 --- /dev/null +++ b/components/download/internal/scheduler/scheduler_impl.h
@@ -0,0 +1,61 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_SCHEDULER_IMPL_H_ +#define COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_SCHEDULER_IMPL_H_ + +#include "components/download/internal/scheduler/scheduler.h" + +#include <map> +#include <vector> + +#include "base/macros.h" +#include "components/download/internal/entry.h" + +namespace download { + +// Scheduler implementation that +// 1. Creates platform background task based on the states of download entries. +// 2. Polls the next entry to be processed by the service mainly according to +// scheduling parameters and current device status. +// +// Provides load balancing between download clients using the service. +class SchedulerImpl : public Scheduler { + public: + SchedulerImpl(PlatformTaskScheduler* platform_scheduler, + const std::vector<DownloadClient>& clients); + ~SchedulerImpl(); + + // Scheduler implementation. + void Reschedule(const Model::EntryList& entries) override; + Entry* Next(const Model::EntryList& entries, + const DeviceStatus& device_status) override; + + private: + // Finds a candidate for each download client to be processed next by the + // service. + // The candidates are selected based on scheduling parameters and current + // device status. + std::map<DownloadClient, Entry*> FindCandidates( + const Model::EntryList& entries, + const DeviceStatus& device_status); + + // Used to create platform dependent background tasks. + PlatformTaskScheduler* platform_scheduler_; + + // List of all download client id, used in round robin load balancing. + // Downloads will be delivered to clients with incremental order based on + // the index of this list. + const std::vector<DownloadClient> download_clients_; + + // The index of the current client. + // See |download_clients_|. + size_t current_client_index_; + + DISALLOW_COPY_AND_ASSIGN(SchedulerImpl); +}; + +} // namespace download + +#endif // COMPONENTS_DOWNLOAD_INTERNAL_SCHEDULER_SCHEDULER_IMPL_H_
diff --git a/components/download/internal/scheduler/scheduler_impl_unittest.cc b/components/download/internal/scheduler/scheduler_impl_unittest.cc new file mode 100644 index 0000000..7730af5a2 --- /dev/null +++ b/components/download/internal/scheduler/scheduler_impl_unittest.cc
@@ -0,0 +1,413 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/download/internal/scheduler/scheduler_impl.h" + +#include <memory> + +#include "base/memory/ptr_util.h" +#include "base/strings/string_number_conversions.h" +#include "components/download/internal/entry.h" +#include "components/download/internal/scheduler/device_status.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::InSequence; + +namespace download { +namespace { + +class MockPlatformTaskScheduler : public PlatformTaskScheduler { + public: + MOCK_METHOD1(ScheduleDownloadTask, void(const Criteria&)); + MOCK_METHOD0(CancelDownloadTask, void()); +}; + +class DownloadSchedulerImplTest : public testing::Test { + public: + DownloadSchedulerImplTest() {} + ~DownloadSchedulerImplTest() override = default; + + void TearDown() override { DestroyScheduler(); } + + void BuildScheduler(const std::vector<DownloadClient> clients) { + scheduler_ = + base::MakeUnique<SchedulerImpl>(&platform_task_scheduler_, clients); + } + void DestroyScheduler() { scheduler_.reset(); } + + // Helper function to create a list of entries for the scheduler to query the + // next entry. + void BuildDataEntries(size_t size) { + entries_ = std::vector<Entry>(size, Entry()); + for (size_t i = 0; i < size; ++i) { + entries_[i].guid = base::IntToString(i); + entries_[i].scheduling_params.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE; + entries_[i].scheduling_params.network_requirements = + SchedulingParams::NetworkRequirements::UNMETERED; + entries_[i].state = Entry::State::AVAILABLE; + } + } + + // Returns list of entry pointers to feed to the scheduler. + Model::EntryList entries() { + Model::EntryList entry_list; + for (auto& entry : entries_) { + entry_list.emplace_back(&entry); + } + return entry_list; + } + + // Simulates the entry has been processed by the download service and the + // state has changed. + void MakeEntryActive(Entry* entry) { + if (entry) + entry->state = Entry::State::ACTIVE; + } + + // Reverts the states of entry so that the scheduler can poll it again. + void MakeEntryAvailable(Entry* entry) { + entry->state = Entry::State::AVAILABLE; + } + + // Helper function to build a device status. + DeviceStatus BuildDeviceStatus(BatteryStatus battery, NetworkStatus network) { + DeviceStatus device_status; + device_status.battery_status = battery; + device_status.network_status = network; + return device_status; + } + + protected: + std::unique_ptr<SchedulerImpl> scheduler_; + MockPlatformTaskScheduler platform_task_scheduler_; + + // Entries owned by the test fixture. + std::vector<Entry> entries_; + + private: + DISALLOW_COPY_AND_ASSIGN(DownloadSchedulerImplTest); +}; + +// Ensures normal polling logic is correct. +TEST_F(DownloadSchedulerImplTest, BasicPolling) { + BuildScheduler(std::vector<DownloadClient>{DownloadClient::TEST_2, + DownloadClient::TEST}); + + // Client TEST: entry 0. + // Client TEST_2: entry 1. + // Poll sequence: 1 -> 0. + BuildDataEntries(2); + entries_[0].client = DownloadClient::TEST; + entries_[1].client = DownloadClient::TEST_2; + + // First download belongs to first client. + Entry* next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(next, &entries_[1]); + MakeEntryActive(next); + + // If the first one is processed, the next should be the other entry. + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(next, &entries_[0]); + MakeEntryActive(next); +} + +// Tests the load balancing and polling downloads based on cancel time. +TEST_F(DownloadSchedulerImplTest, BasicLoadBalancing) { + BuildScheduler(std::vector<DownloadClient>{ + DownloadClient::TEST, DownloadClient::TEST_2, DownloadClient::TEST_3}); + + // Client TEST: entry 0, entry 1 (earlier cancel time). + // Client TEST_2: entry 2. + // Client TEST_3: No entries. + // Poll sequence: 1 -> 2 -> 0. + BuildDataEntries(3); + entries_[0].client = DownloadClient::TEST; + entries_[0].scheduling_params.cancel_time = base::Time::FromInternalValue(20); + entries_[1].client = DownloadClient::TEST; + entries_[1].scheduling_params.cancel_time = base::Time::FromInternalValue(10); + entries_[2].client = DownloadClient::TEST_2; + entries_[2].scheduling_params.cancel_time = base::Time::FromInternalValue(30); + + // There are 2 downloads for client 0, the one with earlier create time will + // be the next download. + Entry* next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[1], next); + MakeEntryActive(next); + + // The second download should belongs to client 1, because of the round robin + // load balancing. + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[2], next); + MakeEntryActive(next); + + // Only one entry left, which will be the next. + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[0], next); + MakeEntryActive(next); + + // Keep polling twice, since no available downloads, both will return nullptr. + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(nullptr, next); + MakeEntryActive(next); + + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(nullptr, next); + MakeEntryActive(next); +} + +// Ensures downloads are polled based on scheduling parameters and device +// status. +TEST_F(DownloadSchedulerImplTest, SchedulingParams) { + BuildScheduler(std::vector<DownloadClient>{DownloadClient::TEST}); + BuildDataEntries(1); + entries_[0].client = DownloadClient::TEST; + entries_[0].scheduling_params.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE; + entries_[0].scheduling_params.network_requirements = + SchedulingParams::NetworkRequirements::UNMETERED; + + Entry* next = nullptr; + + // Tests network scheduling parameter. + // No downloads can be polled when network disconnected. + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::DISCONNECTED)); + EXPECT_EQ(nullptr, next); + + // If the network is metered, and scheduling parameter requires unmetered + // network, the download should not be polled. + next = scheduler_->Next(entries(), BuildDeviceStatus(BatteryStatus::CHARGING, + NetworkStatus::METERED)); + EXPECT_EQ(nullptr, next); + + // If the network requirement is none, the download can happen under metered + // network. However, download won't happen when network is disconnected. + entries_[0].scheduling_params.network_requirements = + SchedulingParams::NetworkRequirements::NONE; + next = scheduler_->Next(entries(), BuildDeviceStatus(BatteryStatus::CHARGING, + NetworkStatus::METERED)); + EXPECT_EQ(&entries_[0], next); + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::DISCONNECTED)); + EXPECT_EQ(nullptr, next); + MakeEntryActive(next); + + // Tests battery sensitive scheduling parameter. + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[0], next); + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::NOT_CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(nullptr, next); + MakeEntryActive(next); + + entries_[0].scheduling_params.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE; + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::NOT_CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[0], next); + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[0], next); + MakeEntryActive(next); +} + +// Ensures higher priority will be scheduled first. +TEST_F(DownloadSchedulerImplTest, Priority) { + BuildScheduler(std::vector<DownloadClient>{DownloadClient::TEST}); + + // The second entry has higher priority but is created later than the first + // entry. This ensures priority is checked before the create time. + BuildDataEntries(2); + entries_[0].client = DownloadClient::TEST; + entries_[0].scheduling_params.priority = SchedulingParams::Priority::LOW; + entries_[0].scheduling_params.cancel_time = base::Time::FromInternalValue(20); + entries_[1].client = DownloadClient::TEST; + entries_[1].scheduling_params.priority = SchedulingParams::Priority::HIGH; + entries_[1].scheduling_params.cancel_time = base::Time::FromInternalValue(40); + + // Download with higher priority should be polled first, even if there is + // another download created earlier. + Entry* next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[1], next); + + // Download with non UI priority should be subject to network and battery + // scheduling parameters. The higher priority one will be ignored because of + // mismatching battery condition. + entries_[1].scheduling_params.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE; + entries_[0].scheduling_params.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE; + + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::NOT_CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[0], next); + MakeEntryActive(next); +} + +// Ensures UI priority entries are subject to device status check. +TEST_F(DownloadSchedulerImplTest, UIPrioritySubjectToDeviceStatus) { + BuildScheduler(std::vector<DownloadClient>{DownloadClient::TEST, + DownloadClient::TEST_2}); + + // Client TEST: entry 0. + // Client TEST_2: entry 1 (UI priority, cancel later). + BuildDataEntries(2); + entries_[0].client = DownloadClient::TEST; + entries_[0].scheduling_params.priority = SchedulingParams::Priority::LOW; + entries_[1].client = DownloadClient::TEST_2; + entries_[1].scheduling_params.priority = SchedulingParams::Priority::UI; + + // UI priority is also subject to device status validation. + Entry* next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::NOT_CHARGING, NetworkStatus::METERED)); + EXPECT_EQ(nullptr, next); + MakeEntryActive(next); +} + +// UI priority entries will be processed first even if they doesn't belong to +// the current client in load balancing. +TEST_F(DownloadSchedulerImplTest, UIPriorityLoadBalancing) { + BuildScheduler(std::vector<DownloadClient>{DownloadClient::TEST, + DownloadClient::TEST_2}); + + // Client TEST: entry 0(Low priority). + // Client TEST_2: entry 1(UI priority). + BuildDataEntries(2); + entries_[0].client = DownloadClient::TEST; + entries_[0].scheduling_params.priority = SchedulingParams::Priority::LOW; + entries_[1].client = DownloadClient::TEST_2; + entries_[1].scheduling_params.priority = SchedulingParams::Priority::UI; + + Entry* next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[1], next); + MakeEntryActive(next); +} + +// When multiple UI priority entries exist, the next entry is selected based on +// cancel time and load balancing. +TEST_F(DownloadSchedulerImplTest, MultipleUIPriorityEntries) { + BuildScheduler(std::vector<DownloadClient>{DownloadClient::TEST, + DownloadClient::TEST_2}); + BuildDataEntries(4); + + // Client TEST: entry 0(UI priority), entry 1(UI priority, early cancel time). + // Client TEST_2: entry 2(UI priority), entry 3(high priority, early cancel + // time). Poll sequence: 1 -> 2 -> 0 -> 3. + for (auto& entry : entries_) { + entry.scheduling_params.priority = SchedulingParams::Priority::UI; + } + entries_[0].client = DownloadClient::TEST; + entries_[0].scheduling_params.cancel_time = base::Time::FromInternalValue(40); + entries_[1].client = DownloadClient::TEST; + entries_[1].scheduling_params.cancel_time = base::Time::FromInternalValue(20); + entries_[2].client = DownloadClient::TEST_2; + entries_[2].scheduling_params.cancel_time = base::Time::FromInternalValue(50); + entries_[3].client = DownloadClient::TEST_2; + entries_[3].scheduling_params.cancel_time = base::Time::FromInternalValue(20); + entries_[3].scheduling_params.priority = SchedulingParams::Priority::HIGH; + + // When device conditions are meet, UI priority entry with the earliest cancel + // time will be processed first. + Entry* next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[1], next); + MakeEntryActive(next); + + // Next entry will be UI priority entry from another client. + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[2], next); + MakeEntryActive(next); + + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[0], next); + MakeEntryActive(next); + + next = scheduler_->Next( + entries(), + BuildDeviceStatus(BatteryStatus::CHARGING, NetworkStatus::UNMETERED)); + EXPECT_EQ(&entries_[3], next); + MakeEntryActive(next); +} + +// Ensures the reschedule logic works correctly, and we can pass the correct +// criteria to platform task scheduler. +TEST_F(DownloadSchedulerImplTest, Reschedule) { + InSequence s; + + BuildScheduler(std::vector<DownloadClient>{DownloadClient::TEST}); + BuildDataEntries(2); + entries_[0].client = DownloadClient::TEST; + entries_[1].client = DownloadClient::TEST; + + entries_[0].scheduling_params.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE; + entries_[0].scheduling_params.network_requirements = + SchedulingParams::NetworkRequirements::UNMETERED; + entries_[1].scheduling_params.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE; + entries_[1].scheduling_params.network_requirements = + SchedulingParams::NetworkRequirements::UNMETERED; + + Criteria criteria; + EXPECT_CALL(platform_task_scheduler_, CancelDownloadTask()) + .RetiresOnSaturation(); + EXPECT_CALL(platform_task_scheduler_, ScheduleDownloadTask(criteria)) + .RetiresOnSaturation(); + scheduler_->Reschedule(entries()); + + entries_[0].scheduling_params.battery_requirements = + SchedulingParams::BatteryRequirements::BATTERY_INSENSITIVE; + criteria.requires_battery_charging = false; + EXPECT_CALL(platform_task_scheduler_, CancelDownloadTask()) + .RetiresOnSaturation(); + EXPECT_CALL(platform_task_scheduler_, ScheduleDownloadTask(criteria)) + .RetiresOnSaturation(); + scheduler_->Reschedule(entries()); + + entries_[0].scheduling_params.network_requirements = + SchedulingParams::NetworkRequirements::NONE; + criteria.requires_unmetered_network = false; + EXPECT_CALL(platform_task_scheduler_, CancelDownloadTask()) + .RetiresOnSaturation(); + EXPECT_CALL(platform_task_scheduler_, ScheduleDownloadTask(criteria)) + .RetiresOnSaturation(); + scheduler_->Reschedule(entries()); +} + +} // namespace +} // namespace download
diff --git a/components/download/public/clients.h b/components/download/public/clients.h index 36665b6..3939aea 100644 --- a/components/download/public/clients.h +++ b/components/download/public/clients.h
@@ -20,17 +20,19 @@ // but also to make sure the underlying database properly associates each // download with the right client. enum class DownloadClient { - // Represents an uninitialized DownloadClient variable. - INVALID = 0, - // Test client values. Meant to be used by the testing framework and not // production code. Callers will be unable to access the DownloadService with // these test APIs. - TEST = 1, + TEST = -1, + TEST_2 = -2, + TEST_3 = -3, - OFFLINE_PAGE_PREFETCH = 2, + // Represents an uninitialized DownloadClient variable. + INVALID = 0, - BOUNDARY = 3, + OFFLINE_PAGE_PREFETCH = 1, + + BOUNDARY = 2, }; using DownloadClientMap = std::map<DownloadClient, std::unique_ptr<Client>>;
diff --git a/components/feature_engagement_tracker/README.md b/components/feature_engagement_tracker/README.md index e912703..d357494c99 100644 --- a/components/feature_engagement_tracker/README.md +++ b/components/feature_engagement_tracker/README.md
@@ -13,21 +13,6 @@ The backend is feature agnostic and have no special logic for any specific features, but instead provides a generic API. -## Compiling for platforms other than Android - -For now the code for the Feature Engagement Tracker is only compiled in -for Android, but only a shim layer is really dependent on Android to provide a -JNI bridge. The goal is to keep all the business logic in the cross-platform -part of the code. - -For local development, it is therefore possible to compile and run tests for -the core of the tracker on other platforms. To do this, simply add the -following line to the `//components:components_unittests` target: - -```python -deps += [ "//components/feature_engagement_tracker:unit_tests" ] -``` - ## Testing To compile and run tests, assuming the product out directory is `out/Debug`,
diff --git a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc index 9d92884..b2d9374a 100644 --- a/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc +++ b/components/feature_engagement_tracker/internal/feature_engagement_tracker_impl.cc
@@ -9,6 +9,7 @@ #include "base/bind.h" #include "base/feature_list.h" +#include "base/files/file_path.h" #include "base/memory/ptr_util.h" #include "base/metrics/field_trial_params.h" #include "base/metrics/user_metrics.h" @@ -35,8 +36,10 @@ namespace feature_engagement_tracker { namespace { -const char kEventDBStorageDir[] = "EventDB"; -const char kAvailabilityDBStorageDir[] = "AvailabilityDB"; +const base::FilePath::CharType kEventDBStorageDir[] = + FILE_PATH_LITERAL("EventDB"); +const base::FilePath::CharType kAvailabilityDBStorageDir[] = + FILE_PATH_LITERAL("AvailabilityDB"); // Creates a FeatureEngagementTrackerImpl that is usable for a demo mode. std::unique_ptr<FeatureEngagementTracker>
diff --git a/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc b/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc index 6bcf53c..e9d08c0 100644 --- a/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc +++ b/components/feature_engagement_tracker/internal/system_time_provider_unittest.cc
@@ -17,6 +17,7 @@ exploded_time.year = year; exploded_time.month = month; exploded_time.day_of_month = day; + exploded_time.day_of_week = 0; exploded_time.hour = 0; exploded_time.minute = 0; exploded_time.second = 0;
diff --git a/components/history/core/browser/BUILD.gn b/components/history/core/browser/BUILD.gn index e60183b..1675bea 100644 --- a/components/history/core/browser/BUILD.gn +++ b/components/history/core/browser/BUILD.gn
@@ -200,6 +200,7 @@ "top_sites_cache_unittest.cc", "top_sites_database_unittest.cc", "top_sites_impl_unittest.cc", + "typed_url_sync_bridge_unittest.cc", "typed_url_sync_metadata_database_unittest.cc", "typed_url_syncable_service_unittest.cc", "url_database_unittest.cc",
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc index bb21144..2a9e668d 100644 --- a/components/history/core/browser/history_backend.cc +++ b/components/history/core/browser/history_backend.cc
@@ -41,7 +41,6 @@ #include "components/history/core/browser/in_memory_history_backend.h" #include "components/history/core/browser/keyword_search_term.h" #include "components/history/core/browser/page_usage_data.h" -#include "components/history/core/browser/typed_url_sync_bridge.h" #include "components/history/core/browser/typed_url_syncable_service.h" #include "components/history/core/browser/url_utils.h" #include "components/sync/driver/sync_driver_switches.h" @@ -224,6 +223,7 @@ &ModelTypeChangeProcessor::Create, // TODO(gangwu): use ReportUnrecoverableError before launch. base::BindRepeating(base::IgnoreResult(&DumpWithoutCrashing)))); + typed_url_sync_bridge_->Init(); } else { typed_url_syncable_service_ = base::MakeUnique<TypedUrlSyncableService>(this);
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h index 59c5838..cae7870 100644 --- a/components/history/core/browser/history_backend.h +++ b/components/history/core/browser/history_backend.h
@@ -32,6 +32,7 @@ #include "components/history/core/browser/history_types.h" #include "components/history/core/browser/keyword_id.h" #include "components/history/core/browser/thumbnail_database.h" +#include "components/history/core/browser/typed_url_sync_bridge.h" #include "components/history/core/browser/visit_tracker.h" #include "sql/init_status.h" @@ -53,7 +54,6 @@ class HistoryDBTask; class InMemoryHistoryBackend; class TypedUrlSyncableService; -class TypedURLSyncBridge; class HistoryBackendHelper; class URLDatabase; @@ -476,6 +476,11 @@ HistoryDatabase* db() const { return db_.get(); } ExpireHistoryBackend* expire_backend() { return &expirer_; } + + void SetTypedURLSyncBridgeForTest( + std::unique_ptr<TypedURLSyncBridge> bridge) { + typed_url_sync_bridge_ = std::move(bridge); + } #endif // Returns true if the passed visit time is already expired (used by the sync
diff --git a/components/history/core/browser/typed_url_sync_bridge.cc b/components/history/core/browser/typed_url_sync_bridge.cc index 40d57d6..48edb4e 100644 --- a/components/history/core/browser/typed_url_sync_bridge.cc +++ b/components/history/core/browser/typed_url_sync_bridge.cc
@@ -4,22 +4,67 @@ #include "components/history/core/browser/typed_url_sync_bridge.h" +#include "base/big_endian.h" #include "base/memory/ptr_util.h" +#include "base/strings/utf_string_conversions.h" +#include "components/history/core/browser/history_backend.h" +#include "components/sync/model/mutable_data_batch.h" #include "components/sync/model_impl/sync_metadata_store_change_list.h" +using syncer::EntityData; +using sync_pb::TypedUrlSpecifics; +using syncer::MutableDataBatch; + namespace history { +namespace { + +// The server backend can't handle arbitrarily large node sizes, so to keep +// the size under control we limit the visit array. +static const int kMaxTypedUrlVisits = 100; + +// There's no limit on how many visits the history DB could have for a given +// typed URL, so we limit how many we fetch from the DB to avoid crashes due to +// running out of memory (http://crbug.com/89793). This value is different +// from kMaxTypedUrlVisits, as some of the visits fetched from the DB may be +// RELOAD visits, which will be stripped. +static const int kMaxVisitsToFetch = 1000; + +// Enforce oldest to newest visit order. +static bool CheckVisitOrdering(const VisitVector& visits) { + int64_t previous_visit_time = 0; + for (VisitVector::const_iterator visit = visits.begin(); + visit != visits.end(); ++visit) { + if (visit != visits.begin() && + previous_visit_time > visit->visit_time.ToInternalValue()) + return false; + + previous_visit_time = visit->visit_time.ToInternalValue(); + } + return true; +} + +std::string GetStorageKeyFromURLRow(const URLRow& row) { + std::string storage_key(sizeof(row.id()), 0); + base::WriteBigEndian<URLID>(&storage_key[0], row.id()); + return storage_key; +} + +} // namespace + TypedURLSyncBridge::TypedURLSyncBridge( HistoryBackend* history_backend, - syncer::SyncMetadataStore* sync_metadata_store, + TypedURLSyncMetadataDatabase* sync_metadata_database, const ChangeProcessorFactory& change_processor_factory) : ModelTypeSyncBridge(change_processor_factory, syncer::TYPED_URLS), history_backend_(history_backend), - sync_metadata_store_(sync_metadata_store) { + sync_metadata_database_(sync_metadata_database), + num_db_accesses_(0), + num_db_errors_(0), + history_backend_observer_(this) { DCHECK(history_backend_); DCHECK(sequence_checker_.CalledOnValidSequence()); - DCHECK(sync_metadata_store_); - NOTIMPLEMENTED(); + DCHECK(sync_metadata_database_); } TypedURLSyncBridge::~TypedURLSyncBridge() { @@ -31,7 +76,7 @@ TypedURLSyncBridge::CreateMetadataChangeList() { DCHECK(sequence_checker_.CalledOnValidSequence()); return base::MakeUnique<syncer::SyncMetadataStoreChangeList>( - sync_metadata_store_, syncer::TYPED_URLS); + sync_metadata_database_, syncer::TYPED_URLS); } base::Optional<syncer::ModelError> TypedURLSyncBridge::MergeSyncData( @@ -58,15 +103,31 @@ void TypedURLSyncBridge::GetAllData(DataCallback callback) { DCHECK(sequence_checker_.CalledOnValidSequence()); - NOTIMPLEMENTED(); + + history::URLRows typed_urls; + ++num_db_accesses_; + if (!history_backend_->GetAllTypedURLs(&typed_urls)) { + ++num_db_errors_; + change_processor()->ReportError(FROM_HERE, + "Could not get the typed_url entries."); + return; + } + + auto batch = base::MakeUnique<MutableDataBatch>(); + for (history::URLRow& url : typed_urls) { + VisitVector visits_vector; + FixupURLAndGetVisits(&url, &visits_vector); + batch->Put(GetStorageKeyFromURLRow(url), + CreateEntityData(url, visits_vector)); + } + callback.Run(std::move(batch)); } // Must be exactly the value of GURL::spec() for backwards comparability with // the previous (Directory + SyncableService) iteration of sync integration. // This can be large but it is assumed that this is not held in memory at steady // state. -std::string TypedURLSyncBridge::GetClientTag( - const syncer::EntityData& entity_data) { +std::string TypedURLSyncBridge::GetClientTag(const EntityData& entity_data) { DCHECK(sequence_checker_.CalledOnValidSequence()); DCHECK(entity_data.specifics.has_typed_url()) << "EntityData does not have typed urls specifics."; @@ -76,11 +137,25 @@ // Prefer to use URLRow::id() to uniquely identify entities when coordinating // with sync because it has a significantly low memory cost than a URL. -std::string TypedURLSyncBridge::GetStorageKey( - const syncer::EntityData& entity_data) { +std::string TypedURLSyncBridge::GetStorageKey(const EntityData& entity_data) { DCHECK(sequence_checker_.CalledOnValidSequence()); - NOTIMPLEMENTED(); - return std::string(); + DCHECK(history_backend_); + DCHECK(entity_data.specifics.has_typed_url()) + << "EntityData does not have typed urls specifics."; + + const TypedUrlSpecifics& typed_url(entity_data.specifics.typed_url()); + URLRow existing_url; + ++num_db_accesses_; + bool is_existing_url = + history_backend_->GetURL(GURL(typed_url.url()), &existing_url); + + if (!is_existing_url) { + // The typed url did not save to local history database yet, so return URL + // for now. + return entity_data.specifics.typed_url().url(); + } + + return GetStorageKeyFromURLRow(existing_url); } void TypedURLSyncBridge::OnURLVisited(history::HistoryBackend* history_backend, @@ -108,4 +183,209 @@ NOTIMPLEMENTED(); } +void TypedURLSyncBridge::Init() { + DCHECK(sequence_checker_.CalledOnValidSequence()); + + history_backend_observer_.Add(history_backend_); + LoadMetadata(); +} + +int TypedURLSyncBridge::GetErrorPercentage() const { + return num_db_accesses_ ? (100 * num_db_errors_ / num_db_accesses_) : 0; +} + +bool TypedURLSyncBridge::WriteToTypedUrlSpecifics( + const URLRow& url, + const VisitVector& visits, + TypedUrlSpecifics* typed_url) { + DCHECK(!url.last_visit().is_null()); + DCHECK(!visits.empty()); + DCHECK_EQ(url.last_visit().ToInternalValue(), + visits.back().visit_time.ToInternalValue()); + + typed_url->set_url(url.url().spec()); + typed_url->set_title(base::UTF16ToUTF8(url.title())); + typed_url->set_hidden(url.hidden()); + + DCHECK(CheckVisitOrdering(visits)); + + bool only_typed = false; + int skip_count = 0; + + if (std::find_if(visits.begin(), visits.end(), + [](const history::VisitRow& visit) { + return ui::PageTransitionCoreTypeIs( + visit.transition, ui::PAGE_TRANSITION_TYPED); + }) == visits.end()) { + // This URL has no TYPED visits, don't sync it + return false; + } + + if (visits.size() > static_cast<size_t>(kMaxTypedUrlVisits)) { + int typed_count = 0; + int total = 0; + // Walk the passed-in visit vector and count the # of typed visits. + for (VisitRow visit : visits) { + // We ignore reload visits. + if (PageTransitionCoreTypeIs(visit.transition, + ui::PAGE_TRANSITION_RELOAD)) { + continue; + } + ++total; + if (PageTransitionCoreTypeIs(visit.transition, + ui::PAGE_TRANSITION_TYPED)) { + ++typed_count; + } + } + + // We should have at least one typed visit. This can sometimes happen if + // the history DB has an inaccurate count for some reason (there's been + // bugs in the history code in the past which has left users in the wild + // with incorrect counts - http://crbug.com/84258). + DCHECK(typed_count > 0); + + if (typed_count > kMaxTypedUrlVisits) { + only_typed = true; + skip_count = typed_count - kMaxTypedUrlVisits; + } else if (total > kMaxTypedUrlVisits) { + skip_count = total - kMaxTypedUrlVisits; + } + } + + for (const auto& visit : visits) { + // Skip reload visits. + if (PageTransitionCoreTypeIs(visit.transition, ui::PAGE_TRANSITION_RELOAD)) + continue; + + // If we only have room for typed visits, then only add typed visits. + if (only_typed && !PageTransitionCoreTypeIs(visit.transition, + ui::PAGE_TRANSITION_TYPED)) { + continue; + } + + if (skip_count > 0) { + // We have too many entries to fit, so we need to skip the oldest ones. + // Only skip typed URLs if there are too many typed URLs to fit. + if (only_typed || !PageTransitionCoreTypeIs(visit.transition, + ui::PAGE_TRANSITION_TYPED)) { + --skip_count; + continue; + } + } + typed_url->add_visits(visit.visit_time.ToInternalValue()); + typed_url->add_visit_transitions(visit.transition); + } + DCHECK_EQ(skip_count, 0); + + CHECK_GT(typed_url->visits_size(), 0); + CHECK_LE(typed_url->visits_size(), kMaxTypedUrlVisits); + CHECK_EQ(typed_url->visits_size(), typed_url->visit_transitions_size()); + + return true; +} + +void TypedURLSyncBridge::LoadMetadata() { + if (!history_backend_ || !sync_metadata_database_) { + change_processor()->ReportError( + FROM_HERE, "Failed to load TypedURLSyncMetadataDatabase."); + return; + } + + auto batch = base::MakeUnique<syncer::MetadataBatch>(); + if (!sync_metadata_database_->GetAllSyncMetadata(batch.get())) { + change_processor()->ReportError( + FROM_HERE, + "Failed reading typed url metadata from TypedURLSyncMetadataDatabase."); + return; + } + change_processor()->ModelReadyToSync(std::move(batch)); +} + +void TypedURLSyncBridge::ClearErrorStats() { + num_db_accesses_ = 0; + num_db_errors_ = 0; +} + +bool TypedURLSyncBridge::FixupURLAndGetVisits(URLRow* url, + VisitVector* visits) { + ++num_db_accesses_; + if (!history_backend_->GetMostRecentVisitsForURL(url->id(), kMaxVisitsToFetch, + visits)) { + ++num_db_errors_; + // Couldn't load the visits for this URL due to some kind of DB error. + // Don't bother writing this URL to the history DB (if we ignore the + // error and continue, we might end up duplicating existing visits). + DLOG(ERROR) << "Could not load visits for url: " << url->url(); + return false; + } + + // Sometimes (due to a bug elsewhere in the history or sync code, or due to + // a crash between adding a URL to the history database and updating the + // visit DB) the visit vector for a URL can be empty. If this happens, just + // create a new visit whose timestamp is the same as the last_visit time. + // This is a workaround for http://crbug.com/84258. + if (visits->empty()) { + DVLOG(1) << "Found empty visits for URL: " << url->url(); + if (url->last_visit().is_null()) { + // If modified URL is bookmarked, history backend treats it as modified + // even if all its visits are deleted. Return false to stop further + // processing because sync expects valid visit time for modified entry. + return false; + } + + VisitRow visit(url->id(), url->last_visit(), 0, ui::PAGE_TRANSITION_TYPED, + 0); + visits->push_back(visit); + } + + // GetMostRecentVisitsForURL() returns the data in the opposite order that + // we need it, so reverse it. + std::reverse(visits->begin(), visits->end()); + + // Sometimes, the last_visit field in the URL doesn't match the timestamp of + // the last visit in our visit array (they come from different tables, so + // crashes/bugs can cause them to mismatch), so just set it here. + url->set_last_visit(visits->back().visit_time); + DCHECK(CheckVisitOrdering(*visits)); + + // Removes all visits that are older than the current expiration time. Visits + // are in ascending order now, so we can check from beginning to check how + // many expired visits. + size_t num_expired_visits = 0; + for (auto& visit : *visits) { + base::Time time = visit.visit_time; + if (history_backend_->IsExpiredVisitTime(time)) { + ++num_expired_visits; + } else { + break; + } + } + if (num_expired_visits != 0) { + if (num_expired_visits == visits->size()) { + DVLOG(1) << "All visits are expired for url: " << url->url(); + visits->clear(); + return false; + } + visits->erase(visits->begin(), visits->begin() + num_expired_visits); + } + DCHECK(CheckVisitOrdering(*visits)); + + return true; +} + +std::unique_ptr<EntityData> TypedURLSyncBridge::CreateEntityData( + const URLRow& row, + const VisitVector& visits) { + auto entity_data = base::MakeUnique<EntityData>(); + TypedUrlSpecifics* specifics = entity_data->specifics.mutable_typed_url(); + + if (!WriteToTypedUrlSpecifics(row, visits, specifics)) { + // Cannot write to specifics, ex. no TYPED visits. + return base::MakeUnique<EntityData>(); + } + entity_data->non_unique_name = row.url().spec(); + + return entity_data; +} + } // namespace history
diff --git a/components/history/core/browser/typed_url_sync_bridge.h b/components/history/core/browser/typed_url_sync_bridge.h index 59eb075..281e673a 100644 --- a/components/history/core/browser/typed_url_sync_bridge.h +++ b/components/history/core/browser/typed_url_sync_bridge.h
@@ -5,15 +5,13 @@ #ifndef COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_BRIDGE_H_ #define COMPONENTS_HISTORY_CORE_BROWSER_TYPED_URL_SYNC_BRIDGE_H_ +#include "base/scoped_observer.h" #include "components/history/core/browser/history_backend_observer.h" +#include "components/history/core/browser/typed_url_sync_metadata_database.h" #include "components/sync/model/metadata_change_list.h" #include "components/sync/model/model_type_sync_bridge.h" #include "components/sync/model/sync_error.h" -namespace syncer { -class SyncMetadataStore; -} - namespace history { class TypedURLSyncBridge : public syncer::ModelTypeSyncBridge, @@ -22,7 +20,7 @@ // |sync_metadata_store| is owned by |history_backend|, and must outlive // TypedURLSyncBridge. TypedURLSyncBridge(HistoryBackend* history_backend, - syncer::SyncMetadataStore* sync_metadata_store, + TypedURLSyncMetadataDatabase* sync_metadata_store, const ChangeProcessorFactory& change_processor_factory); ~TypedURLSyncBridge() override; @@ -54,19 +52,69 @@ const history::URLRows& deleted_rows, const std::set<GURL>& favicon_urls) override; + // Must be called after creation and before any operations. + void Init(); + + // Returns the percentage of DB accesses that have resulted in an error. + int GetErrorPercentage() const; + + // Return true if this function successfully converts the passed URL + // information to a TypedUrlSpecifics structure for writing to the sync DB. + static bool WriteToTypedUrlSpecifics(const URLRow& url, + const VisitVector& visits, + sync_pb::TypedUrlSpecifics* specifics) + WARN_UNUSED_RESULT; + private: + friend class TypedURLSyncBridgeTest; + + // Synchronously load sync metadata from the TypedURLSyncMetadataDatabase and + // pass it to the processor so that it can start tracking changes. + void LoadMetadata(); + + // Helper function that clears our error counters (used to reset stats after + // merge so we can track merge errors separately). + void ClearErrorStats(); + + // Fetches visits from the history DB corresponding to the passed URL. This + // function compensates for the fact that the history DB has rather poor data + // integrity (duplicate visits, visit timestamps that don't match the + // last_visit timestamp, huge data sets that exhaust memory when fetched, + // expired visits that are not deleted by |ExpireHistoryBackend|, etc) by + // modifying the passed |url| object and |visits| vector. The order of + // |visits| will be from the oldest to the newest order. + // Returns false in two cases. + // 1. we could not fetch the visits for the passed URL, DB error. + // 2. No visits for the passed url, or all the visits are expired. + bool FixupURLAndGetVisits(URLRow* url, VisitVector* visits); + + // Create an EntityData by URL |row| and its visits |visits|. + std::unique_ptr<syncer::EntityData> CreateEntityData( + const URLRow& row, + const VisitVector& visits); + // A non-owning pointer to the backend, which we're syncing local changes from // and sync changes to. HistoryBackend* const history_backend_; // A non-owning pointer to the database, which is for storing typed urls sync // metadata and state. - syncer::SyncMetadataStore* const sync_metadata_store_; + TypedURLSyncMetadataDatabase* const sync_metadata_database_; + + // Statistics for the purposes of tracking the percentage of DB accesses that + // fail for each client via UMA. + int num_db_accesses_; + int num_db_errors_; // Since HistoryBackend use SequencedTaskRunner, so should use SequenceChecker // here. base::SequenceChecker sequence_checker_; + // Tracks observed history backend, for receiving updates from history + // backend. + ScopedObserver<history::HistoryBackend, history::HistoryBackendObserver> + history_backend_observer_; + DISALLOW_COPY_AND_ASSIGN(TypedURLSyncBridge); };
diff --git a/components/history/core/browser/typed_url_sync_bridge_unittest.cc b/components/history/core/browser/typed_url_sync_bridge_unittest.cc new file mode 100644 index 0000000..2453270 --- /dev/null +++ b/components/history/core/browser/typed_url_sync_bridge_unittest.cc
@@ -0,0 +1,260 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/history/core/browser/typed_url_sync_bridge.h" + +#include "base/files/scoped_temp_dir.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/thread_task_runner_handle.h" +#include "components/history/core/browser/history_backend.h" +#include "components/history/core/browser/history_backend_client.h" +#include "components/history/core/browser/history_database_params.h" +#include "components/history/core/browser/in_memory_history_backend.h" +#include "components/history/core/test/test_history_database.h" +#include "components/sync/model/data_batch.h" +#include "components/sync/model/recording_model_type_change_processor.h" +#include "components/sync/model/sync_metadata_store.h" +#include "testing/gtest/include/gtest/gtest.h" + +using sync_pb::TypedUrlSpecifics; +using syncer::DataBatch; +using syncer::EntityData; +using syncer::EntityDataPtr; +using syncer::KeyAndData; +using syncer::RecordingModelTypeChangeProcessor; + +namespace history { + +namespace { + +// Visits with this timestamp are treated as expired. +const int kExpiredVisit = -1; + +// Helper constants for tests. +const char kTitle[] = "pie"; +const char kTitle2[] = "cookie"; +const char kURL[] = "http://pie.com/"; +const char kURL2[] = "http://cookie.com/"; + +// Create a new row object and the typed visit çorresponding with the time at +// |last_visit| in the |visits| vector. +URLRow MakeTypedUrlRow(const std::string& url, + const std::string& title, + int typed_count, + int64_t last_visit, + bool hidden, + VisitVector* visits) { + // Give each URL a unique ID, to mimic the behavior of the real database. + GURL gurl(url); + URLRow history_url(gurl); + history_url.set_title(base::UTF8ToUTF16(title)); + history_url.set_typed_count(typed_count); + history_url.set_hidden(hidden); + + base::Time last_visit_time = base::Time::FromInternalValue(last_visit); + history_url.set_last_visit(last_visit_time); + + if (typed_count > 0) { + // Add a typed visit for time |last_visit|. + visits->push_back(VisitRow(history_url.id(), last_visit_time, 0, + ui::PAGE_TRANSITION_TYPED, 0)); + } else { + // Add a non-typed visit for time |last_visit|. + visits->push_back(VisitRow(history_url.id(), last_visit_time, 0, + ui::PAGE_TRANSITION_RELOAD, 0)); + } + + history_url.set_visit_count(visits->size()); + return history_url; +} + +void VerifyEqual(const TypedUrlSpecifics& s1, const TypedUrlSpecifics& s2) { + // Instead of just comparing serialized strings, manually check fields to show + // differences on failure. + EXPECT_EQ(s1.url(), s2.url()); + EXPECT_EQ(s1.title(), s2.title()); + EXPECT_EQ(s1.hidden(), s2.hidden()); + EXPECT_EQ(s1.visits_size(), s2.visits_size()); + EXPECT_EQ(s1.visit_transitions_size(), s2.visit_transitions_size()); + EXPECT_EQ(s1.visits_size(), s1.visit_transitions_size()); + int size = s1.visits_size(); + for (int i = 0; i < size; ++i) { + EXPECT_EQ(s1.visits(i), s2.visits(i)) << "visits differ at index " << i; + EXPECT_EQ(s1.visit_transitions(i), s2.visit_transitions(i)) + << "visit_transitions differ at index " << i; + } +} + +void VerifyDataBatch(std::map<std::string, TypedUrlSpecifics> expected, + std::unique_ptr<DataBatch> batch) { + while (batch->HasNext()) { + const KeyAndData& pair = batch->Next(); + auto iter = expected.find(pair.first); + ASSERT_NE(iter, expected.end()); + VerifyEqual(iter->second, pair.second->specifics.typed_url()); + // Removing allows us to verify we don't see the same item multiple times, + // and that we saw everything we expected. + expected.erase(iter); + } + EXPECT_TRUE(expected.empty()); +} + +class TestHistoryBackendDelegate : public HistoryBackend::Delegate { + public: + TestHistoryBackendDelegate() {} + + void NotifyProfileError(sql::InitStatus init_status, + const std::string& diagnostics) override {} + void SetInMemoryBackend( + std::unique_ptr<InMemoryHistoryBackend> backend) override{}; + void NotifyFaviconsChanged(const std::set<GURL>& page_urls, + const GURL& icon_url) override{}; + void NotifyURLVisited(ui::PageTransition transition, + const URLRow& row, + const RedirectList& redirects, + base::Time visit_time) override{}; + void NotifyURLsModified(const URLRows& changed_urls) override{}; + void NotifyURLsDeleted(bool all_history, + bool expired, + const URLRows& deleted_rows, + const std::set<GURL>& favicon_urls) override{}; + void NotifyKeywordSearchTermUpdated(const URLRow& row, + KeywordID keyword_id, + const base::string16& term) override{}; + void NotifyKeywordSearchTermDeleted(URLID url_id) override{}; + void DBLoaded() override{}; + + private: + DISALLOW_COPY_AND_ASSIGN(TestHistoryBackendDelegate); +}; + +class TestHistoryBackend : public HistoryBackend { + public: + TestHistoryBackend() + : HistoryBackend(new TestHistoryBackendDelegate(), + nullptr, + base::ThreadTaskRunnerHandle::Get()) {} + + bool IsExpiredVisitTime(const base::Time& time) override { + return time.ToInternalValue() == kExpiredVisit; + } + + URLID GetIdByUrl(const GURL& gurl) { + return db()->GetRowForURL(gurl, nullptr); + } + + void SetVisitsForUrl(URLRow& new_url, const VisitVector visits) { + std::vector<history::VisitInfo> added_visits; + URLRows new_urls; + DeleteURL(new_url.url()); + for (const auto& visit : visits) { + added_visits.push_back( + history::VisitInfo(visit.visit_time, visit.transition)); + } + new_urls.push_back(new_url); + AddPagesWithDetails(new_urls, history::SOURCE_SYNCED); + AddVisits(new_url.url(), added_visits, history::SOURCE_SYNCED); + new_url.set_id(GetIdByUrl(new_url.url())); + } + + private: + ~TestHistoryBackend() override {} +}; + +} // namespace + +class TypedURLSyncBridgeTest : public testing::Test { + public: + TypedURLSyncBridgeTest() : typed_url_sync_bridge_(NULL) {} + ~TypedURLSyncBridgeTest() override {} + + void SetUp() override { + fake_history_backend_ = new TestHistoryBackend(); + ASSERT_TRUE(test_dir_.CreateUniqueTempDir()); + fake_history_backend_->Init( + false, TestHistoryDatabaseParamsForPath(test_dir_.GetPath())); + std::unique_ptr<TypedURLSyncBridge> bridge = + base::MakeUnique<TypedURLSyncBridge>( + fake_history_backend_.get(), fake_history_backend_->db(), + RecordingModelTypeChangeProcessor::FactoryForBridgeTest(&processor_, + false)); + typed_url_sync_bridge_ = bridge.get(); + typed_url_sync_bridge_->Init(); + fake_history_backend_->SetTypedURLSyncBridgeForTest(std::move(bridge)); + } + + void TearDown() override { fake_history_backend_->Closing(); } + + // Fills |specifics| with the sync data for |url| and |visits|. + static bool WriteToTypedUrlSpecifics(const URLRow& url, + const VisitVector& visits, + sync_pb::TypedUrlSpecifics* specifics) { + return TypedURLSyncBridge::WriteToTypedUrlSpecifics(url, visits, specifics); + } + + std::string GetStorageKey(const TypedUrlSpecifics& specifics) { + std::string key = + bridge()->GetStorageKey(SpecificsToEntity(specifics).value()); + EXPECT_FALSE(key.empty()); + return key; + } + + EntityDataPtr SpecificsToEntity(const TypedUrlSpecifics& specifics) { + EntityData data; + data.client_tag_hash = "ignored"; + *data.specifics.mutable_typed_url() = specifics; + return data.PassToPtr(); + } + + std::map<std::string, TypedUrlSpecifics> ExpectedMap( + const std::vector<TypedUrlSpecifics>& specifics_vector) { + std::map<std::string, TypedUrlSpecifics> map; + for (const auto& specifics : specifics_vector) { + map[GetStorageKey(specifics)] = specifics; + } + return map; + } + + void VerifyLocalHistoryData(const std::vector<TypedUrlSpecifics>& expected) { + bridge()->GetAllData(base::Bind(&VerifyDataBatch, ExpectedMap(expected))); + } + + TypedURLSyncBridge* bridge() { return typed_url_sync_bridge_; } + + TypedURLSyncMetadataDatabase* metadata_store() { + return bridge()->sync_metadata_database_; + } + + const RecordingModelTypeChangeProcessor& processor() { return *processor_; } + + protected: + base::MessageLoop message_loop_; + base::ScopedTempDir test_dir_; + scoped_refptr<TestHistoryBackend> fake_history_backend_; + TypedURLSyncBridge* typed_url_sync_bridge_; + // A non-owning pointer to the processor given to the bridge. Will be null + // before being given to the bridge, to make ownership easier. + RecordingModelTypeChangeProcessor* processor_ = nullptr; +}; + +// Add two typed urls locally and verify bridge can get them from GetAllData. +TEST_F(TypedURLSyncBridgeTest, GetAllData) { + // Add two urls to backend. + VisitVector visits1, visits2; + URLRow row1 = MakeTypedUrlRow(kURL, kTitle, 1, 3, false, &visits1); + URLRow row2 = MakeTypedUrlRow(kURL2, kTitle2, 2, 4, false, &visits2); + fake_history_backend_->SetVisitsForUrl(row1, visits1); + fake_history_backend_->SetVisitsForUrl(row2, visits2); + + // Create the same data in sync. + sync_pb::TypedUrlSpecifics typed_url1, typed_url2; + WriteToTypedUrlSpecifics(row1, visits1, &typed_url1); + WriteToTypedUrlSpecifics(row2, visits2, &typed_url2); + + // Check that the local cache is still correct. + VerifyLocalHistoryData({typed_url1, typed_url2}); +} + +} // namespace history
diff --git a/components/history/core/browser/typed_url_sync_metadata_database.cc b/components/history/core/browser/typed_url_sync_metadata_database.cc index f0b2ce6..81e9da0 100644 --- a/components/history/core/browser/typed_url_sync_metadata_database.cc +++ b/components/history/core/browser/typed_url_sync_metadata_database.cc
@@ -4,8 +4,9 @@ #include "components/history/core/browser/typed_url_sync_metadata_database.h" +#include "base/big_endian.h" #include "base/logging.h" -#include "base/strings/string_number_conversions.h" +#include "components/history/core/browser/url_row.h" #include "sql/statement.h" namespace history { @@ -55,9 +56,11 @@ << "Only the TYPED_URLS model type is supported"; int64_t storage_key_int = 0; - if (!base::StringToInt64(storage_key, &storage_key_int)) { - return false; - } + DCHECK_EQ(storage_key.size(), sizeof(storage_key_int)); + base::ReadBigEndian(storage_key.data(), &storage_key_int); + // Make sure storage_key_int is set. + DCHECK_NE(storage_key_int, 0); + sql::Statement s(GetDB().GetUniqueStatement( "INSERT OR REPLACE INTO typed_url_sync_metadata " "(storage_key, value) VALUES(?, ?)")); @@ -74,9 +77,11 @@ << "Only the TYPED_URLS model type is supported"; int64_t storage_key_int = 0; - if (!base::StringToInt64(storage_key, &storage_key_int)) { - return false; - } + DCHECK_EQ(storage_key.size(), sizeof(storage_key_int)); + base::ReadBigEndian(storage_key.data(), &storage_key_int); + // Make sure storage_key_int is set. + DCHECK_NE(storage_key_int, 0); + sql::Statement s(GetDB().GetUniqueStatement( "DELETE FROM typed_url_sync_metadata WHERE storage_key=?")); s.BindInt64(0, storage_key_int); @@ -122,7 +127,8 @@ "SELECT storage_key, value FROM typed_url_sync_metadata")); while (s.Step()) { - std::string storage_key = base::Int64ToString(s.ColumnInt64(0)); + std::string storage_key(sizeof(URLID), 0); + base::WriteBigEndian<URLID>(&storage_key[0], s.ColumnInt64(0)); std::string serialized_metadata = s.ColumnString(1); sync_pb::EntityMetadata entity_metadata; if (entity_metadata.ParseFromString(serialized_metadata)) {
diff --git a/components/history/core/browser/typed_url_sync_metadata_database_unittest.cc b/components/history/core/browser/typed_url_sync_metadata_database_unittest.cc index c37bf3ee..ec0f22f 100644 --- a/components/history/core/browser/typed_url_sync_metadata_database_unittest.cc +++ b/components/history/core/browser/typed_url_sync_metadata_database_unittest.cc
@@ -4,8 +4,10 @@ #include "components/history/core/browser/typed_url_sync_metadata_database.h" +#include "base/big_endian.h" #include "base/files/file_path.h" #include "base/files/scoped_temp_dir.h" +#include "components/history/core/browser/url_row.h" #include "components/sync/protocol/model_type_state.pb.h" #include "sql/statement.h" #include "testing/gtest/include/gtest/gtest.h" @@ -17,6 +19,16 @@ namespace history { +namespace { + +std::string IntToStorageKey(int i) { + std::string storage_key(sizeof(URLID), 0); + base::WriteBigEndian<URLID>(&storage_key[0], i); + return storage_key; +} + +} // namespace + class TypedURLSyncMetadataDatabaseTest : public testing::Test, public TypedURLSyncMetadataDatabase { public: @@ -60,8 +72,8 @@ TEST_F(TypedURLSyncMetadataDatabaseTest, TypedURLGetAllSyncMetadata) { EntityMetadata metadata; - std::string storage_key = "1"; - std::string storage_key2 = "2"; + std::string storage_key = IntToStorageKey(1); + std::string storage_key2 = IntToStorageKey(2); metadata.set_sequence_number(1); EXPECT_TRUE(UpdateSyncMetadata(syncer::TYPED_URLS, storage_key, metadata)); @@ -96,7 +108,7 @@ TEST_F(TypedURLSyncMetadataDatabaseTest, TypedURLWriteThenDeleteSyncMetadata) { EntityMetadata metadata; MetadataBatch metadata_batch; - std::string storage_key = "1"; + std::string storage_key = IntToStorageKey(1); ModelTypeState model_type_state; model_type_state.set_initial_sync_done(true);
diff --git a/components/safe_browsing_db/v4_database_unittest.cc b/components/safe_browsing_db/v4_database_unittest.cc index de42e1a3..66db6fa5 100644 --- a/components/safe_browsing_db/v4_database_unittest.cc +++ b/components/safe_browsing_db/v4_database_unittest.cc
@@ -24,7 +24,7 @@ const bool hash_prefix_matches) : V4Store( task_runner, - base::FilePath(store_path.value() + FILE_PATH_LITERAL(".store"))), + base::FilePath(store_path.value() + FILE_PATH_LITERAL(".fake"))), hash_prefix_should_match_(hash_prefix_matches) {} HashPrefix GetMatchingHashPrefix(const FullHash& full_hash) override { @@ -103,13 +103,13 @@ SB_THREAT_TYPE_URL_MALWARE); expected_identifiers_.push_back(win_malware_id_); expected_store_paths_.push_back( - database_dirname_.AppendASCII("win_url_malware.store")); + database_dirname_.AppendASCII("win_url_malware.fake")); list_infos_.emplace_back(true, "linux_url_malware", linux_malware_id_, SB_THREAT_TYPE_URL_MALWARE); expected_identifiers_.push_back(linux_malware_id_); expected_store_paths_.push_back( - database_dirname_.AppendASCII("linux_url_malware.store")); + database_dirname_.AppendASCII("linux_url_malware.fake")); } void DatabaseUpdated() {}
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc index fbbc1b94..c17dbde9 100644 --- a/components/safe_browsing_db/v4_local_database_manager.cc +++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -11,12 +11,10 @@ #include "base/bind_helpers.h" #include "base/callback.h" -#include "base/files/file_util.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" -#include "base/metrics/histogram_functions.h" #include "base/metrics/histogram_macros.h" -#include "base/task_scheduler/post_task.h" +#include "base/threading/sequenced_worker_pool.h" #include "components/safe_browsing_db/v4_feature_list.h" #include "components/safe_browsing_db/v4_protocol_manager_util.h" #include "content/public/browser/browser_thread.h" @@ -32,14 +30,11 @@ const ThreatSeverity kLeastSeverity = std::numeric_limits<ThreatSeverity>::max(); -// The list of the name of any store files that are no longer used and can be -// safely deleted from the disk. There's no overlap allowed between the files -// on this list and the list returned by GetListInfos(). -const char* const kStoreFileNamesToDelete[] = {"AnyIpMalware.store"}; - ListInfos GetListInfos() { // NOTE(vakh): When adding a store here, add the corresponding store-specific // histograms also. + // NOTE(vakh): Delete file "AnyIpMalware.store". It has been renamed to + // "IpMalware.store". If it exists, it should be 75 bytes long. // The first argument to ListInfo specifies whether to sync hash prefixes for // that list. This can be false for two reasons: // - The server doesn't support that list yet. Once the server adds support @@ -161,14 +156,10 @@ : base_path_(base_path), extended_reporting_level_callback_(extended_reporting_level_callback), list_infos_(GetListInfos()), - task_runner_(base::CreateSequencedTaskRunnerWithTraits( - {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN})), weak_factory_(this) { DCHECK(!base_path_.empty()); DCHECK(!list_infos_.empty()); - DeleteUnusedStoreFiles(); - DVLOG(1) << "V4LocalDatabaseManager::V4LocalDatabaseManager: " << "base_path_: " << base_path_.AsUTF8Unsafe(); } @@ -505,32 +496,6 @@ } } -void V4LocalDatabaseManager::DeleteUnusedStoreFiles() { - for (auto* const store_filename_to_delete : kStoreFileNamesToDelete) { - // Is the file marked for deletion also being used for a valid V4Store? - auto it = std::find_if(std::begin(list_infos_), std::end(list_infos_), - [&store_filename_to_delete](ListInfo const& li) { - return li.filename() == store_filename_to_delete; - }); - if (list_infos_.end() == it) { - const auto& store_path = base_path_.AppendASCII(store_filename_to_delete); - bool path_exists = base::PathExists(store_path); - base::UmaHistogramBoolean("SafeBrowsing.V4UnusedStoreFileExists" + - GetUmaSuffixForStore(store_path), - path_exists); - if (!path_exists) { - continue; - } - task_runner_->PostTask(FROM_HERE, - base::Bind(base::IgnoreResult(&base::DeleteFile), - store_path, false /* recursive */)); - } else { - NOTREACHED() << "Trying to delete a store file that's in use: " - << store_filename_to_delete; - } - } -} - bool V4LocalDatabaseManager::GetPrefixMatches( const std::unique_ptr<PendingCheck>& check, FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes) { @@ -824,6 +789,14 @@ DCHECK(!list_infos_.empty()); DCHECK_CURRENTLY_ON(BrowserThread::IO); + // Only get a new task runner if there isn't one already. If the service has + // previously been started and stopped, a task runner could already exist. + if (!task_runner_) { + base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool(); + task_runner_ = pool->GetSequencedTaskRunnerWithShutdownBehavior( + pool->GetSequenceToken(), base::SequencedWorkerPool::SKIP_ON_SHUTDOWN); + } + // Do not create the database on the IO thread since this may be an expensive // operation. Instead, do that on the task_runner and when the new database // has been created, swap it out on the IO thread.
diff --git a/components/safe_browsing_db/v4_local_database_manager.h b/components/safe_browsing_db/v4_local_database_manager.h index b82d9a8..0c154325 100644 --- a/components/safe_browsing_db/v4_local_database_manager.h +++ b/components/safe_browsing_db/v4_local_database_manager.h
@@ -198,9 +198,6 @@ // Called when the database has been updated and schedules the next update. void DatabaseUpdated(); - // Delete any *.store files from disk that are no longer used. - void DeleteUnusedStoreFiles(); - // Identifies the prefixes and the store they matched in, for a given |check|. // Returns true if one or more hash prefix matches are found; false otherwise. bool GetPrefixMatches(
diff --git a/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/components/safe_browsing_db/v4_local_database_manager_unittest.cc index 9d2e633..5e20cb7 100644 --- a/components/safe_browsing_db/v4_local_database_manager_unittest.cc +++ b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -3,7 +3,6 @@ // found in the LICENSE file. #include "components/safe_browsing_db/v4_local_database_manager.h" -#include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/ptr_util.h" #include "base/memory/ref_counted.h" @@ -1102,45 +1101,4 @@ EXPECT_TRUE(client.on_check_download_urls_result_called_); } -TEST_F(V4LocalDatabaseManagerTest, DeleteUnusedStoreFileDoesNotExist) { - auto store_file_path = base_dir_.GetPath().AppendASCII("AnyIpMalware.store"); - ASSERT_FALSE(base::PathExists(store_file_path)); - - // Reset the database manager so that DeleteUnusedStoreFiles is called. - ResetLocalDatabaseManager(); - WaitForTasksOnTaskRunner(); - ASSERT_FALSE(base::PathExists(store_file_path)); -} - -TEST_F(V4LocalDatabaseManagerTest, DeleteUnusedStoreFileSuccess) { - auto store_file_path = base_dir_.GetPath().AppendASCII("AnyIpMalware.store"); - ASSERT_FALSE(base::PathExists(store_file_path)); - - // Now write an empty file. - base::WriteFile(store_file_path, "", 0); - ASSERT_TRUE(base::PathExists(store_file_path)); - - // Reset the database manager so that DeleteUnusedStoreFiles is called. - ResetLocalDatabaseManager(); - WaitForTasksOnTaskRunner(); - ASSERT_FALSE(base::PathExists(store_file_path)); -} - -TEST_F(V4LocalDatabaseManagerTest, DeleteUnusedStoreFileRandomFileNotDeleted) { - auto random_store_file_path = base_dir_.GetPath().AppendASCII("random.store"); - ASSERT_FALSE(base::PathExists(random_store_file_path)); - - // Now write an empty file. - base::WriteFile(random_store_file_path, "", 0); - ASSERT_TRUE(base::PathExists(random_store_file_path)); - - // Reset the database manager so that DeleteUnusedStoreFiles is called. - ResetLocalDatabaseManager(); - WaitForTasksOnTaskRunner(); - ASSERT_TRUE(base::PathExists(random_store_file_path)); - - // Cleanup - base::DeleteFile(random_store_file_path, false /* recursive */); -} - } // namespace safe_browsing
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.cc b/components/safe_browsing_db/v4_protocol_manager_util.cc index 022374a..44aeee98 100644 --- a/components/safe_browsing_db/v4_protocol_manager_util.cc +++ b/components/safe_browsing_db/v4_protocol_manager_util.cc
@@ -21,10 +21,6 @@ using base::TimeDelta; namespace safe_browsing { -const base::FilePath::CharType kStoreSuffix[] = FILE_PATH_LITERAL(".store"); - -// The Safe Browsing V4 server URL prefix. -const char kSbV4UrlPrefix[] = "https://safebrowsing.googleapis.com/v4"; namespace { @@ -145,11 +141,8 @@ return ListIdentifier(GetCurrentPlatformType(), URL, UNWANTED_SOFTWARE); } -std::string GetUmaSuffixForStore(const base::FilePath& file_path) { - DCHECK_EQ(kStoreSuffix, file_path.BaseName().Extension()); - return base::StringPrintf( - ".%" PRIsFP, file_path.BaseName().RemoveExtension().value().c_str()); -} +// The Safe Browsing V4 server URL prefix. +const char kSbV4UrlPrefix[] = "https://safebrowsing.googleapis.com/v4"; StoreAndHashPrefix::StoreAndHashPrefix(ListIdentifier list_id, const HashPrefix& hash_prefix)
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.h b/components/safe_browsing_db/v4_protocol_manager_util.h index 434b94b..54b5225 100644 --- a/components/safe_browsing_db/v4_protocol_manager_util.h +++ b/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -169,9 +169,6 @@ ListIdentifier GetUrlSubresourceFilterId(); ListIdentifier GetUrlUwsId(); -// Returns the basename of the store file, without the ".store" extension. -std::string GetUmaSuffixForStore(const base::FilePath& file_path); - // Represents the state of each store. using StoreStateMap = std::unordered_map<ListIdentifier, std::string>;
diff --git a/components/safe_browsing_db/v4_store.cc b/components/safe_browsing_db/v4_store.cc index 5871922..fe3220a1 100644 --- a/components/safe_browsing_db/v4_store.cc +++ b/components/safe_browsing_db/v4_store.cc
@@ -46,6 +46,11 @@ const uint32_t kFileMagic = 0x600D71FE; const uint32_t kFileVersion = 9; +std::string GetUmaSuffixForStore(const base::FilePath& file_path) { + return base::StringPrintf( + ".%" PRIsFP, file_path.BaseName().RemoveExtension().value().c_str()); +} + void RecordTimeWithAndWithoutSuffix(const std::string& metric, base::TimeDelta time, const base::FilePath& file_path) {
diff --git a/components/security_interstitials/core/browser/resources/interstitial_v2.css b/components/security_interstitials/core/browser/resources/interstitial_v2.css index 5af309a..fdda65d 100644 --- a/components/security_interstitials/core/browser/resources/interstitial_v2.css +++ b/components/security_interstitials/core/browser/resources/interstitial_v2.css
@@ -65,7 +65,7 @@ #details { color: #696969; - margin: 45px 0 50px; + margin: 0 0 50px; } #details p:not(:first-of-type) { @@ -315,7 +315,7 @@ @media (min-width: 240px) and (max-width: 420px) and (min-height: 401px), (min-width: 421px) and (min-height: 240px) and - (max-height: 736px) { + (max-height: 560px) { body .nav-wrapper { background: #f7f7f7; bottom: 0; @@ -348,7 +348,7 @@ } @media (max-width: 420px) and (orientation: portrait), - (max-height: 736px) { + (max-height: 560px) { body { margin: 0 auto; } @@ -435,7 +435,7 @@ } } -@media (min-width: 421px) and (min-height: 500px) and (max-height: 736px) { +@media (min-width: 421px) and (min-height: 500px) and (max-height: 560px) { .interstitial-wrapper { margin-top: 10vh; }
diff --git a/components/security_interstitials/core/browser/resources/interstitial_v2_mobile.js b/components/security_interstitials/core/browser/resources/interstitial_v2_mobile.js index 8980099..655d91f 100644 --- a/components/security_interstitials/core/browser/resources/interstitial_v2_mobile.js +++ b/components/security_interstitials/core/browser/resources/interstitial_v2_mobile.js
@@ -13,7 +13,7 @@ var mainContent = document.querySelector('#main-content'); var mediaQuery = '(min-width: 240px) and (max-width: 420px) and ' + '(min-height: 401px), ' + - '(max-height: 736px) and (min-height: 240px) and ' + + '(max-height: 560px) and (min-height: 240px) and ' + '(min-width: 421px)'; var detailsHidden = helpOuterBox.classList.contains('hidden');
diff --git a/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css b/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css index 80a87648c..12719e8 100644 --- a/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css +++ b/components/security_interstitials/core/browser/resources/interstitial_webview_quiet.css
@@ -34,7 +34,9 @@ h1 { color: rgba(0,0,0,.38); + font-family: Roboto-Regular; font-size: 1.037037em; + font-weight: normal; line-height: 1.4em; margin: 8px 0 8px; } @@ -55,10 +57,11 @@ .icon { background-image: url(images/blocked.svg); + background-position: center; height: 20vh; margin: 0 auto; - max-height: 36px; - max-width: 36px; + max-height: 24px; + max-width: 24px; min-height: 18px; min-width: 18px; opacity: .54; @@ -96,8 +99,8 @@ @media (min-height:25em) and (min-width:37.5em), (min-height:37.5em) and (min-width:25em) { .icon { - height: 36px; - width: 36px; + max-height: 36px; + max-width: 36px; } }
diff --git a/components/subresource_filter/content/browser/BUILD.gn b/components/subresource_filter/content/browser/BUILD.gn index dd59a01..cfd824e 100644 --- a/components/subresource_filter/content/browser/BUILD.gn +++ b/components/subresource_filter/content/browser/BUILD.gn
@@ -59,6 +59,8 @@ "async_document_subresource_filter_test_utils.h", "fake_safe_browsing_database_manager.cc", "fake_safe_browsing_database_manager.h", + "subresource_filter_observer_test_utils.cc", + "subresource_filter_observer_test_utils.h", ] deps = [ ":browser",
diff --git a/components/subresource_filter/content/browser/async_document_subresource_filter.h b/components/subresource_filter/content/browser/async_document_subresource_filter.h index b96e827..92c80ac 100644 --- a/components/subresource_filter/content/browser/async_document_subresource_filter.h +++ b/components/subresource_filter/content/browser/async_document_subresource_filter.h
@@ -16,6 +16,7 @@ #include "components/subresource_filter/core/common/activation_level.h" #include "components/subresource_filter/core/common/activation_state.h" #include "components/subresource_filter/core/common/document_subresource_filter.h" +#include "components/subresource_filter/core/common/load_policy.h" #include "url/gurl.h" #include "url/origin.h"
diff --git a/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc b/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc index 88a0862..424f872 100644 --- a/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc +++ b/components/subresource_filter/content/browser/async_document_subresource_filter_unittest.cc
@@ -16,6 +16,7 @@ #include "base/test/test_simple_task_runner.h" #include "base/threading/sequenced_task_runner_handle.h" #include "components/subresource_filter/content/browser/async_document_subresource_filter_test_utils.h" +#include "components/subresource_filter/core/common/load_policy.h" #include "components/subresource_filter/core/common/proto/rules.pb.h" #include "components/subresource_filter/core/common/test_ruleset_creator.h" #include "components/subresource_filter/core/common/test_ruleset_utils.h"
diff --git a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc index 8254f53..877a4d3 100644 --- a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc +++ b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.cc
@@ -7,6 +7,7 @@ #include "base/bind.h" #include "base/logging.h" #include "base/metrics/histogram_macros.h" +#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h" #include "components/subresource_filter/core/common/time_measurements.h" #include "content/public/browser/navigation_handle.h" #include "content/public/common/browser_side_navigation_policy.h" @@ -24,16 +25,21 @@ } SubframeNavigationFilteringThrottle::~SubframeNavigationFilteringThrottle() { - if (disallowed_) { - UMA_HISTOGRAM_CUSTOM_MICRO_TIMES( - "SubresourceFilter.DocumentLoad.SubframeFilteringDelay.Disallowed", - total_defer_time_, base::TimeDelta::FromMicroseconds(1), - base::TimeDelta::FromSeconds(10), 50); - } else { - UMA_HISTOGRAM_CUSTOM_MICRO_TIMES( - "SubresourceFilter.DocumentLoad.SubframeFilteringDelay.Allowed", - total_defer_time_, base::TimeDelta::FromMicroseconds(1), - base::TimeDelta::FromSeconds(10), 50); + switch (load_policy_) { + case LoadPolicy::ALLOW: + UMA_HISTOGRAM_CUSTOM_MICRO_TIMES( + "SubresourceFilter.DocumentLoad.SubframeFilteringDelay.Allowed", + total_defer_time_, base::TimeDelta::FromMicroseconds(1), + base::TimeDelta::FromSeconds(10), 50); + break; + case LoadPolicy::WOULD_DISALLOW: + // fall through + case LoadPolicy::DISALLOW: + UMA_HISTOGRAM_CUSTOM_MICRO_TIMES( + "SubresourceFilter.DocumentLoad.SubframeFilteringDelay.Disallowed", + total_defer_time_, base::TimeDelta::FromMicroseconds(1), + base::TimeDelta::FromSeconds(10), 50); + break; } } @@ -47,6 +53,13 @@ return DeferToCalculateLoadPolicy(ThrottlingStage::WillRedirectRequest); } +content::NavigationThrottle::ThrottleCheckResult +SubframeNavigationFilteringThrottle::WillProcessResponse() { + DCHECK_NE(load_policy_, LoadPolicy::DISALLOW); + NotifyLoadPolicy(); + return content::NavigationThrottle::ThrottleCheckResult::PROCEED; +} + const char* SubframeNavigationFilteringThrottle::GetNameForLogging() { return "SubframeNavigationFilteringThrottle"; } @@ -54,6 +67,9 @@ content::NavigationThrottle::ThrottleCheckResult SubframeNavigationFilteringThrottle::DeferToCalculateLoadPolicy( ThrottlingStage stage) { + DCHECK_NE(load_policy_, LoadPolicy::DISALLOW); + if (load_policy_ == LoadPolicy::WOULD_DISALLOW) + return content::NavigationThrottle::ThrottleCheckResult::PROCEED; parent_frame_filter_->GetLoadPolicyForSubdocument( navigation_handle()->GetURL(), base::Bind(&SubframeNavigationFilteringThrottle::OnCalculatedLoadPolicy, @@ -66,12 +82,13 @@ ThrottlingStage stage, LoadPolicy policy) { DCHECK(!last_defer_timestamp_.is_null()); + load_policy_ = policy; total_defer_time_ += base::TimeTicks::Now() - last_defer_timestamp_; - // TODO(csharrison): Support WouldDisallow pattern and expose the policy for - // metrics. + if (policy == LoadPolicy::DISALLOW) { - disallowed_ = true; parent_frame_filter_->ReportDisallowedLoad(); + // Other load policies will be reported in WillProcessResponse. + NotifyLoadPolicy(); const bool block_and_collapse_is_supported = content::IsBrowserSideNavigationEnabled() || @@ -85,4 +102,13 @@ } } +void SubframeNavigationFilteringThrottle::NotifyLoadPolicy() const { + if (auto* observer_manager = + SubresourceFilterObserverManager::FromWebContents( + navigation_handle()->GetWebContents())) { + observer_manager->NotifySubframeNavigationEvaluated(navigation_handle(), + load_policy_); + } +} + } // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h index e4dbfe12..74d8921 100644 --- a/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h +++ b/components/subresource_filter/content/browser/subframe_navigation_filtering_throttle.h
@@ -9,6 +9,7 @@ #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "components/subresource_filter/content/browser/async_document_subresource_filter.h" +#include "components/subresource_filter/core/common/load_policy.h" #include "content/public/browser/navigation_throttle.h" namespace content { @@ -38,6 +39,8 @@ content::NavigationThrottle::ThrottleCheckResult WillStartRequest() override; content::NavigationThrottle::ThrottleCheckResult WillRedirectRequest() override; + content::NavigationThrottle::ThrottleCheckResult WillProcessResponse() + override; const char* GetNameForLogging() override; private: @@ -47,12 +50,14 @@ ThrottlingStage stage); void OnCalculatedLoadPolicy(ThrottlingStage stage, LoadPolicy policy); + void NotifyLoadPolicy() const; + // Must outlive this class. AsyncDocumentSubresourceFilter* parent_frame_filter_; base::TimeTicks last_defer_timestamp_; base::TimeDelta total_defer_time_; - bool disallowed_ = false; + LoadPolicy load_policy_ = LoadPolicy::ALLOW; base::WeakPtrFactory<SubframeNavigationFilteringThrottle> weak_ptr_factory_;
diff --git a/components/subresource_filter/content/browser/subresource_filter_observer.h b/components/subresource_filter/content/browser/subresource_filter_observer.h index 7daa78a6..8946095 100644 --- a/components/subresource_filter/content/browser/subresource_filter_observer.h +++ b/components/subresource_filter/content/browser/subresource_filter_observer.h
@@ -6,6 +6,7 @@ #define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_OBSERVER_H_ #include "components/subresource_filter/core/common/activation_decision.h" +#include "components/subresource_filter/core/common/load_policy.h" namespace content { class NavigationHandle; @@ -27,6 +28,12 @@ content::NavigationHandle* navigation_handle, ActivationDecision activation_decision, const ActivationState& activation_state) {} + + // Called before navigation commit, either at the WillStartRequest stage or + // WillRedirectRequest stage. + virtual void OnSubframeNavigationEvaluated( + content::NavigationHandle* navigation_handle, + LoadPolicy load_policy) {} }; } // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc b/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc index f3b891c..a0d02d1 100644 --- a/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc +++ b/components/subresource_filter/content/browser/subresource_filter_observer_manager.cc
@@ -39,4 +39,11 @@ } } +void SubresourceFilterObserverManager::NotifySubframeNavigationEvaluated( + content::NavigationHandle* navigation_handle, + LoadPolicy load_policy) { + for (auto& observer : observers_) + observer.OnSubframeNavigationEvaluated(navigation_handle, load_policy); +} + } // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/subresource_filter_observer_manager.h b/components/subresource_filter/content/browser/subresource_filter_observer_manager.h index 489fb21..978b1a3b 100644 --- a/components/subresource_filter/content/browser/subresource_filter_observer_manager.h +++ b/components/subresource_filter/content/browser/subresource_filter_observer_manager.h
@@ -9,6 +9,7 @@ #include "base/observer_list.h" #include "components/subresource_filter/content/browser/subresource_filter_observer.h" #include "components/subresource_filter/core/common/activation_decision.h" +#include "components/subresource_filter/core/common/load_policy.h" #include "content/public/browser/web_contents_user_data.h" namespace content { @@ -39,6 +40,10 @@ ActivationDecision activation_decision, const ActivationState& activation_state); + void NotifySubframeNavigationEvaluated( + content::NavigationHandle* navigation_handle, + LoadPolicy load_policy); + private: base::ObserverList<SubresourceFilterObserver> observers_; DISALLOW_COPY_AND_ASSIGN(SubresourceFilterObserverManager);
diff --git a/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc b/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc new file mode 100644 index 0000000..24cf9480 --- /dev/null +++ b/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.cc
@@ -0,0 +1,53 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h" + +#include "content/public/browser/navigation_handle.h" + +namespace subresource_filter { + +TestSubresourceFilterObserver::TestSubresourceFilterObserver( + content::WebContents* web_contents) + : scoped_observer_(this) { + scoped_observer_.Add( + SubresourceFilterObserverManager::FromWebContents(web_contents)); +} + +TestSubresourceFilterObserver::~TestSubresourceFilterObserver() {} + +void TestSubresourceFilterObserver::OnSubresourceFilterGoingAway() { + scoped_observer_.RemoveAll(); +} + +void TestSubresourceFilterObserver::OnPageActivationComputed( + content::NavigationHandle* navigation_handle, + ActivationDecision activation_decision, + const ActivationState& activation_state) { + page_activations_[navigation_handle->GetURL()] = activation_decision; +} + +void TestSubresourceFilterObserver::OnSubframeNavigationEvaluated( + content::NavigationHandle* navigation_handle, + LoadPolicy load_policy) { + subframe_load_evaluations_[navigation_handle->GetURL()] = load_policy; +} + +base::Optional<ActivationDecision> +TestSubresourceFilterObserver::GetPageActivation(const GURL& url) { + auto it = page_activations_.find(url); + if (it != page_activations_.end()) + return it->second; + return base::Optional<ActivationDecision>(); +} + +base::Optional<LoadPolicy> TestSubresourceFilterObserver::GetSubframeLoadPolicy( + const GURL& url) { + auto it = subframe_load_evaluations_.find(url); + if (it != subframe_load_evaluations_.end()) + return it->second; + return base::Optional<LoadPolicy>(); +} + +} // namespace subresource_filter
diff --git a/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h b/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h new file mode 100644 index 0000000..b76f203bd --- /dev/null +++ b/components/subresource_filter/content/browser/subresource_filter_observer_test_utils.h
@@ -0,0 +1,57 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_OBSERVER_TEST_UTILS_H_ +#define COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_OBSERVER_TEST_UTILS_H_ + +#include <map> + +#include "base/macros.h" +#include "base/optional.h" +#include "base/scoped_observer.h" +#include "components/subresource_filter/content/browser/subresource_filter_observer.h" +#include "components/subresource_filter/content/browser/subresource_filter_observer_manager.h" +#include "components/subresource_filter/core/common/activation_decision.h" +#include "components/subresource_filter/core/common/load_policy.h" +#include "url/gurl.h" + +namespace content { +class WebContents; +} // namespace content + +namespace subresource_filter { + +// This class can be used to observe subresource filtering events associated +// with a particular web contents. Particular events can be expected by using +// the Get* methods. +class TestSubresourceFilterObserver : public SubresourceFilterObserver { + public: + TestSubresourceFilterObserver(content::WebContents* web_contents); + ~TestSubresourceFilterObserver() override; + + // SubresourceFilterObserver: + void OnSubresourceFilterGoingAway() override; + void OnPageActivationComputed( + content::NavigationHandle* navigation_handle, + ActivationDecision activation_decision, + const ActivationState& activation_state) override; + void OnSubframeNavigationEvaluated( + content::NavigationHandle* navigation_handle, + LoadPolicy load_policy) override; + + base::Optional<ActivationDecision> GetPageActivation(const GURL& url); + base::Optional<LoadPolicy> GetSubframeLoadPolicy(const GURL& url); + + private: + std::map<GURL, LoadPolicy> subframe_load_evaluations_; + std::map<GURL, ActivationDecision> page_activations_; + + ScopedObserver<SubresourceFilterObserverManager, SubresourceFilterObserver> + scoped_observer_; + DISALLOW_COPY_AND_ASSIGN(TestSubresourceFilterObserver); +}; + +} // namespace subresource_filter + +#endif // COMPONENTS_SUBRESOURCE_FILTER_CONTENT_BROWSER_SUBRESOURCE_FILTER_OBSERVER_TEST_UTILS_H_
diff --git a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc index de17ed65..efb514b 100644 --- a/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc +++ b/components/subresource_filter/content/renderer/web_document_subresource_filter_impl.cc
@@ -8,6 +8,7 @@ #include "base/memory/ref_counted.h" #include "components/subresource_filter/core/common/activation_state.h" +#include "components/subresource_filter/core/common/load_policy.h" #include "components/subresource_filter/core/common/memory_mapped_ruleset.h" #include "third_party/WebKit/public/platform/WebURL.h" #include "third_party/WebKit/public/platform/WebURLRequest.h"
diff --git a/components/subresource_filter/core/common/BUILD.gn b/components/subresource_filter/core/common/BUILD.gn index 61964f8d..ea52296 100644 --- a/components/subresource_filter/core/common/BUILD.gn +++ b/components/subresource_filter/core/common/BUILD.gn
@@ -25,6 +25,7 @@ "fuzzy_pattern_matching.h", "indexed_ruleset.cc", "indexed_ruleset.h", + "load_policy.h", "memory_mapped_ruleset.cc", "memory_mapped_ruleset.h", "ngram_extractor.h",
diff --git a/components/subresource_filter/core/common/document_subresource_filter.h b/components/subresource_filter/core/common/document_subresource_filter.h index 611707d..0a8ac037 100644 --- a/components/subresource_filter/core/common/document_subresource_filter.h +++ b/components/subresource_filter/core/common/document_subresource_filter.h
@@ -16,6 +16,7 @@ #include "components/subresource_filter/core/common/activation_state.h" #include "components/subresource_filter/core/common/document_load_statistics.h" #include "components/subresource_filter/core/common/indexed_ruleset.h" +#include "components/subresource_filter/core/common/load_policy.h" #include "components/subresource_filter/core/common/proto/rules.pb.h" class GURL; @@ -29,12 +30,6 @@ class FirstPartyOrigin; class MemoryMappedRuleset; -enum class LoadPolicy { - ALLOW, - DISALLOW, - WOULD_DISALLOW, -}; - // Computes whether/how subresource filtering should be activated while loading // |document_url| in a frame, based on the parent document's |activation_state|, // the |parent_document_origin|, as well as any applicable deactivation rules in
diff --git a/components/subresource_filter/core/common/load_policy.h b/components/subresource_filter/core/common/load_policy.h new file mode 100644 index 0000000..0a235a7e --- /dev/null +++ b/components/subresource_filter/core/common/load_policy.h
@@ -0,0 +1,20 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_LOAD_POLICY_H_ +#define COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_LOAD_POLICY_H_ + +namespace subresource_filter { + +// Represents the value returned by the DocumentSubresourceFilter corresponding +// to a resource load. +enum class LoadPolicy { + ALLOW, + DISALLOW, + WOULD_DISALLOW, +}; + +} // namespace subresource_filter + +#endif // COMPONENTS_SUBRESOURCE_FILTER_CORE_COMMON_LOAD_POLICY_H_
diff --git a/components/viz/client/BUILD.gn b/components/viz/client/BUILD.gn index 881aac5..1e73b925 100644 --- a/components/viz/client/BUILD.gn +++ b/components/viz/client/BUILD.gn
@@ -6,6 +6,8 @@ sources = [ "client_compositor_frame_sink.cc", "client_compositor_frame_sink.h", + "local_surface_id_provider.cc", + "local_surface_id_provider.h", ] public_deps = [
diff --git a/components/viz/client/DEPS b/components/viz/client/DEPS index 1d0b8872..86ba24d 100644 --- a/components/viz/client/DEPS +++ b/components/viz/client/DEPS
@@ -1,3 +1,4 @@ include_rules = [ "+cc", + "+ui/gfx/geometry", ]
diff --git a/components/viz/client/client_compositor_frame_sink.cc b/components/viz/client/client_compositor_frame_sink.cc index e363f8c..3fe17a6 100644 --- a/components/viz/client/client_compositor_frame_sink.cc +++ b/components/viz/client/client_compositor_frame_sink.cc
@@ -9,6 +9,7 @@ #include "cc/output/begin_frame_args.h" #include "cc/output/compositor_frame.h" #include "cc/output/compositor_frame_sink_client.h" +#include "components/viz/client/local_surface_id_provider.h" namespace viz { @@ -20,11 +21,13 @@ std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source, cc::mojom::MojoCompositorFrameSinkPtrInfo compositor_frame_sink_info, cc::mojom::MojoCompositorFrameSinkClientRequest client_request, + std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider, bool enable_surface_synchronization) : cc::CompositorFrameSink(std::move(context_provider), std::move(worker_context_provider), gpu_memory_buffer_manager, shared_bitmap_manager), + local_surface_id_provider_(std::move(local_surface_id_provider)), synthetic_begin_frame_source_(std::move(synthetic_begin_frame_source)), compositor_frame_sink_info_(std::move(compositor_frame_sink_info)), client_request_(std::move(client_request)), @@ -38,8 +41,10 @@ std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source, cc::mojom::MojoCompositorFrameSinkPtrInfo compositor_frame_sink_info, cc::mojom::MojoCompositorFrameSinkClientRequest client_request, + std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider, bool enable_surface_synchronization) : cc::CompositorFrameSink(std::move(vulkan_context_provider)), + local_surface_id_provider_(std::move(local_surface_id_provider)), synthetic_begin_frame_source_(std::move(synthetic_begin_frame_source)), compositor_frame_sink_info_(std::move(compositor_frame_sink_info)), client_request_(std::move(client_request)), @@ -94,13 +99,10 @@ DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber, frame.metadata.begin_frame_ack.sequence_number); - if (!enable_surface_synchronization_ && - (!local_surface_id_.is_valid() || ShouldAllocateNewLocalSurfaceId(frame))) - local_surface_id_ = id_allocator_.GenerateId(); - - surface_size_ = frame.render_pass_list.back()->output_rect.size(); - device_scale_factor_ = frame.metadata.device_scale_factor; - + if (!enable_surface_synchronization_) { + local_surface_id_ = + local_surface_id_provider_->GetLocalSurfaceIdForFrame(frame); + } compositor_frame_sink_->SubmitCompositorFrame(local_surface_id_, std::move(frame)); } @@ -131,13 +133,6 @@ client_->ReclaimResources(resources); } -bool ClientCompositorFrameSink::ShouldAllocateNewLocalSurfaceId( - const cc::CompositorFrame& frame) { - gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size(); - return frame_size != surface_size_ || - device_scale_factor_ != frame.metadata.device_scale_factor; -} - void ClientCompositorFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) { compositor_frame_sink_->SetNeedsBeginFrame(needs_begin_frames); }
diff --git a/components/viz/client/client_compositor_frame_sink.h b/components/viz/client/client_compositor_frame_sink.h index 008b730..236767c 100644 --- a/components/viz/client/client_compositor_frame_sink.h +++ b/components/viz/client/client_compositor_frame_sink.h
@@ -16,6 +16,8 @@ namespace viz { +class LocalSurfaceIdProvider; + class ClientCompositorFrameSink : public cc::CompositorFrameSink, public cc::mojom::MojoCompositorFrameSinkClient, @@ -30,6 +32,7 @@ synthetic_begin_frame_source, cc::mojom::MojoCompositorFrameSinkPtrInfo compositor_frame_sink_info, cc::mojom::MojoCompositorFrameSinkClientRequest client_request, + std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider, bool enable_surface_synchronization); ClientCompositorFrameSink( @@ -38,6 +41,7 @@ synthetic_begin_frame_source, cc::mojom::MojoCompositorFrameSinkPtrInfo compositor_frame_sink_info, cc::mojom::MojoCompositorFrameSinkClientRequest client_request, + std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider, bool enable_surface_synchronization); ~ClientCompositorFrameSink() override; @@ -50,9 +54,6 @@ void DidNotProduceFrame(const cc::BeginFrameAck& ack) override; private: - virtual bool ShouldAllocateNewLocalSurfaceId( - const cc::CompositorFrame& frame); - // cc::mojom::MojoCompositorFrameSinkClient implementation: void DidReceiveCompositorFrameAck( const cc::ReturnedResourceArray& resources) override; @@ -62,11 +63,8 @@ // cc::ExternalBeginFrameSourceClient implementation. void OnNeedsBeginFrames(bool needs_begin_frames) override; - gfx::Size surface_size_; - float device_scale_factor_ = 0.f; - cc::LocalSurfaceId local_surface_id_; - cc::LocalSurfaceIdAllocator id_allocator_; + std::unique_ptr<LocalSurfaceIdProvider> local_surface_id_provider_; std::unique_ptr<cc::ExternalBeginFrameSource> begin_frame_source_; std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source_; cc::mojom::MojoCompositorFrameSinkPtrInfo compositor_frame_sink_info_;
diff --git a/components/viz/client/local_surface_id_provider.cc b/components/viz/client/local_surface_id_provider.cc new file mode 100644 index 0000000..caf3ca9 --- /dev/null +++ b/components/viz/client/local_surface_id_provider.cc
@@ -0,0 +1,29 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/viz/client/local_surface_id_provider.h" +#include "cc/output/compositor_frame.h" + +namespace viz { + +LocalSurfaceIdProvider::LocalSurfaceIdProvider() = default; + +LocalSurfaceIdProvider::~LocalSurfaceIdProvider() = default; + +DefaultLocalSurfaceIdProvider::DefaultLocalSurfaceIdProvider() = default; + +const cc::LocalSurfaceId& +DefaultLocalSurfaceIdProvider::GetLocalSurfaceIdForFrame( + const cc::CompositorFrame& frame) { + gfx::Size frame_size = frame.render_pass_list.back()->output_rect.size(); + if (!local_surface_id_.is_valid() || surface_size_ != frame_size || + frame.metadata.device_scale_factor != device_scale_factor_) { + local_surface_id_ = local_surface_id_allocator_.GenerateId(); + } + surface_size_ = frame_size; + device_scale_factor_ = frame.metadata.device_scale_factor; + return local_surface_id_; +} + +} // namespace viz
diff --git a/components/viz/client/local_surface_id_provider.h b/components/viz/client/local_surface_id_provider.h new file mode 100644 index 0000000..50f4dd2e --- /dev/null +++ b/components/viz/client/local_surface_id_provider.h
@@ -0,0 +1,48 @@ +// Copyright 2017 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_VIZ_CLIENT_LOCAL_SURFACE_ID_PROVIDER_H_ +#define COMPONENTS_VIZ_CLIENT_LOCAL_SURFACE_ID_PROVIDER_H_ + +#include "cc/surfaces/local_surface_id.h" +#include "cc/surfaces/local_surface_id_allocator.h" +#include "ui/gfx/geometry/size.h" + +namespace cc { +class CompositorFrame; +} + +namespace viz { + +class LocalSurfaceIdProvider { + public: + LocalSurfaceIdProvider(); + virtual ~LocalSurfaceIdProvider(); + + virtual const cc::LocalSurfaceId& GetLocalSurfaceIdForFrame( + const cc::CompositorFrame& frame) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(LocalSurfaceIdProvider); +}; + +class DefaultLocalSurfaceIdProvider : public LocalSurfaceIdProvider { + public: + DefaultLocalSurfaceIdProvider(); + + const cc::LocalSurfaceId& GetLocalSurfaceIdForFrame( + const cc::CompositorFrame& frame) override; + + private: + cc::LocalSurfaceId local_surface_id_; + gfx::Size surface_size_; + float device_scale_factor_ = 0; + cc::LocalSurfaceIdAllocator local_surface_id_allocator_; + + DISALLOW_COPY_AND_ASSIGN(DefaultLocalSurfaceIdProvider); +}; + +} // namespace viz + +#endif // COMPONENTS_VIZ_CLIENT_LOCAL_SURFACE_ID_PROVIDER_H_
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc index 28a6209..0026338 100644 --- a/content/browser/download/download_item_impl.cc +++ b/content/browser/download/download_item_impl.cc
@@ -132,6 +132,40 @@ // The maximum number of attempts we will make to resume automatically. const int DownloadItemImpl::kMaxAutoResumeAttempts = 5; +DownloadItemImpl::RequestInfo::RequestInfo( + const std::vector<GURL>& url_chain, + const GURL& referrer_url, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url, + const std::string& suggested_filename, + const base::FilePath& forced_file_path, + ui::PageTransition transition_type, + bool has_user_gesture, + const std::string& remote_address, + base::Time start_time) + : url_chain(url_chain), + referrer_url(referrer_url), + site_url(site_url), + tab_url(tab_url), + tab_referrer_url(tab_referrer_url), + suggested_filename(suggested_filename), + forced_file_path(forced_file_path), + transition_type(transition_type), + has_user_gesture(has_user_gesture), + remote_address(remote_address), + start_time(start_time) {} + +DownloadItemImpl::RequestInfo::RequestInfo(const GURL& url) + : url_chain(std::vector<GURL>(1, url)), start_time(base::Time::Now()) {} + +DownloadItemImpl::RequestInfo::RequestInfo() = default; + +DownloadItemImpl::RequestInfo::RequestInfo( + const DownloadItemImpl::RequestInfo& other) = default; + +DownloadItemImpl::RequestInfo::~RequestInfo() = default; + // Constructor for reading from the history service. DownloadItemImpl::DownloadItemImpl( DownloadItemImplDelegate* delegate, @@ -161,14 +195,20 @@ bool transient, const std::vector<DownloadItem::ReceivedSlice>& received_slices, const net::NetLogWithSource& net_log) - : guid_(base::ToUpperASCII(guid)), + : request_info_(url_chain, + referrer_url, + site_url, + tab_url, + tab_refererr_url, + std::string(), + base::FilePath(), + ui::PAGE_TRANSITION_LINK, + false, + std::string(), + start_time), + guid_(base::ToUpperASCII(guid)), download_id_(download_id), target_path_(target_path), - url_chain_(url_chain), - referrer_url_(referrer_url), - site_url_(site_url), - tab_url_(tab_url), - tab_referrer_url_(tab_refererr_url), mime_type_(mime_type), original_mime_type_(original_mime_type), total_bytes_(total_bytes), @@ -176,7 +216,6 @@ start_tick_(base::TimeTicks()), state_(ExternalToInternalState(state)), danger_type_(danger_type), - start_time_(start_time), end_time_(end_time), delegate_(delegate), opened_(opened), @@ -203,32 +242,32 @@ uint32_t download_id, const DownloadCreateInfo& info, const net::NetLogWithSource& net_log) - : guid_(info.guid.empty() ? base::ToUpperASCII(base::GenerateGUID()) + : request_info_(info.url_chain, + info.referrer_url, + info.site_url, + info.tab_url, + info.tab_referrer_url, + base::UTF16ToUTF8(info.save_info->suggested_name), + info.save_info->file_path, + info.transition_type ? info.transition_type.value() + : ui::PAGE_TRANSITION_LINK, + info.has_user_gesture, + info.remote_address, + info.start_time), + guid_(info.guid.empty() ? base::ToUpperASCII(base::GenerateGUID()) : info.guid), download_id_(download_id), target_disposition_((info.save_info->prompt_for_save_location) ? TARGET_DISPOSITION_PROMPT : TARGET_DISPOSITION_OVERWRITE), - url_chain_(info.url_chain), - referrer_url_(info.referrer_url), - site_url_(info.site_url), - tab_url_(info.tab_url), - tab_referrer_url_(info.tab_referrer_url), - suggested_filename_(base::UTF16ToUTF8(info.save_info->suggested_name)), - forced_file_path_(info.save_info->file_path), - transition_type_(info.transition_type ? info.transition_type.value() - : ui::PAGE_TRANSITION_LINK), - has_user_gesture_(info.has_user_gesture), response_headers_(info.response_headers), content_disposition_(info.content_disposition), mime_type_(info.mime_type), original_mime_type_(info.original_mime_type), - remote_address_(info.remote_address), total_bytes_(info.total_bytes), last_reason_(info.result), start_tick_(base::TimeTicks::Now()), state_(INITIAL_INTERNAL), - start_time_(info.start_time), delegate_(delegate), is_temporary_(!info.transient && !info.save_info->file_path.empty()), transient_(info.transient), @@ -258,16 +297,15 @@ const std::string& mime_type, std::unique_ptr<DownloadRequestHandleInterface> request_handle, const net::NetLogWithSource& net_log) - : is_save_package_download_(true), + : request_info_(url), + is_save_package_download_(true), guid_(base::ToUpperASCII(base::GenerateGUID())), download_id_(download_id), target_path_(path), - url_chain_(1, url), mime_type_(mime_type), original_mime_type_(mime_type), start_tick_(base::TimeTicks::Now()), state_(IN_PROGRESS_INTERNAL), - start_time_(base::Time::Now()), delegate_(delegate), current_path_(path), net_log_(net_log), @@ -576,37 +614,39 @@ } const GURL& DownloadItemImpl::GetURL() const { - return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.back(); + return request_info_.url_chain.empty() ? GURL::EmptyGURL() + : request_info_.url_chain.back(); } const std::vector<GURL>& DownloadItemImpl::GetUrlChain() const { - return url_chain_; + return request_info_.url_chain; } const GURL& DownloadItemImpl::GetOriginalUrl() const { // Be careful about taking the front() of possibly-empty vectors! // http://crbug.com/190096 - return url_chain_.empty() ? GURL::EmptyGURL() : url_chain_.front(); + return request_info_.url_chain.empty() ? GURL::EmptyGURL() + : request_info_.url_chain.front(); } const GURL& DownloadItemImpl::GetReferrerUrl() const { - return referrer_url_; + return request_info_.referrer_url; } const GURL& DownloadItemImpl::GetSiteUrl() const { - return site_url_; + return request_info_.site_url; } const GURL& DownloadItemImpl::GetTabUrl() const { - return tab_url_; + return request_info_.tab_url; } const GURL& DownloadItemImpl::GetTabReferrerUrl() const { - return tab_referrer_url_; + return request_info_.tab_referrer_url; } std::string DownloadItemImpl::GetSuggestedFilename() const { - return suggested_filename_; + return request_info_.suggested_filename; } const scoped_refptr<const net::HttpResponseHeaders>& @@ -627,16 +667,16 @@ } std::string DownloadItemImpl::GetRemoteAddress() const { - return remote_address_; + return request_info_.remote_address; } bool DownloadItemImpl::HasUserGesture() const { - return has_user_gesture_; -}; + return request_info_.has_user_gesture; +} ui::PageTransition DownloadItemImpl::GetTransitionType() const { - return transition_type_; -}; + return request_info_.transition_type; +} const std::string& DownloadItemImpl::GetLastModifiedTime() const { return last_modified_time_; @@ -661,7 +701,7 @@ const base::FilePath& DownloadItemImpl::GetForcedFilePath() const { // TODO(asanka): Get rid of GetForcedFilePath(). We should instead just // require that clients respect GetTargetFilePath() if it is already set. - return forced_file_path_; + return request_info_.forced_file_path; } base::FilePath DownloadItemImpl::GetFileNameToReportUser() const { @@ -766,7 +806,7 @@ } base::Time DownloadItemImpl::GetStartTime() const { - return start_time_; + return request_info_.start_time; } base::Time DownloadItemImpl::GetEndTime() const { @@ -869,9 +909,9 @@ // Construct a string of the URL chain. std::string url_list("<none>"); - if (!url_chain_.empty()) { - std::vector<GURL>::const_iterator iter = url_chain_.begin(); - std::vector<GURL>::const_iterator last = url_chain_.end(); + if (!request_info_.url_chain.empty()) { + std::vector<GURL>::const_iterator iter = request_info_.url_chain.begin(); + std::vector<GURL>::const_iterator last = request_info_.url_chain.end(); url_list = (*iter).is_valid() ? (*iter).spec() : "<invalid>"; ++iter; for ( ; verbose && (iter != last); ++iter) { @@ -1029,7 +1069,7 @@ // download since the initial request, in order. std::vector<GURL>::const_iterator chain_iter = new_create_info.url_chain.begin(); - if (*chain_iter == url_chain_.back()) + if (*chain_iter == request_info_.url_chain.back()) ++chain_iter; // Record some stats. If the precondition failed (the server returned @@ -1049,8 +1089,8 @@ origin_state |= ORIGIN_STATE_ON_RESUMPTION_CONTENT_DISPOSITION_CHANGED; RecordOriginStateOnResumption(is_partial, origin_state); - url_chain_.insert( - url_chain_.end(), chain_iter, new_create_info.url_chain.end()); + request_info_.url_chain.insert(request_info_.url_chain.end(), chain_iter, + new_create_info.url_chain.end()); etag_ = new_create_info.etag; last_modified_time_ = new_create_info.last_modified; response_headers_ = new_create_info.response_headers; @@ -1203,10 +1243,10 @@ file_name = target_path_.AsUTF8Unsafe(); } else { // See if it's set programmatically. - file_name = forced_file_path_.AsUTF8Unsafe(); + file_name = GetForcedFilePath().AsUTF8Unsafe(); // Possibly has a 'download' attribute for the anchor. if (file_name.empty()) - file_name = suggested_filename_; + file_name = GetSuggestedFilename(); // From the URL file name. if (file_name.empty()) file_name = GetURL().ExtractFileName(); @@ -2078,7 +2118,7 @@ StoragePartition* storage_partition = BrowserContext::GetStoragePartitionForSite(GetBrowserContext(), - site_url_); + request_info_.site_url); // Avoid using the WebContents even if it's still around. Resumption requests // are consistently routed through the no-renderer code paths so that the
diff --git a/content/browser/download/download_item_impl.h b/content/browser/download/download_item_impl.h index 42a4ebaa..9980ad00 100644 --- a/content/browser/download/download_item_impl.h +++ b/content/browser/download/download_item_impl.h
@@ -43,6 +43,65 @@ RESUME_MODE_USER_RESTART }; + // Information about the initial request that triggers the download. Most of + // the fields are immutable after the DownloadItem is successfully created. + // However, it is possible that the url chain is changed when resuming an + // interrupted download. In that case, the download will restart from the + // beginning. + struct CONTENT_EXPORT RequestInfo { + RequestInfo(const std::vector<GURL>& url_chain, + const GURL& referrer_url, + const GURL& site_url, + const GURL& tab_url, + const GURL& tab_referrer_url, + const std::string& suggested_filename, + const base::FilePath& forced_file_path, + ui::PageTransition transition_type, + bool has_user_gesture, + const std::string& remote_address, + base::Time start_time); + RequestInfo(); + RequestInfo(const RequestInfo& other); + RequestInfo(const GURL& url); + ~RequestInfo(); + + // The chain of redirects that leading up to and including the final URL. + std::vector<GURL> url_chain; + + // The URL of the page that initiated the download. + GURL referrer_url; + + // Site URL for the site instance that initiated this download. + GURL site_url; + + // The URL of the tab that initiated the download. + GURL tab_url; + + // The URL of the referrer of the tab that initiated the download. + GURL tab_referrer_url; + + // Filename suggestion from DownloadSaveInfo. It could, among others, be the + // suggested filename in 'download' attribute of an anchor. Details: + // http://www.whatwg.org/specs/web-apps/current-work/#downloading-hyperlinks + std::string suggested_filename; + + // If non-empty, contains an externally supplied path that should be used as + // the target path. + base::FilePath forced_file_path; + + // Page transition that triggerred the download. + ui::PageTransition transition_type = ui::PAGE_TRANSITION_LINK; + + // Whether the download was triggered with a user gesture. + bool has_user_gesture = false; + + // The remote IP address where the download was fetched from. + std::string remote_address; + + // Time the download was started. + base::Time start_time; + }; + // The maximum number of attempts we will make to resume automatically. static const int kMaxAutoResumeAttempts; @@ -517,6 +576,8 @@ static bool IsValidStateTransition(DownloadInternalState from, DownloadInternalState to); + RequestInfo request_info_; + // Will be false for save package downloads retrieved from the history. // TODO(rdsmith): Replace with a generalized enum for "download source". const bool is_save_package_download_ = false; @@ -537,36 +598,6 @@ // Whether the target should be overwritten, uniquified or prompted for. TargetDisposition target_disposition_ = TARGET_DISPOSITION_OVERWRITE; - // The chain of redirects that leading up to and including the final URL. - std::vector<GURL> url_chain_; - - // The URL of the page that initiated the download. - GURL referrer_url_; - - // Site URL for the site instance that initiated this download. - GURL site_url_; - - // The URL of the tab that initiated the download. - GURL tab_url_; - - // The URL of the referrer of the tab that initiated the download. - GURL tab_referrer_url_; - - // Filename suggestion from DownloadSaveInfo. It could, among others, be the - // suggested filename in 'download' attribute of an anchor. Details: - // http://www.whatwg.org/specs/web-apps/current-work/#downloading-hyperlinks - std::string suggested_filename_; - - // If non-empty, contains an externally supplied path that should be used as - // the target path. - base::FilePath forced_file_path_; - - // Page transition that triggerred the download. - ui::PageTransition transition_type_ = ui::PAGE_TRANSITION_LINK; - - // Whether the download was triggered with a user gesture. - bool has_user_gesture_ = false; - // Information from the response. // The HTTP response headers. This contains a nullptr when the response has @@ -584,10 +615,6 @@ // which may look at the file extension and first few bytes of the file. std::string original_mime_type_; - // The remote IP address where the download was fetched from. Copied from - // DownloadCreateInfo::remote_address. - std::string remote_address_; - // Total bytes expected. int64_t total_bytes_ = 0; @@ -606,9 +633,6 @@ // The views of this item in the download shelf and download contents. base::ObserverList<Observer> observers_; - // Time the download was started. - base::Time start_time_; - // Time the download completed. base::Time end_time_;
diff --git a/content/common/feature_policy/feature_policy.cc b/content/common/feature_policy/feature_policy.cc index 76ad7698..1211672a 100644 --- a/content/common/feature_policy/feature_policy.cc +++ b/content/common/feature_policy/feature_policy.cc
@@ -170,7 +170,7 @@ } else { new_policy->inherited_policies_[feature.first] = false; } - if (!container_policy.empty()) + if (parent_policy && !container_policy.empty()) new_policy->AddContainerPolicy(container_policy, parent_policy); } return new_policy;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index 7681cd24..8f8da66f 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -347,10 +347,6 @@ const base::Feature kAndroidAutofillAccessibility{ "AndroidAutofillAccessibility", base::FEATURE_ENABLED_BY_DEFAULT}; -// FeatureList definition for the Seccomp field trial. -const base::Feature kSeccompSandboxAndroid{"SeccompSandboxAndroid", - base::FEATURE_ENABLED_BY_DEFAULT}; - // Service worker based payment apps as defined by w3c here: // https://w3c.github.io/webpayments-payment-apps-api/ const base::Feature kServiceWorkerPaymentApps{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index f426387..b2138af 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -89,7 +89,6 @@ #if defined(OS_ANDROID) CONTENT_EXPORT extern const base::Feature kAndroidAutofillAccessibility; CONTENT_EXPORT extern const base::Feature kImeThread; -CONTENT_EXPORT extern const base::Feature kSeccompSandboxAndroid; CONTENT_EXPORT extern const base::Feature kServiceWorkerPaymentApps; CONTENT_EXPORT extern const base::Feature kWebNfc; #endif // defined(OS_ANDROID)
diff --git a/content/renderer/BUILD.gn b/content/renderer/BUILD.gn index 4b534b9..66be081 100644 --- a/content/renderer/BUILD.gn +++ b/content/renderer/BUILD.gn
@@ -137,8 +137,6 @@ "gpu/render_widget_compositor.cc", "gpu/render_widget_compositor.h", "gpu/render_widget_compositor_delegate.h", - "gpu/renderer_compositor_frame_sink.cc", - "gpu/renderer_compositor_frame_sink.h", "gpu/stream_texture_host_android.cc", "gpu/stream_texture_host_android.h", "history_entry.cc",
diff --git a/content/renderer/gpu/renderer_compositor_frame_sink.cc b/content/renderer/gpu/renderer_compositor_frame_sink.cc deleted file mode 100644 index 90a0846..0000000 --- a/content/renderer/gpu/renderer_compositor_frame_sink.cc +++ /dev/null
@@ -1,110 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/gpu/renderer_compositor_frame_sink.h" - -#include <utility> - -#include "base/command_line.h" -#include "base/location.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "build/build_config.h" -#include "cc/output/compositor_frame.h" -#include "cc/output/compositor_frame_sink_client.h" -#include "cc/output/managed_memory_policy.h" -#include "content/common/view_messages.h" -#include "content/public/common/content_switches.h" -#include "content/renderer/render_thread_impl.h" -#include "gpu/command_buffer/client/context_support.h" -#include "gpu/command_buffer/client/gles2_interface.h" -#include "gpu/ipc/client/command_buffer_proxy_impl.h" -#include "ipc/ipc_sync_channel.h" -#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h" - -namespace content { - -RendererCompositorFrameSink::RendererCompositorFrameSink( - int32_t routing_id, - std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source, - scoped_refptr<cc::ContextProvider> context_provider, - scoped_refptr<cc::ContextProvider> worker_context_provider, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - cc::SharedBitmapManager* shared_bitmap_manager, - cc::mojom::MojoCompositorFrameSinkPtrInfo sink_info, - cc::mojom::MojoCompositorFrameSinkClientRequest sink_client_request) - : ClientCompositorFrameSink(std::move(context_provider), - std::move(worker_context_provider), - gpu_memory_buffer_manager, - shared_bitmap_manager, - std::move(synthetic_begin_frame_source), - std::move(sink_info), - std::move(sink_client_request), - false /* enable_surface_synchronization */), - compositor_frame_sink_filter_( - RenderThreadImpl::current()->compositor_message_filter()), - message_sender_(RenderThreadImpl::current()->sync_message_filter()), - routing_id_(routing_id) { - DCHECK(compositor_frame_sink_filter_); - DCHECK(message_sender_); -} - -RendererCompositorFrameSink::RendererCompositorFrameSink( - int32_t routing_id, - std::unique_ptr<cc::SyntheticBeginFrameSource> synthetic_begin_frame_source, - scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider, - cc::mojom::MojoCompositorFrameSinkPtrInfo sink_info, - cc::mojom::MojoCompositorFrameSinkClientRequest sink_client_request) - : ClientCompositorFrameSink(std::move(vulkan_context_provider), - std::move(synthetic_begin_frame_source), - std::move(sink_info), - std::move(sink_client_request), - false /* enable_surface_synchronization */), - compositor_frame_sink_filter_( - RenderThreadImpl::current()->compositor_message_filter()), - message_sender_(RenderThreadImpl::current()->sync_message_filter()), - routing_id_(routing_id) { - DCHECK(compositor_frame_sink_filter_); - DCHECK(message_sender_); -} - -RendererCompositorFrameSink::~RendererCompositorFrameSink() = default; - -bool RendererCompositorFrameSink::BindToClient( - cc::CompositorFrameSinkClient* client) { - if (!ClientCompositorFrameSink::BindToClient(client)) - return false; - - compositor_frame_sink_proxy_ = new RendererCompositorFrameSinkProxy(this); - compositor_frame_sink_filter_handler_ = - base::Bind(&RendererCompositorFrameSinkProxy::OnMessageReceived, - compositor_frame_sink_proxy_); - compositor_frame_sink_filter_->AddHandlerOnCompositorThread( - routing_id_, compositor_frame_sink_filter_handler_); - - return true; -} - -void RendererCompositorFrameSink::DetachFromClient() { - compositor_frame_sink_proxy_->ClearCompositorFrameSink(); - compositor_frame_sink_filter_->RemoveHandlerOnCompositorThread( - routing_id_, compositor_frame_sink_filter_handler_); - ClientCompositorFrameSink::DetachFromClient(); -} - -void RendererCompositorFrameSink::SubmitCompositorFrame( - cc::CompositorFrame frame) { - auto new_surface_properties = - RenderWidgetSurfaceProperties::FromCompositorFrame(frame); - ClientCompositorFrameSink::SubmitCompositorFrame(std::move(frame)); - current_surface_properties_ = new_surface_properties; -} - -bool RendererCompositorFrameSink::ShouldAllocateNewLocalSurfaceId( - const cc::CompositorFrame& frame) { - return current_surface_properties_ != - RenderWidgetSurfaceProperties::FromCompositorFrame(frame); -} - -} // namespace content
diff --git a/content/renderer/gpu/renderer_compositor_frame_sink.h b/content/renderer/gpu/renderer_compositor_frame_sink.h deleted file mode 100644 index 6db24f0b..0000000 --- a/content/renderer/gpu/renderer_compositor_frame_sink.h +++ /dev/null
@@ -1,112 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_RENDERER_GPU_RENDERER_COMPOSITOR_FRAME_SINK_H_ -#define CONTENT_RENDERER_GPU_RENDERER_COMPOSITOR_FRAME_SINK_H_ - -#include <stdint.h> - -#include <memory> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/threading/non_thread_safe.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "build/build_config.h" -#include "cc/input/selection.h" -#include "cc/ipc/mojo_compositor_frame_sink.mojom.h" -#include "cc/output/begin_frame_args.h" -#include "cc/output/compositor_frame_sink.h" -#include "cc/scheduler/begin_frame_source.h" -#include "cc/surfaces/local_surface_id.h" -#include "cc/surfaces/local_surface_id_allocator.h" -#include "components/viz/client/client_compositor_frame_sink.h" -#include "content/common/render_widget_surface_properties.h" -#include "content/renderer/gpu/compositor_forwarding_message_filter.h" -#include "ipc/ipc_sync_message_filter.h" -#include "mojo/public/cpp/bindings/binding.h" -#include "ui/gfx/selection_bound.h" - -namespace IPC { -class Message; -} - -namespace cc { -class CompositorFrame; -class ContextProvider; -} - -namespace content { - -// This class can be created only on the main thread, but then becomes pinned -// to a fixed thread when BindToClient is called. -class RendererCompositorFrameSink - : NON_EXPORTED_BASE(public viz::ClientCompositorFrameSink) { - public: - RendererCompositorFrameSink( - int32_t routing_id, - std::unique_ptr<cc::SyntheticBeginFrameSource> - synthetic_begin_frame_source, - scoped_refptr<cc::ContextProvider> context_provider, - scoped_refptr<cc::ContextProvider> worker_context_provider, - gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager, - cc::SharedBitmapManager* shared_bitmap_manager, - cc::mojom::MojoCompositorFrameSinkPtrInfo sink_info, - cc::mojom::MojoCompositorFrameSinkClientRequest sink_client_request); - RendererCompositorFrameSink( - int32_t routing_id, - std::unique_ptr<cc::SyntheticBeginFrameSource> - synthetic_begin_frame_source, - scoped_refptr<cc::VulkanContextProvider> vulkan_context_provider, - cc::mojom::MojoCompositorFrameSinkPtrInfo sink_info, - cc::mojom::MojoCompositorFrameSinkClientRequest sink_client_request); - ~RendererCompositorFrameSink() override; - - // Overriden from viz::ClientCompositorFrameSink. - bool BindToClient(cc::CompositorFrameSinkClient* client) override; - void DetachFromClient() override; - void SubmitCompositorFrame(cc::CompositorFrame frame) override; - bool ShouldAllocateNewLocalSurfaceId( - const cc::CompositorFrame& frame) override; - - private: - class RendererCompositorFrameSinkProxy - : public base::RefCountedThreadSafe<RendererCompositorFrameSinkProxy> { - public: - explicit RendererCompositorFrameSinkProxy( - RendererCompositorFrameSink* compositor_frame_sink) - : compositor_frame_sink_(compositor_frame_sink) {} - void ClearCompositorFrameSink() { compositor_frame_sink_ = NULL; } - void OnMessageReceived(const IPC::Message& message) { - if (compositor_frame_sink_) - compositor_frame_sink_->OnMessageReceived(message); - } - - private: - friend class base::RefCountedThreadSafe<RendererCompositorFrameSinkProxy>; - ~RendererCompositorFrameSinkProxy() {} - RendererCompositorFrameSink* compositor_frame_sink_; - - DISALLOW_COPY_AND_ASSIGN(RendererCompositorFrameSinkProxy); - }; - - void OnMessageReceived(const IPC::Message& message) {} - - scoped_refptr<CompositorForwardingMessageFilter> - compositor_frame_sink_filter_; - CompositorForwardingMessageFilter::Handler - compositor_frame_sink_filter_handler_; - scoped_refptr<RendererCompositorFrameSinkProxy> compositor_frame_sink_proxy_; - scoped_refptr<IPC::SyncMessageFilter> message_sender_; - int routing_id_; - - RenderWidgetSurfaceProperties current_surface_properties_; -}; - -} // namespace content - -#endif // CONTENT_RENDERER_GPU_RENDERER_COMPOSITOR_FRAME_SINK_H_
diff --git a/content/renderer/mus/renderer_window_tree_client.cc b/content/renderer/mus/renderer_window_tree_client.cc index 20dc7d93..59b6a8b 100644 --- a/content/renderer/mus/renderer_window_tree_client.cc +++ b/content/renderer/mus/renderer_window_tree_client.cc
@@ -10,6 +10,7 @@ #include "base/lazy_instance.h" #include "cc/base/switches.h" #include "components/viz/client/client_compositor_frame_sink.h" +#include "components/viz/client/local_surface_id_provider.h" namespace content { @@ -87,7 +88,9 @@ std::move(context_provider), nullptr /* worker_context_provider */, gpu_memory_buffer_manager, nullptr /* shared_bitmap_manager */, nullptr /* synthetic_begin_frame_source */, std::move(sink_info), - std::move(client_request), enable_surface_synchronization); + std::move(client_request), + base::MakeUnique<viz::DefaultLocalSurfaceIdProvider>(), + enable_surface_synchronization); tree_->AttachCompositorFrameSink(root_window_id_, std::move(sink_request), std::move(client)); callback.Run(std::move(frame_sink));
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc index bc63aab..fe54aff 100644 --- a/content/renderer/render_thread_impl.cc +++ b/content/renderer/render_thread_impl.cc
@@ -55,6 +55,8 @@ #include "components/discardable_memory/client/client_discardable_shared_memory_manager.h" #include "components/metrics/public/interfaces/single_sample_metrics.mojom.h" #include "components/metrics/single_sample_metrics.h" +#include "components/viz/client/client_compositor_frame_sink.h" +#include "components/viz/client/local_surface_id_provider.h" #include "content/child/appcache/appcache_dispatcher.h" #include "content/child/appcache/appcache_frontend_impl.h" #include "content/child/blob_storage/blob_message_filter.h" @@ -106,7 +108,6 @@ #include "content/renderer/gpu/compositor_external_begin_frame_source.h" #include "content/renderer/gpu/compositor_forwarding_message_filter.h" #include "content/renderer/gpu/frame_swap_message_queue.h" -#include "content/renderer/gpu/renderer_compositor_frame_sink.h" #include "content/renderer/input/input_event_filter.h" #include "content/renderer/input/input_handler_manager.h" #include "content/renderer/input/main_thread_input_event_filter.h" @@ -419,6 +420,26 @@ connector, base::Passed(&request))); } +class RendererLocalSurfaceIdProvider : public viz::LocalSurfaceIdProvider { + public: + const cc::LocalSurfaceId& GetLocalSurfaceIdForFrame( + const cc::CompositorFrame& frame) override { + auto new_surface_properties = + RenderWidgetSurfaceProperties::FromCompositorFrame(frame); + if (!local_surface_id_.is_valid() || + new_surface_properties != surface_properties_) { + local_surface_id_ = local_surface_id_allocator_.GenerateId(); + surface_properties_ = new_surface_properties; + } + return local_surface_id_; + } + + private: + cc::LocalSurfaceIdAllocator local_surface_id_allocator_; + cc::LocalSurfaceId local_surface_id_; + RenderWidgetSurfaceProperties surface_properties_; +}; + } // namespace RenderThreadImpl::HistogramCustomizer::HistogramCustomizer() { @@ -1914,10 +1935,12 @@ DCHECK(!layout_test_mode()); frame_sink_provider_->CreateForWidget(routing_id, std::move(sink_request), std::move(client)); - callback.Run(base::MakeUnique<RendererCompositorFrameSink>( - routing_id, std::move(synthetic_begin_frame_source), - std::move(vulkan_context_provider), std::move(sink_info), - std::move(client_request))); + callback.Run(base::MakeUnique<viz::ClientCompositorFrameSink>( + std::move(vulkan_context_provider), + std::move(synthetic_begin_frame_source), std::move(sink_info), + std::move(client_request), + base::MakeUnique<RendererLocalSurfaceIdProvider>(), + false /* enable_surface_synchroninzation */)); return; } } @@ -1942,10 +1965,12 @@ DCHECK(!layout_test_mode()); frame_sink_provider_->CreateForWidget(routing_id, std::move(sink_request), std::move(client)); - callback.Run(base::MakeUnique<RendererCompositorFrameSink>( - routing_id, std::move(synthetic_begin_frame_source), nullptr, nullptr, - nullptr, shared_bitmap_manager(), std::move(sink_info), - std::move(client_request))); + callback.Run(base::MakeUnique<viz::ClientCompositorFrameSink>( + nullptr, nullptr, nullptr, shared_bitmap_manager(), + std::move(synthetic_begin_frame_source), std::move(sink_info), + std::move(client_request), + base::MakeUnique<RendererLocalSurfaceIdProvider>(), + false /* enable_surface_synchroninzation */)); return; } @@ -2014,11 +2039,13 @@ #endif frame_sink_provider_->CreateForWidget(routing_id, std::move(sink_request), std::move(client)); - callback.Run(base::WrapUnique(new RendererCompositorFrameSink( - routing_id, std::move(synthetic_begin_frame_source), + callback.Run(base::MakeUnique<viz::ClientCompositorFrameSink>( std::move(context_provider), std::move(worker_context_provider), - GetGpuMemoryBufferManager(), nullptr, std::move(sink_info), - std::move(client_request)))); + GetGpuMemoryBufferManager(), nullptr, + std::move(synthetic_begin_frame_source), std::move(sink_info), + std::move(client_request), + base::MakeUnique<RendererLocalSurfaceIdProvider>(), + false /* enable_surface_synchroninzation */)); } AssociatedInterfaceRegistry*
diff --git a/content/renderer/renderer_main_platform_delegate_android.cc b/content/renderer/renderer_main_platform_delegate_android.cc index fc14746..fd6dde5 100644 --- a/content/renderer/renderer_main_platform_delegate_android.cc +++ b/content/renderer/renderer_main_platform_delegate_android.cc
@@ -7,7 +7,6 @@ #include <signal.h> #include "base/android/build_info.h" -#include "base/feature_list.h" #include "base/logging.h" #include "base/macros.h" #include "base/metrics/histogram_macros.h" @@ -16,7 +15,6 @@ #if BUILDFLAG(USE_SECCOMP_BPF) #include "content/common/sandbox_linux/android/sandbox_bpf_base_policy_android.h" -#include "content/public/common/content_features.h" #include "content/renderer/seccomp_sandbox_status_android.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #endif @@ -106,29 +104,22 @@ return true; } - // Seccomp has been detected, check if the field trial experiment should run. - if (base::FeatureList::IsEnabled(features::kSeccompSandboxAndroid)) { - status_uma.set_status(SeccompSandboxStatus::FEATURE_ENABLED); - - sig_t old_handler = signal(SIGSYS, SIG_DFL); - if (old_handler != SIG_DFL) { - // On Android O and later, the zygote applies a seccomp filter to all - // apps. It has its own SIGSYS handler that must be un-hooked so that - // the Chromium one can be used instead. If pre-O devices have a SIGSYS - // handler, then warn about that. - DLOG_IF(WARNING, info->sdk_int() < 26) - << "Un-hooking existing SIGSYS handler before starting " - << "Seccomp sandbox"; - } - - sandbox::SandboxBPF sandbox(new SandboxBPFBasePolicyAndroid()); - CHECK(sandbox.StartSandbox( - sandbox::SandboxBPF::SeccompLevel::MULTI_THREADED)); - - status_uma.set_status(SeccompSandboxStatus::ENGAGED); - } else { - status_uma.set_status(SeccompSandboxStatus::FEATURE_DISABLED); + sig_t old_handler = signal(SIGSYS, SIG_DFL); + if (old_handler != SIG_DFL) { + // On Android O and later, the zygote applies a seccomp filter to all + // apps. It has its own SIGSYS handler that must be un-hooked so that + // the Chromium one can be used instead. If pre-O devices have a SIGSYS + // handler, then warn about that. + DLOG_IF(WARNING, info->sdk_int() < 26) + << "Un-hooking existing SIGSYS handler before starting " + << "Seccomp sandbox"; } + + sandbox::SandboxBPF sandbox(new SandboxBPFBasePolicyAndroid()); + CHECK( + sandbox.StartSandbox(sandbox::SandboxBPF::SeccompLevel::MULTI_THREADED)); + + status_uma.set_status(SeccompSandboxStatus::ENGAGED); #endif return true; }
diff --git a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py index 0212732e..c9d2fe4 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance_expectations.py +++ b/content/test/gpu/gpu_tests/webgl_conformance_expectations.py
@@ -111,8 +111,6 @@ # Passthrough command decoder self.Fail('conformance/extensions/ext-sRGB.html', ['passthrough'], bug=679696) - self.Fail('conformance/extensions/get-extension.html', - ['passthrough'], bug=682745) self.Fail('conformance/extensions/webgl-draw-buffers.html', ['passthrough'], bug=1523) # angle bug ID self.Fail('conformance/glsl/misc/shaders-with-name-conflicts.html', @@ -127,8 +125,6 @@ ['passthrough'], bug=1635) # angle bug ID self.Fail('conformance/textures/misc/texture-mips.html', ['passthrough'], bug=665518) - self.Fail('conformance/extensions/webgl-compressed-texture-s3tc-srgb.html', - ['passthrough'], bug=2049) # angle bug ID self.Skip('conformance/textures/canvas/*', ['passthrough'], bug=1932) # angle bug ID self.Skip('conformance/textures/video/*',
diff --git a/docs/testing/layout_tests.md b/docs/testing/layout_tests.md index c6d57e2..02294ff 100644 --- a/docs/testing/layout_tests.md +++ b/docs/testing/layout_tests.md
@@ -153,8 +153,7 @@ | `--nocheck-sys-deps` | Don't check system dependencies; this allows faster iteration. | | `--verbose` | Produce more verbose output, including a list of tests that pass. | | `--no-pixel-tests` | Disable the pixel-to-pixel PNG comparisons and image checksums for tests that don't call `testRunner.dumpAsText()` | -| `--reset-results` | Write all generated results directly into the given directory, overwriting what's there. | -| `--new-baseline` | Write all generated results into the most specific platform directory, overwriting what's there. Equivalent to `--reset-results --add-platform-expectations` | +| `--reset-results` | Overwrite the current baselines (`-expected.{png|txt|wav}` files) with actual results, or create new baselines if there are no existing baselines. | | `--renderer-startup-dialog` | Bring up a modal dialog before running the test, useful for attaching a debugger. | | `--fully-parallel` | Run tests in parallel using as many child processes as the system has cores. | | `--driver-logging` | Print C++ logs (LOG(WARNING), etc). | @@ -431,36 +430,29 @@ *** promo To automatically re-baseline tests across all Chromium platforms, using the -buildbot results, see the -[Rebaselining keywords in TestExpectations](./layout_test_expectations.md) -and the -[Rebaselining Tool](https://trac.webkit.org/wiki/Rebaseline). +buildbot results, see [How to rebaseline](./layout_test_expectations.md#How-to-rebaseline). Alternatively, to manually run and test and rebaseline it on your workstation, read on. *** -By default, text-only tests (ones that call `testRunner.dumpAsText()`) produce -only text results. Other tests produce both new text results and new image -results (the image baseline comprises two files, `-expected.png` and - `-expected.checksum`). So you'll need either one or three `-expected.\*` files -in your new baseline, depending on whether you have a text-only test or not. If -you enable `--no-pixel-tests`, only new text results will be produced, even for -tests that do image comparisons. - ```bash cd src/third_party/WebKit -Tools/Scripts/run-webkit-tests --new-baseline foo/bar/test.html +Tools/Scripts/run-webkit-tests --reset-results foo/bar/test.html ``` -The above command will generate a new baseline for -`LayoutTests/foo/bar/test.html` and put the output files in the right place, -e.g. -`LayoutTests/platform/chromium-win/LayoutTests/foo/bar/test-expected.{txt,png,checksum}`. +If there are current expectation files for `LayoutTests/foo/bar/test.html`, +the above command will overwrite the current baselines at their original +locations with the actual results. The current baseline means the `-expected.*` +file used to compare the actual result when the test is run locally, i.e. the +first file found in the [baseline search path] +(https://cs.chromium.org/search/?q=port/base.py+baseline_search_path). + +If there are no current baselines, the above command will create new baselines +in the platform-independent directory, e.g. +`LayoutTests/foo/bar/test-expected.{txt,png}`. When you rebaseline a test, make sure your commit description explains why the -test is being re-baselined. If this is a special case (i.e., something we've -decided to be different with upstream), please put a README file next to the new -expected output explaining the difference. +test is being re-baselined. ## web-platform-tests
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 29ee8e9..d2fe695 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc
@@ -1410,22 +1410,23 @@ // formats as GL_OES_texture_float(i.e.LUMINANCE_ALPHA,LUMINANCE and Alpha) if (extensions.Contains("GL_OES_texture_float")) { enable_texture_float = true; - if (extensions.Contains("GL_OES_texture_float_linear")) { - enable_texture_float_linear = true; - } - if (enable_ext_color_buffer_float) { may_enable_chromium_color_buffer_float = true; } } + if (extensions.Contains("GL_OES_texture_float_linear")) { + enable_texture_float_linear = true; + } + // TODO(dshwang): GLES3 supports half float by default but GL_HALF_FLOAT_OES // isn't equal to GL_HALF_FLOAT. if (extensions.Contains("GL_OES_texture_half_float")) { enable_texture_half_float = true; - if (extensions.Contains("GL_OES_texture_half_float_linear")) { - enable_texture_half_float_linear = true; - } + } + + if (extensions.Contains("GL_OES_texture_half_float_linear")) { + enable_texture_half_float_linear = true; } } @@ -1433,22 +1434,24 @@ validators_.pixel_type.AddValue(GL_FLOAT); validators_.read_pixel_type.AddValue(GL_FLOAT); AddExtensionString("GL_OES_texture_float"); - if (enable_texture_float_linear) { - oes_texture_float_linear_available_ = true; - if (!disallowed_features_.oes_texture_float_linear) - EnableOESTextureFloatLinear(); - } + } + + if (enable_texture_float_linear) { + oes_texture_float_linear_available_ = true; + if (!disallowed_features_.oes_texture_float_linear) + EnableOESTextureFloatLinear(); } if (enable_texture_half_float) { validators_.pixel_type.AddValue(GL_HALF_FLOAT_OES); validators_.read_pixel_type.AddValue(GL_HALF_FLOAT_OES); AddExtensionString("GL_OES_texture_half_float"); - if (enable_texture_half_float_linear) { - oes_texture_half_float_linear_available_ = true; - if (!disallowed_features_.oes_texture_half_float_linear) - EnableOESTextureHalfFloatLinear(); - } + } + + if (enable_texture_half_float_linear) { + oes_texture_half_float_linear_available_ = true; + if (!disallowed_features_.oes_texture_half_float_linear) + EnableOESTextureHalfFloatLinear(); } bool had_native_chromium_color_buffer_float_ext = false;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc index a3bf1c2..d9adaf81 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_passthrough.cc
@@ -170,11 +170,10 @@ } // Each context initializes its own feature info because some extensions may - // be enabled dynamically - DisallowedFeatures adjusted_disallowed_features = - AdjustDisallowedFeatures(attrib_helper.context_type, disallowed_features); + // be enabled dynamically. Don't disallow any features, leave it up to ANGLE + // to dynamically enable extensions. if (!feature_info_->Initialize(attrib_helper.context_type, - adjusted_disallowed_features)) { + DisallowedFeatures())) { Destroy(true); return false; }
diff --git a/media/gpu/dxva_video_decode_accelerator_win.cc b/media/gpu/dxva_video_decode_accelerator_win.cc index c1f525db..c2c4629 100644 --- a/media/gpu/dxva_video_decode_accelerator_win.cc +++ b/media/gpu/dxva_video_decode_accelerator_win.cc
@@ -1235,13 +1235,11 @@ (supported_profile <= VP9PROFILE_MAX)) { continue; } - std::pair<int, int> min_resolution = GetMinResolution(supported_profile); - std::pair<int, int> max_resolution = GetMaxResolution(supported_profile); SupportedProfile profile; profile.profile = supported_profile; - profile.min_resolution.SetSize(min_resolution.first, min_resolution.second); - profile.max_resolution.SetSize(max_resolution.first, max_resolution.second); + profile.min_resolution = GetMinResolution(supported_profile); + profile.max_resolution = GetMaxResolution(supported_profile); profiles.push_back(profile); } return profiles; @@ -1264,95 +1262,74 @@ } // static -std::pair<int, int> DXVAVideoDecodeAccelerator::GetMinResolution( +gfx::Size DXVAVideoDecodeAccelerator::GetMinResolution( VideoCodecProfile profile) { TRACE_EVENT0("gpu,startup", "DXVAVideoDecodeAccelerator::GetMinResolution"); - std::pair<int, int> min_resolution; + + // TODO(dalecurtis): These values are too low. We should only be using + // hardware decode for videos above ~360p, see http://crbug.com/684792. + if (profile >= H264PROFILE_BASELINE && profile <= H264PROFILE_HIGH) { // Windows Media Foundation H.264 decoding does not support decoding videos // with any dimension smaller than 48 pixels: // http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815 - min_resolution = std::make_pair(48, 48); - } else { - // TODO(ananta) - // Detect this properly for VP8/VP9 profiles. - min_resolution = std::make_pair(16, 16); + return gfx::Size(48, 48); } - return min_resolution; + + // TODO(dalecurtis): Detect this properly for VP8/VP9 profiles. + return gfx::Size(16, 16); } // static -std::pair<int, int> DXVAVideoDecodeAccelerator::GetMaxResolution( - const VideoCodecProfile profile) { +gfx::Size DXVAVideoDecodeAccelerator::GetMaxResolution( + VideoCodecProfile profile) { TRACE_EVENT0("gpu,startup", "DXVAVideoDecodeAccelerator::GetMaxResolution"); - std::pair<int, int> max_resolution; + + // Computes and caches the maximum resolution since it's expensive to + // determine and this function is called for every profile in + // kSupportedProfiles. + if (profile >= H264PROFILE_BASELINE && profile <= H264PROFILE_HIGH) { - max_resolution = GetMaxH264Resolution(); - } else { - // TODO(ananta) - // Detect this properly for VP8/VP9 profiles. - max_resolution = std::make_pair(4096, 2160); + const gfx::Size kDefaultMax = gfx::Size(1920, 1088); + + // On Windows 7 the maximum resolution supported by media foundation is + // 1920 x 1088. We use 1088 to account for 16x16 macroblocks. + if (base::win::GetVersion() == base::win::VERSION_WIN7) + return kDefaultMax; + + static const gfx::Size kCachedH264Resolution = GetMaxResolutionForGUIDs( + kDefaultMax, {DXVA2_ModeH264_E, DXVA2_Intel_ModeH264_E}, + {gfx::Size(2560, 1440), gfx::Size(3840, 2160), gfx::Size(4096, 2160), + gfx::Size(4096, 2304), gfx::Size(7680, 4320)}); + return kCachedH264Resolution; } - return max_resolution; + + // Despite the name this is the GUID for VP8/VP9. + static const gfx::Size kCachedVPXResolution = GetMaxResolutionForGUIDs( + gfx::Size(4096, 2160), {D3D11_DECODER_PROFILE_VP9_VLD_PROFILE0}, + {gfx::Size(4096, 2304), gfx::Size(7680, 4320)}); + return kCachedVPXResolution; } -std::pair<int, int> DXVAVideoDecodeAccelerator::GetMaxH264Resolution() { +gfx::Size DXVAVideoDecodeAccelerator::GetMaxResolutionForGUIDs( + const gfx::Size& default_max, + const std::vector<GUID>& valid_guids, + const std::vector<gfx::Size>& resolutions_to_test) { TRACE_EVENT0("gpu,startup", - "DXVAVideoDecodeAccelerator::GetMaxH264Resolution"); - // The H.264 resolution detection operation is expensive. This static flag - // allows us to run the detection once. - static bool resolution_detected = false; - // Use 1088 to account for 16x16 macroblocks. - static std::pair<int, int> max_resolution = std::make_pair(1920, 1088); - if (resolution_detected) - return max_resolution; - - resolution_detected = true; - - // On Windows 7 the maximum resolution supported by media foundation is - // 1920 x 1088. - if (base::win::GetVersion() == base::win::VERSION_WIN7) - return max_resolution; + "DXVAVideoDecodeAccelerator::GetMaxResolutionForGUIDs"); + gfx::Size max_resolution = default_max; // To detect if a driver supports the desired resolutions, we try and create // a DXVA decoder instance for that resolution and profile. If that succeeds // we assume that the driver supports H/W H.264 decoding for that resolution. HRESULT hr = E_FAIL; base::win::ScopedComPtr<ID3D11Device> device; - { TRACE_EVENT0("gpu,startup", - "GetMaxH264Resolution. QueryDeviceObjectFromANGLE"); + "GetMaxResolutionForGUIDs. QueryDeviceObjectFromANGLE"); device = gl::QueryD3D11DeviceObjectFromANGLE(); - if (!device.Get()) - return max_resolution; - } - - base::win::ScopedComPtr<ID3D11VideoDevice> video_device; - hr = device.CopyTo(IID_PPV_ARGS(&video_device)); - if (FAILED(hr)) - return max_resolution; - - GUID decoder_guid = {}; - - { - TRACE_EVENT0("gpu,startup", - "GetMaxH264Resolution. H.264 guid search begin"); - // Enumerate supported video profiles and look for the H264 profile. - bool found = false; - UINT profile_count = video_device->GetVideoDecoderProfileCount(); - for (UINT profile_idx = 0; profile_idx < profile_count; profile_idx++) { - GUID profile_id = {}; - hr = video_device->GetVideoDecoderProfile(profile_idx, &profile_id); - if (SUCCEEDED(hr) && (profile_id == DXVA2_ModeH264_E || - profile_id == DXVA2_Intel_ModeH264_E)) { - decoder_guid = profile_id; - found = true; - break; - } - } - if (!found) + if (!device) return max_resolution; } @@ -1361,25 +1338,38 @@ if (IsLegacyGPU(device.Get())) return max_resolution; - // We look for the following resolutions in the driver. - // TODO(ananta) - // Look into whether this list needs to be expanded. - static std::pair<int, int> resolution_array[] = { - // Use 1088 to account for 16x16 macroblocks. - std::make_pair(1920, 1088), std::make_pair(2560, 1440), - std::make_pair(3840, 2160), std::make_pair(4096, 2160), - std::make_pair(4096, 2304), - }; + base::win::ScopedComPtr<ID3D11VideoDevice> video_device; + hr = device.CopyTo(IID_PPV_ARGS(&video_device)); + if (FAILED(hr)) + return max_resolution; + + GUID decoder_guid = GUID_NULL; + { + TRACE_EVENT0("gpu,startup", "GetMaxResolutionForGUIDs. GUID search begin"); + // Enumerate supported video profiles and look for the H264 profile. + UINT profile_count = video_device->GetVideoDecoderProfileCount(); + for (UINT profile_idx = 0; profile_idx < profile_count; profile_idx++) { + GUID profile_id = {}; + hr = video_device->GetVideoDecoderProfile(profile_idx, &profile_id); + if (SUCCEEDED(hr) && (std::find(valid_guids.begin(), valid_guids.end(), + profile_id) != valid_guids.end())) { + decoder_guid = profile_id; + break; + } + } + if (decoder_guid == GUID_NULL) + return max_resolution; + } { TRACE_EVENT0("gpu,startup", - "GetMaxH264Resolution. Resolution search begin"); + "GetMaxResolutionForGUIDs. Resolution search begin"); - for (size_t res_idx = 0; res_idx < arraysize(resolution_array); res_idx++) { + for (auto& res : resolutions_to_test) { D3D11_VIDEO_DECODER_DESC desc = {}; desc.Guid = decoder_guid; - desc.SampleWidth = resolution_array[res_idx].first; - desc.SampleHeight = resolution_array[res_idx].second; + desc.SampleWidth = res.width(); + desc.SampleHeight = res.height(); desc.OutputFormat = DXGI_FORMAT_NV12; UINT config_count = 0; hr = video_device->GetVideoDecoderConfigCount(&desc, &config_count); @@ -1394,12 +1384,13 @@ base::win::ScopedComPtr<ID3D11VideoDecoder> video_decoder; hr = video_device->CreateVideoDecoder(&desc, &config, video_decoder.GetAddressOf()); - if (!video_decoder.Get()) + if (!video_decoder) return max_resolution; - max_resolution = resolution_array[res_idx]; + max_resolution = res; } } + return max_resolution; }
diff --git a/media/gpu/dxva_video_decode_accelerator_win.h b/media/gpu/dxva_video_decode_accelerator_win.h index dc02f98..0d31de58b 100644 --- a/media/gpu/dxva_video_decode_accelerator_win.h +++ b/media/gpu/dxva_video_decode_accelerator_win.h
@@ -169,13 +169,20 @@ }; // Returns the minimum resolution for the |profile| passed in. - static std::pair<int, int> GetMinResolution(const VideoCodecProfile profile); + static gfx::Size GetMinResolution(VideoCodecProfile profile); // Returns the maximum resolution for the |profile| passed in. - static std::pair<int, int> GetMaxResolution(const VideoCodecProfile profile); + static gfx::Size GetMaxResolution(VideoCodecProfile profile); - // Returns the maximum resolution for H264 video. - static std::pair<int, int> GetMaxH264Resolution(); + // Returns the maximum resolution for by attempting to create a decoder for + // each of the resolutions in |resolutions_to_test| for the first decoder + // matching a GUID from |valid_guids|. |resolutions_to_test| should be ordered + // from smallest to largest resolution. |default_max_resolution| will be + // returned if any errors occur during the process. + static gfx::Size GetMaxResolutionForGUIDs( + const gfx::Size& default_max_resolution, + const std::vector<GUID>& valid_guids, + const std::vector<gfx::Size>& resolutions_to_test); // Certain AMD GPU drivers like R600, R700, Evergreen and Cayman and // some second generation Intel GPU drivers crash if we create a video
diff --git a/remoting/ios/app/client_connection_view_controller.h b/remoting/ios/app/client_connection_view_controller.h index cb5638b..efc5b56 100644 --- a/remoting/ios/app/client_connection_view_controller.h +++ b/remoting/ios/app/client_connection_view_controller.h
@@ -7,6 +7,8 @@ #import <UIKit/UIKit.h> +@class HostInfo; + // This enumerated the differnt modes this Client Connection View can be in. typedef NS_ENUM(NSInteger, ClientConnectionViewState) { ClientViewConnecting, @@ -15,18 +17,6 @@ ClientViewClosed, }; -// The host connection view controller delegate provides feedback for state -// changes on Host Connection that the calling view should respond to. -@protocol ClientConnectionViewControllerDelegate<NSObject> - -// Notifies the delegate the client is connected to the host. -- (void)clientConnected; - -// Gets the current host name the client is attempting to connect to. -- (NSString*)getConnectingHostName; - -@end - // This is the view that shows the user feedback while the client connection is // being established. If requested the view can also display the pin entry view. // State communication for this view is handled by NSNotifications, it listens @@ -35,13 +25,11 @@ // work the same way if state is set directly. @interface ClientConnectionViewController : UIViewController +- (instancetype)initWithHostInfo:(HostInfo*)hostInfo; + // Setting state will change the view @property(nonatomic, assign) ClientConnectionViewState state; -// This delegate is used to ask for Host Name and to notify when the connection -// has been established. -@property(weak, nonatomic) id<ClientConnectionViewControllerDelegate> delegate; - @end #endif // REMOTING_IOS_APP_CLIENT_CONNECTION_VIEW_CONTROLLER_H_
diff --git a/remoting/ios/app/client_connection_view_controller.mm b/remoting/ios/app/client_connection_view_controller.mm index 395f3c60..31ad6d8 100644 --- a/remoting/ios/app/client_connection_view_controller.mm +++ b/remoting/ios/app/client_connection_view_controller.mm
@@ -8,11 +8,16 @@ #import "remoting/ios/app/client_connection_view_controller.h" +#import "base/mac/bind_objc_block.h" #import "ios/third_party/material_components_ios/src/components/ActivityIndicator/src/MDCActivityIndicator.h" #import "ios/third_party/material_components_ios/src/components/Buttons/src/MaterialButtons.h" #import "ios/third_party/material_components_ios/src/components/NavigationBar/src/MaterialNavigationBar.h" +#import "remoting/ios/app/host_view_controller.h" #import "remoting/ios/app/pin_entry_view.h" #import "remoting/ios/domain/client_session_details.h" +#import "remoting/ios/domain/host_info.h" +#import "remoting/ios/facade/remoting_authentication.h" +#import "remoting/ios/facade/remoting_service.h" #import "remoting/ios/session/remoting_client.h" #include "base/strings/sys_string_conversions.h" @@ -40,17 +45,32 @@ MDCNavigationBar* _navBar; PinEntryView* _pinEntryView; NSString* _remoteHostName; + RemotingClient* _client; } @end @implementation ClientConnectionViewController @synthesize state = _state; -@synthesize delegate = _delegate; -- (id)init { +- (instancetype)initWithHostInfo:(HostInfo*)hostInfo { self = [super init]; if (self) { + _client = [[RemotingClient alloc] init]; + + __weak RemotingClient* weakClient = _client; + [[RemotingService SharedInstance].authentication + callbackWithAccessToken:base::BindBlockArc(^( + remoting::OAuthTokenGetter::Status status, + const std::string& user_email, + const std::string& access_token) { + [weakClient connectToHost:hostInfo + username:base::SysUTF8ToNSString(user_email) + accessToken:base::SysUTF8ToNSString(access_token)]; + })]; + + _remoteHostName = hostInfo.hostName; + // TODO(yuweih): This logic may be reused by other views. UIButton* cancelButton = [UIButton buttonWithType:UIButtonTypeSystem]; [cancelButton setTitle:@"CANCEL" forState:UIControlStateNormal]; @@ -82,8 +102,6 @@ constraintEqualToAnchor:[self.view trailingAnchor]], [[_navBar heightAnchor] constraintEqualToConstant:kBarHeight], ]]; - - _remoteHostName = @""; } return self; } @@ -187,6 +205,10 @@ [[NSNotificationCenter defaultCenter] removeObserver:self]; } +- (BOOL)prefersStatusBarHidden { + return YES; +} + #pragma mark - Keyboard - (void)keyboardWillShow:(NSNotification*)notification { @@ -240,15 +262,6 @@ } } -- (void)setDelegate:(id<ClientConnectionViewControllerDelegate>)delegate { - _delegate = delegate; - if (_delegate) { - _remoteHostName = [_delegate getConnectingHostName]; - // To get the view to use the new remote host name. - [self setState:_state]; - } -} - #pragma mark - Private - (void)showConnectingState { @@ -282,9 +295,19 @@ _activityIndicator.cycleColors = @[ [UIColor greenColor] ]; [_activityIndicator startAnimating]; _activityIndicator.progress = 1.0; - [self dismissViewControllerAnimated:YES + + HostViewController* hostViewController = + [[HostViewController alloc] initWithClient:_client]; + _client = nil; + + __weak UIViewController* parentController = self.presentingViewController; + + [self dismissViewControllerAnimated:NO completion:^{ - [_delegate clientConnected]; + [parentController + presentViewController:hostViewController + animated:NO + completion:nil]; }]; } @@ -299,12 +322,12 @@ } - (void)didTapCancel:(id)sender { - NSLog(@"%@ was tapped.", NSStringFromClass([sender class])); - // TODO(nicholss): Need to cancel the pending connection. + _client = nil; [self dismissViewControllerAnimated:YES completion:nil]; } - (void)hostSessionStatusChanged:(NSNotification*)notification { + NSLog(@"hostSessionStatusChanged: %@", [notification userInfo]); ClientConnectionViewState state; ClientSessionDetails* sessionDetails = [[notification userInfo] objectForKey:kSessionDetails];
diff --git a/remoting/ios/app/host_collection_view_controller.mm b/remoting/ios/app/host_collection_view_controller.mm index 3d415c8..0fabb03 100644 --- a/remoting/ios/app/host_collection_view_controller.mm +++ b/remoting/ios/app/host_collection_view_controller.mm
@@ -17,15 +17,6 @@ @"remotingHostCollectionViewControllerItem"; static CGFloat kHostCollectionViewControllerCellHeight = 70.f; -static CGFloat kHostCollectionViewControllerDefaultHeaderHeight = 100.f; -static CGFloat kHostCollectionViewControllerSmallHeaderHeight = 60.f; -static UIColor* kBackgroundColor = - [UIColor colorWithRed:0.f green:0.67f blue:0.55f alpha:1.f]; - -@interface HostCollectionViewController () { - MDCInkTouchController* _inkTouchController; -} -@end @implementation HostCollectionViewController @@ -36,7 +27,7 @@ - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout*)layout { self = [super initWithCollectionViewLayout:layout]; if (self) { - self.collectionView.backgroundColor = [UIColor whiteColor]; + self.collectionView.backgroundColor = [UIColor clearColor]; [self.collectionView registerClass:[HostCollectionViewCell class] forCellWithReuseIdentifier:NSStringFromClass( [HostCollectionViewCell class])]; @@ -48,7 +39,7 @@ - (void)viewDidLoad { [super viewDidLoad]; - self.styler.cellStyle = MDCCollectionViewCellStyleCard; + self.styler.cellStyle = MDCCollectionViewCellStyleGrouped; self.styler.cellLayoutType = MDCCollectionViewCellLayoutTypeList; } @@ -111,32 +102,14 @@ #pragma mark - Private -- (UIView*)hostsHeaderView { - CGRect headerFrame = - _flexHeaderContainerViewController.headerViewController.headerView.bounds; - UIView* hostsHeaderView = [[UIView alloc] initWithFrame:headerFrame]; - hostsHeaderView.backgroundColor = kBackgroundColor; - hostsHeaderView.layer.masksToBounds = YES; - hostsHeaderView.autoresizingMask = - (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight); - - _inkTouchController = - [[MDCInkTouchController alloc] initWithView:hostsHeaderView]; - [_inkTouchController addInkView]; - - return hostsHeaderView; -} - -- (void)setflexHeaderContainerViewController: +- (void)setFlexHeaderContainerViewController: (MDCFlexibleHeaderContainerViewController*) flexHeaderContainerViewController { _flexHeaderContainerViewController = flexHeaderContainerViewController; MDCFlexibleHeaderView* headerView = _flexHeaderContainerViewController.headerViewController.headerView; headerView.trackingScrollView = self.collectionView; - headerView.maximumHeight = kHostCollectionViewControllerDefaultHeaderHeight; - headerView.minimumHeight = kHostCollectionViewControllerSmallHeaderHeight; - [headerView addSubview:[self hostsHeaderView]]; + headerView.backgroundColor = [UIColor clearColor]; // Use a custom shadow under the flexible header. MDCShadowLayer* shadowLayer = [MDCShadowLayer layer];
diff --git a/remoting/ios/app/remoting_view_controller.mm b/remoting/ios/app/remoting_view_controller.mm index 443311a..73da201 100644 --- a/remoting/ios/app/remoting_view_controller.mm +++ b/remoting/ios/app/remoting_view_controller.mm
@@ -20,7 +20,6 @@ #import "remoting/ios/domain/client_session_details.h" #import "remoting/ios/facade/remoting_authentication.h" #import "remoting/ios/facade/remoting_service.h" -#import "remoting/ios/session/remoting_client.h" #include "base/strings/sys_string_conversions.h" #include "remoting/base/oauth_token_getter.h" @@ -28,8 +27,10 @@ static CGFloat kHostInset = 5.f; +static UIColor* kChromotingBlueBackground = + [UIColor colorWithRed:0.11f green:0.23f blue:0.66f alpha:1.f]; + @interface RemotingViewController ()<HostCollectionViewControllerDelegate, - ClientConnectionViewControllerDelegate, UIViewControllerAnimatedTransitioning, UIViewControllerTransitioningDelegate> { bool _isAuthenticated; @@ -37,7 +38,6 @@ MDCAppBar* _appBar; HostCollectionViewController* _collectionViewController; RemotingService* _remotingService; - RemotingClient* _client; } @end @@ -69,7 +69,7 @@ [self addChildViewController:_appBar.headerViewController]; _appBar.headerViewController.headerView.backgroundColor = - [UIColor clearColor]; + kChromotingBlueBackground; _appBar.navigationBar.tintColor = [UIColor whiteColor]; UIBarButtonItem* menuButton = @@ -85,12 +85,6 @@ target:self action:@selector(didSelectRefresh)]; self.navigationItem.rightBarButtonItem = refreshButton; - - [[NSNotificationCenter defaultCenter] - addObserver:self - selector:@selector(hostSessionStatusChanged:) - name:kHostSessionStatusChanged - object:nil]; } return self; } @@ -99,6 +93,20 @@ - (void)viewDidLoad { [super viewDidLoad]; + + UIImage* image = [UIImage imageNamed:@"Background"]; + UIImageView* imageView = [[UIImageView alloc] initWithImage:image]; + [self.view addSubview:imageView]; + [self.view sendSubviewToBack:imageView]; + + imageView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [[imageView widthAnchor] + constraintGreaterThanOrEqualToAnchor:[self.view widthAnchor]], + [[imageView heightAnchor] + constraintGreaterThanOrEqualToAnchor:[self.view heightAnchor]], + ]]; + [_appBar addSubviewsToParent]; [[NSNotificationCenter defaultCenter] @@ -135,18 +143,8 @@ } } -- (void)viewDidLayoutSubviews { - [super viewDidLayoutSubviews]; - - // Adjust the collection view's position and size so that it doesn't get - // overlayed by the navigation bar. - CGFloat collectionOffsetY = - _appBar.headerViewController.headerView.frame.size.height; - CGFloat collectionHeight = self.view.bounds.size.height - collectionOffsetY; - CGRect oldFrame = _collectionViewController.collectionView.frame; - _collectionViewController.collectionView.frame = - CGRectMake(oldFrame.origin.x, collectionOffsetY, oldFrame.size.width, - collectionHeight); +- (UIStatusBarStyle)preferredStatusBarStyle { + return UIStatusBarStyleLightContent; } #pragma mark - Remoting Service Notifications @@ -183,22 +181,6 @@ [_collectionViewController.collectionView reloadData]; } -#pragma mark - ClientConnectionViewControllerDelegate - -- (void)clientConnected { - HostViewController* hostViewController = - [[HostViewController alloc] initWithClient:_client]; - _client = nil; - [self presentViewController:hostViewController animated:YES completion:nil]; -} - -- (NSString*)getConnectingHostName { - if (_client) { - return _client.hostInfo.hostName; - } - return nil; -} - #pragma mark - HostCollectionViewControllerDelegate - (void)didSelectCell:(HostCollectionViewCell*)cell @@ -210,23 +192,8 @@ return; } - _client = [[RemotingClient alloc] init]; - - [_remotingService.authentication - callbackWithAccessToken:base::BindBlockArc(^( - remoting::OAuthTokenGetter::Status status, - const std::string& user_email, - const std::string& access_token) { - // TODO(nicholss): Check status. - HostInfo* hostInfo = cell.hostInfo; - [_client connectToHost:hostInfo - username:base::SysUTF8ToNSString(user_email) - accessToken:base::SysUTF8ToNSString(access_token)]; - })]; - ClientConnectionViewController* clientConnectionViewController = - [[ClientConnectionViewController alloc] init]; - clientConnectionViewController.delegate = self; + [[ClientConnectionViewController alloc] initWithHostInfo:cell.hostInfo]; [self presentViewController:clientConnectionViewController animated:YES completion:nil]; @@ -269,10 +236,6 @@ #pragma mark - Private -- (void)hostSessionStatusChanged:(NSNotification*)notification { - NSLog(@"hostSessionStatusChanged: %@", [notification userInfo]); -} - - (void)closeViewController { [self dismissViewControllerAnimated:true completion:nil]; }
diff --git a/remoting/ios/app/resources/Assets.xcassets/Background.imageset/Contents.json b/remoting/ios/app/resources/Assets.xcassets/Background.imageset/Contents.json new file mode 100644 index 0000000..486721f --- /dev/null +++ b/remoting/ios/app/resources/Assets.xcassets/Background.imageset/Contents.json
@@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "bkg1.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "bkg1_2x.jpg", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file
diff --git a/remoting/ios/app/resources/Assets.xcassets/Background.imageset/bkg1.jpg b/remoting/ios/app/resources/Assets.xcassets/Background.imageset/bkg1.jpg new file mode 100644 index 0000000..63b8d14 --- /dev/null +++ b/remoting/ios/app/resources/Assets.xcassets/Background.imageset/bkg1.jpg Binary files differ
diff --git a/remoting/ios/app/resources/Assets.xcassets/Background.imageset/bkg1_2x.jpg b/remoting/ios/app/resources/Assets.xcassets/Background.imageset/bkg1_2x.jpg new file mode 100644 index 0000000..354fcac --- /dev/null +++ b/remoting/ios/app/resources/Assets.xcassets/Background.imageset/bkg1_2x.jpg Binary files differ
diff --git a/services/ui/ws/BUILD.gn b/services/ui/ws/BUILD.gn index 5b2cca7..0e4de01 100644 --- a/services/ui/ws/BUILD.gn +++ b/services/ui/ws/BUILD.gn
@@ -249,7 +249,6 @@ "transient_windows_unittest.cc", "user_activity_monitor_unittest.cc", "user_display_manager_unittest.cc", - "window_coordinate_conversions_unittest.cc", "window_finder_unittest.cc", "window_manager_state_unittest.cc", "window_tree_client_unittest.cc",
diff --git a/services/ui/ws/event_dispatcher.cc b/services/ui/ws/event_dispatcher.cc index 5634221..751e562 100644 --- a/services/ui/ws/event_dispatcher.cc +++ b/services/ui/ws/event_dispatcher.cc
@@ -525,9 +525,7 @@ void EventDispatcher::DispatchToClient(ServerWindow* window, ClientSpecificId client_id, const ui::LocatedEvent& event) { - gfx::Point location(event.location()); - gfx::Transform transform(GetTransformToWindow(window)); - transform.TransformPoint(&location); + gfx::Point location = ConvertPointFromRoot(window, event.location()); std::unique_ptr<ui::Event> clone = ui::Event::Clone(event); clone->AsLocatedEvent()->set_location(location); // TODO(jonross): add post-target accelerator support once accelerators
diff --git a/services/ui/ws/event_dispatcher_unittest.cc b/services/ui/ws/event_dispatcher_unittest.cc index be3217a..7888872 100644 --- a/services/ui/ws/event_dispatcher_unittest.cc +++ b/services/ui/ws/event_dispatcher_unittest.cc
@@ -1619,7 +1619,7 @@ std::unique_ptr<DispatchedEventDetails> details = test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); ASSERT_TRUE(details) << " details is nullptr " << i; - EXPECT_EQ(kTouchData[i].expected_target, details->window); + EXPECT_EQ(kTouchData[i].expected_target, details->window) << i; // Release touch. event_dispatcher()->ProcessEvent( @@ -1882,6 +1882,36 @@ EXPECT_EQ(nullptr, event_dispatcher()->mouse_cursor_source_window()); } +TEST_F(EventDispatcherTest, LocationHonorsTransform) { + std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3)); + + gfx::Transform transform; + transform.Scale(SkIntToMScalar(2), SkIntToMScalar(2)); + child->SetTransform(transform); + + root_window()->SetBounds(gfx::Rect(0, 0, 100, 100)); + child->SetBounds(gfx::Rect(10, 10, 20, 20)); + + // Send event that is over child. + const ui::PointerEvent ui_event(ui::MouseEvent( + ui::ET_MOUSE_PRESSED, gfx::Point(20, 25), gfx::Point(20, 25), + base::TimeTicks(), ui::EF_LEFT_MOUSE_BUTTON, ui::EF_LEFT_MOUSE_BUTTON)); + event_dispatcher()->ProcessEvent(ui_event, 0, + EventDispatcher::AcceleratorMatchPhase::ANY); + + std::unique_ptr<DispatchedEventDetails> details = + test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails(); + ASSERT_TRUE(details); + ASSERT_EQ(child.get(), details->window); + + ASSERT_TRUE(details->event); + ASSERT_TRUE(details->event->IsPointerEvent()); + + ui::PointerEvent* dispatched_event = details->event->AsPointerEvent(); + EXPECT_EQ(gfx::Point(20, 25), dispatched_event->root_location()); + EXPECT_EQ(gfx::Point(5, 7), dispatched_event->location()); +} + } // namespace test } // namespace ws } // namespace ui
diff --git a/services/ui/ws/window_coordinate_conversions.cc b/services/ui/ws/window_coordinate_conversions.cc index 11430a8a..e6bab98f4 100644 --- a/services/ui/ws/window_coordinate_conversions.cc +++ b/services/ui/ws/window_coordinate_conversions.cc
@@ -6,69 +6,41 @@ #include "services/ui/ws/server_window.h" #include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/point_conversions.h" +#include "ui/gfx/geometry/point3_f.h" #include "ui/gfx/geometry/point_f.h" -#include "ui/gfx/geometry/rect.h" -#include "ui/gfx/geometry/vector2d.h" -#include "ui/gfx/geometry/vector2d_f.h" +#include "ui/gfx/transform.h" namespace ui { - namespace ws { - namespace { -gfx::Vector2dF CalculateOffsetToAncestor(const ServerWindow* window, - const ServerWindow* ancestor) { - DCHECK(ancestor->Contains(window)); - gfx::Vector2d result; - for (const ServerWindow* v = window; v != ancestor; v = v->parent()) - result += v->bounds().OffsetFromOrigin(); - return gfx::Vector2dF(result.x(), result.y()); +gfx::Transform GetTransformToRoot(const ServerWindow* window) { + // This code should only be called when |window| is connected to a display. + const ServerWindow* root = window->GetRoot(); + DCHECK(root); + + gfx::Transform transform; + const ServerWindow* w = window; + for (; w && w != root; w = w->parent()) { + gfx::Transform translation; + translation.Translate(static_cast<float>(w->bounds().x()), + static_cast<float>(w->bounds().y())); + if (!w->transform().IsIdentity()) + transform.ConcatTransform(w->transform()); + transform.ConcatTransform(translation); + } + return transform; } } // namespace -gfx::Point ConvertPointBetweenWindows(const ServerWindow* from, - const ServerWindow* to, - const gfx::Point& point) { - return gfx::ToFlooredPoint( - ConvertPointFBetweenWindows(from, to, gfx::PointF(point.x(), point.y()))); -} - -gfx::PointF ConvertPointFBetweenWindows(const ServerWindow* from, - const ServerWindow* to, - const gfx::PointF& point) { - DCHECK(from); - DCHECK(to); - if (from == to) - return point; - - if (from->Contains(to)) { - const gfx::Vector2dF offset(CalculateOffsetToAncestor(to, from)); - return point - offset; - } - DCHECK(to->Contains(from)); - const gfx::Vector2dF offset(CalculateOffsetToAncestor(from, to)); - return point + offset; -} - -gfx::Rect ConvertRectBetweenWindows(const ServerWindow* from, - const ServerWindow* to, - const gfx::Rect& rect) { - DCHECK(from); - DCHECK(to); - if (from == to) - return rect; - - const gfx::Point top_left( - ConvertPointBetweenWindows(from, to, rect.origin())); - const gfx::Point bottom_right(gfx::ToCeiledPoint(ConvertPointFBetweenWindows( - from, to, gfx::PointF(rect.right(), rect.bottom())))); - return gfx::Rect(top_left.x(), top_left.y(), bottom_right.x() - top_left.x(), - bottom_right.y() - top_left.y()); +gfx::Point ConvertPointFromRoot(const ServerWindow* window, + const gfx::Point& location_in_root) { + const gfx::Transform transform = GetTransformToRoot(window); + gfx::Point3F location_in_root3(gfx::PointF{location_in_root}); + transform.TransformPointReverse(&location_in_root3); + return gfx::ToFlooredPoint(location_in_root3.AsPointF()); } } // namespace ws - } // namespace ui
diff --git a/services/ui/ws/window_coordinate_conversions.h b/services/ui/ws/window_coordinate_conversions.h index 577cb99..1c687c1 100644 --- a/services/ui/ws/window_coordinate_conversions.h +++ b/services/ui/ws/window_coordinate_conversions.h
@@ -7,33 +7,18 @@ namespace gfx { class Point; -class PointF; -class Rect; } namespace ui { - namespace ws { class ServerWindow; -// Converts |point| from the coordinates of |from| to the coordinates of |to|. -// |from| and |to| must be an ancestors or descendants of each other. -gfx::Point ConvertPointBetweenWindows(const ServerWindow* from, - const ServerWindow* to, - const gfx::Point& point); -gfx::PointF ConvertPointFBetweenWindows(const ServerWindow* from, - const ServerWindow* to, - const gfx::PointF& point); - -// Converts |rect| from the coordinates of |from| to the coordinates of |to|. -// |from| and |to| must be an ancestors or descendants of each other. -gfx::Rect ConvertRectBetweenWindows(const ServerWindow* from, - const ServerWindow* to, - const gfx::Rect& rect); +// Converts |point|, in the coordinates of the root, to that of |window|. +gfx::Point ConvertPointFromRoot(const ServerWindow* window, + const gfx::Point& point); } // namespace ws - } // namespace ui #endif // SERVICES_UI_WS_WINDOW_COORDINATE_CONVERSIONS_H_
diff --git a/services/ui/ws/window_coordinate_conversions_unittest.cc b/services/ui/ws/window_coordinate_conversions_unittest.cc deleted file mode 100644 index 6cdebff..0000000 --- a/services/ui/ws/window_coordinate_conversions_unittest.cc +++ /dev/null
@@ -1,62 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "services/ui/ws/window_coordinate_conversions.h" - -#include "services/ui/ws/server_window.h" -#include "services/ui/ws/server_window_delegate.h" -#include "services/ui/ws/test_server_window_delegate.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "ui/gfx/geometry/point_f.h" -#include "ui/gfx/geometry/rect.h" - -namespace ui { - -namespace ws { - -using WindowCoordinateConversionsTest = testing::Test; - -TEST_F(WindowCoordinateConversionsTest, ConvertRectBetweenWindows) { - TestServerWindowDelegate d1, d2, d3; - ServerWindow v1(&d1, WindowId()), v2(&d2, WindowId()), v3(&d3, WindowId()); - v1.SetBounds(gfx::Rect(1, 2, 100, 100)); - v2.SetBounds(gfx::Rect(3, 4, 100, 100)); - v3.SetBounds(gfx::Rect(5, 6, 100, 100)); - v1.Add(&v2); - v2.Add(&v3); - - EXPECT_EQ(gfx::Rect(2, 1, 8, 9), - ConvertRectBetweenWindows(&v1, &v3, gfx::Rect(10, 11, 8, 9))); - - EXPECT_EQ(gfx::Rect(18, 21, 8, 9), - ConvertRectBetweenWindows(&v3, &v1, gfx::Rect(10, 11, 8, 9))); -} - -TEST_F(WindowCoordinateConversionsTest, ConvertPointFBetweenWindows) { - TestServerWindowDelegate d1, d2, d3; - ServerWindow v1(&d1, WindowId()), v2(&d2, WindowId()), v3(&d3, WindowId()); - v1.SetBounds(gfx::Rect(1, 2, 100, 100)); - v2.SetBounds(gfx::Rect(3, 4, 100, 100)); - v3.SetBounds(gfx::Rect(5, 6, 100, 100)); - v1.Add(&v2); - v2.Add(&v3); - - { - const gfx::PointF result( - ConvertPointFBetweenWindows(&v1, &v3, gfx::PointF(10.5f, 11.9f))); - EXPECT_FLOAT_EQ(2.5f, result.x()); - EXPECT_FLOAT_EQ(1.9f, result.y()); - } - - { - const gfx::PointF result( - ConvertPointFBetweenWindows(&v3, &v1, gfx::PointF(10.2f, 11.4f))); - EXPECT_FLOAT_EQ(18.2f, result.x()); - EXPECT_FLOAT_EQ(21.4f, result.y()); - } -} - -} // namespace ws - -} // namespace ui
diff --git a/services/ui/ws/window_finder.cc b/services/ui/ws/window_finder.cc index 6aa0657..fa2d95b 100644 --- a/services/ui/ws/window_finder.cc +++ b/services/ui/ws/window_finder.cc
@@ -7,7 +7,6 @@ #include "base/containers/adapters.h" #include "services/ui/ws/server_window.h" #include "services/ui/ws/server_window_delegate.h" -#include "services/ui/ws/window_coordinate_conversions.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point3_f.h" #include "ui/gfx/geometry/point_f.h" @@ -35,30 +34,28 @@ return true; } -gfx::Point ConvertPointFromParentToChild(const ServerWindow* child, - const gfx::Point& location_in_parent) { - if (child->transform().IsIdentity()) { - return gfx::Point(location_in_parent.x() - child->bounds().x(), - location_in_parent.y() - child->bounds().y()); - } - - gfx::Transform transform = child->transform(); +gfx::Transform TransformFromParent(const ServerWindow* window, + const gfx::Transform& current_transform) { + gfx::Transform transform = current_transform; + if (!window->transform().IsIdentity()) + transform.ConcatTransform(window->transform()); gfx::Transform translation; - translation.Translate(static_cast<float>(child->bounds().x()), - static_cast<float>(child->bounds().y())); + translation.Translate(static_cast<float>(window->bounds().x()), + static_cast<float>(window->bounds().y())); transform.ConcatTransform(translation); - gfx::Point3F location_in_child3(gfx::PointF{location_in_parent}); - transform.TransformPointReverse(&location_in_child3); - return gfx::ToFlooredPoint(location_in_child3.AsPointF()); + return transform; } -bool FindDeepestVisibleWindowForEventsImpl(ServerWindow* window, - const gfx::Point& location, - DeepestWindow* deepest_window) { +bool FindDeepestVisibleWindowForEventsImpl( + ServerWindow* window, + const gfx::Point& location_in_root, + const gfx::Point& location_in_window, + const gfx::Transform& transform_from_parent, + DeepestWindow* deepest_window) { // The non-client area takes precedence over descendants, as otherwise the // user would likely not be able to hit the non-client area as it's common // for descendants to go into the non-client area. - if (IsLocationInNonclientArea(window, location)) { + if (IsLocationInNonclientArea(window, location_in_window)) { deepest_window->window = window; deepest_window->in_non_client_area = true; return true; @@ -77,8 +74,12 @@ if (!child->visible()) continue; - gfx::Point location_in_child = - ConvertPointFromParentToChild(child, location); + const gfx::Transform child_transform = + TransformFromParent(child, transform_from_parent); + gfx::Point3F location_in_child3(gfx::PointF{location_in_root}); + child_transform.TransformPointReverse(&location_in_child3); + const gfx::Point location_in_child = + gfx::ToFlooredPoint(location_in_child3.AsPointF()); gfx::Rect child_bounds(child->bounds().size()); child_bounds.Inset(-child->extended_hit_test_region().left(), -child->extended_hit_test_region().top(), @@ -90,8 +91,9 @@ continue; } - if (FindDeepestVisibleWindowForEventsImpl(child, location_in_child, - deepest_window)) { + if (FindDeepestVisibleWindowForEventsImpl( + child, location_in_root, location_in_child, child_transform, + deepest_window)) { return true; } } @@ -110,19 +112,10 @@ DeepestWindow FindDeepestVisibleWindowForEvents(ServerWindow* root_window, const gfx::Point& location) { DeepestWindow result; - FindDeepestVisibleWindowForEventsImpl(root_window, location, &result); + FindDeepestVisibleWindowForEventsImpl(root_window, location, location, + gfx::Transform(), &result); return result; } -gfx::Transform GetTransformToWindow(ServerWindow* window) { - gfx::Transform transform; - ServerWindow* current = window; - while (current->parent()) { - transform.Translate(-current->bounds().x(), -current->bounds().y()); - current = current->parent(); - } - return transform; -} - } // namespace ws } // namespace ui
diff --git a/services/ui/ws/window_finder.h b/services/ui/ws/window_finder.h index 8f203c4..9ea4d2bb 100644 --- a/services/ui/ws/window_finder.h +++ b/services/ui/ws/window_finder.h
@@ -7,7 +7,6 @@ namespace gfx { class Point; -class Transform; } namespace ui { @@ -27,10 +26,6 @@ DeepestWindow FindDeepestVisibleWindowForEvents(ServerWindow* root_window, const gfx::Point& location); -// Retrieve the transform to the provided |window|'s coordinate space from the -// root. -gfx::Transform GetTransformToWindow(ServerWindow* window); - } // namespace ws } // namespace ui
diff --git a/services/ui/ws/window_server.cc b/services/ui/ws/window_server.cc index 1252adc..1031515 100644 --- a/services/ui/ws/window_server.cc +++ b/services/ui/ws/window_server.cc
@@ -19,7 +19,6 @@ #include "services/ui/ws/server_window.h" #include "services/ui/ws/server_window_compositor_frame_sink_manager.h" #include "services/ui/ws/user_activity_monitor.h" -#include "services/ui/ws/window_coordinate_conversions.h" #include "services/ui/ws/window_manager_access_policy.h" #include "services/ui/ws/window_manager_display_root.h" #include "services/ui/ws/window_manager_state.h"
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json index 3bb22249..ff8be44 100644 --- a/testing/buildbot/chromium.linux.json +++ b/testing/buildbot/chromium.linux.json
@@ -3519,11 +3519,23 @@ "Linux Builder": { "additional_compile_targets": [ "all" + ], + "scripts": [ + { + "name": "check_gn_headers", + "script": "check_gn_headers.py" + } ] }, "Linux Builder (dbg)": { "additional_compile_targets": [ "all" + ], + "scripts": [ + { + "name": "check_gn_headers", + "script": "check_gn_headers.py" + } ] }, "Linux Tests": {
diff --git a/testing/scripts/check_gn_headers.py b/testing/scripts/check_gn_headers.py new file mode 100755 index 0000000..7aa36a6a --- /dev/null +++ b/testing/scripts/check_gn_headers.py
@@ -0,0 +1,46 @@ +#!/usr/bin/env python +# Copyright 2017 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import json +import os +import sys + + +import common + + +def main_run(args): + with common.temporary_file() as tempfile_path: + rc = common.run_command([ + sys.executable, + os.path.join(common.SRC_DIR, 'build', 'check_gn_headers.py'), + '--out-dir', + os.path.join(args.paths['checkout'], 'out', args.build_config_fs), + '--whitelist', + os.path.join(common.SRC_DIR, 'build', 'check_gn_headers_whitelist.txt'), + '--json', tempfile_path + ], cwd=common.SRC_DIR) + + with open(tempfile_path) as f: + failures = json.load(f) + + json.dump({ + 'valid': True, + 'failures': failures, + }, args.output) + + return rc + + +def main_compile_targets(args): + json.dump([], args.output) + + +if __name__ == '__main__': + funcs = { + 'run': main_run, + 'compile_targets': main_compile_targets, + } + sys.exit(common.run_script(sys.argv[1:], funcs))
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 5be5f25..8d0eed5e 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -2841,21 +2841,6 @@ ] } ], - "SeccompSandboxAndroid": [ - { - "platforms": [ - "android" - ], - "experiments": [ - { - "name": "SandboxEnabled", - "enable_features": [ - "SeccompSandboxAndroid" - ] - } - ] - } - ], "SecurityChip": [ { "platforms": [
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG index 5b8b6375..7ea2e39 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -22601,7 +22601,7 @@ crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/webgl/webgl-texture-binding-preserved.html [ Failure ] crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/webgl/webgl-viewport-parameters-preserved.html [ Failure ] crbug.com/591099 virtual/display_list_2d_canvas/fast/canvas/zero-size-fill-rect.html [ Crash ] -crbug.com/591099 virtual/enable_wasm/http/tests/wasm/wasm_local_iframe_test.html [ Crash Timeout ] +crbug.com/591099 virtual/enable_wasm/external/wpt/wasm/wasm_local_iframe_test.html [ Crash Timeout ] crbug.com/591099 virtual/gpu/fast/canvas/2d.composite.globalAlpha.fillPath.html [ Crash ] crbug.com/591099 virtual/gpu/fast/canvas/2d.fillText.gradient.html [ Crash ] crbug.com/591099 virtual/gpu/fast/canvas/2d.text.draw.fill.maxWidth.gradient.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service index edc37dca3..0725edaf 100644 --- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service +++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-network-service
@@ -3658,11 +3658,11 @@ Bug(none) virtual/display_list_2d_canvas/fast/canvas/webgl/texImage-imageBitmap-from-blob.html [ Failure ] Bug(none) virtual/display_list_2d_canvas/fast/canvas/webgl/texImage-imageBitmap-from-imageBitmap-from-blob.html [ Failure ] Bug(none) virtual/enable_asmjs/http/tests/asmjs/asm-warnings.html [ Failure ] -Bug(none) virtual/enable_wasm/http/tests/wasm/wasm_indexeddb_test.html [ Timeout ] -Bug(none) virtual/enable_wasm/http/tests/wasm/wasm_local_iframe_test.html [ Failure ] +Bug(none) virtual/enable_wasm/external/wpt/wasm/wasm_indexeddb_test.html [ Timeout ] +Bug(none) virtual/enable_wasm/external/wpt/wasm/wasm_local_iframe_test.html [ Failure ] Bug(none) virtual/enable_wasm/http/tests/wasm/wasm_remote_postMessage_test.https.html [ Timeout ] -Bug(none) virtual/enable_wasm/http/tests/wasm/wasm_serialization_tests.html [ Failure ] -Bug(none) virtual/enable_wasm/http/tests/wasm/wasm_service_worker_test.html [ Failure ] +Bug(none) virtual/enable_wasm/external/wpt/wasm/wasm_serialization_tests.html [ Failure ] +Bug(none) virtual/enable_wasm/external/wpt/wasm/wasm_service_worker_test.html [ Failure ] Bug(none) virtual/enable_wasm_streaming/http/tests/wasm_streaming/wasm_response_apis.html [ Failure ] Bug(none) virtual/gpu/fast/canvas/canvas-composite-video-shadow.html [ Timeout ] Bug(none) virtual/gpu/fast/canvas/canvas-createImageBitmap-blob-in-workers.html [ Timeout ]
diff --git a/third_party/WebKit/LayoutTests/NeverFixTests b/third_party/WebKit/LayoutTests/NeverFixTests index 422fcebd..ba6e67c 100644 --- a/third_party/WebKit/LayoutTests/NeverFixTests +++ b/third_party/WebKit/LayoutTests/NeverFixTests
@@ -213,6 +213,7 @@ # wasm tests. Currently under virtual/enable_wasm or virtual/enable_wasm_streaming crbug.com/642912 http/tests/wasm/ [ WontFix ] +crbug.com/642912 external/wpt/wasm/ [ WontFix ] crbug.com/642912 virtual/mojo-loading/http/tests/wasm/ [ WontFix ] crbug.com/712970 http/tests/wasm_streaming/ [ WontFix ] crbug.com/712970 virtual/mojo-loading/http/tests/wasm_streaming/ [ WontFix ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites index 14bcce1..883fb3e 100644 --- a/third_party/WebKit/LayoutTests/VirtualTestSuites +++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -372,6 +372,11 @@ "args": ["--enable-features=WebAssembly"] }, { + "prefix": "enable_wasm", + "base": "external/wpt/wasm", + "args": ["--enable-features=WebAssembly"] + }, + { "prefix": "enable_wasm_streaming", "base": "http/tests/wasm_streaming", "args": ["--enable-features=WebAssemblyStreaming"]
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator-pluginarray.html b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator-pluginarray.html new file mode 100644 index 0000000..8798b263 --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/html/webappapis/system-state-and-capabilities/the-navigator-object/navigator-pluginarray.html
@@ -0,0 +1,55 @@ +<!doctype html> +<html> +<body> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script type="text/javascript"> +test(function () { + for (var i = 0; i < navigator.plugins.length; i++) { + var plugin = navigator.plugins[i]; + var name = plugin.name; + assert_equals(plugin, navigator.plugins[i]); + assert_equals(plugin, navigator.plugins[name]); + } + for (var i = 0; i < navigator.mimeTypes.length; i++) { + var mime_type = navigator.mimeTypes[i]; + var type = mime_type.type; + assert_equals(mime_type, navigator.mimeTypes[i]); + assert_equals(mime_type, navigator.mimeTypes[type]); + assert_equals(mime_type.enabledPlugin, navigator.plugins[mime_type.enabledPlugin.name]); + } +}, "Tests that navigator.plugins and navigator.mimeTypes returns the same object when queried multiple times."); + +test(function () { + var iframe = document.createElement("iframe"); + iframe.src = "about:blank"; + document.body.appendChild(iframe); + assert_equals(navigator.plugins.length, iframe.contentWindow.navigator.plugins.length); + assert_equals(navigator.mimeTypes.length, iframe.contentWindow.navigator.mimeTypes.length); + for (var i = 0; i < navigator.plugins.length; i++) { + var plugin = navigator.plugins[i]; + var name = plugin.name; + assert_not_equals(plugin, iframe.contentWindow.navigator.plugins[i]); + assert_not_equals(plugin, iframe.contentWindow.navigator.plugins[name]); + } + for (var i = 0; i < navigator.mimeTypes.length; i++) { + var mime_type = navigator.mimeTypes[i]; + var type = mime_type.type; + assert_not_equals(mime_type, iframe.contentWindow.navigator.mimeTypes[i]); + assert_not_equals(mime_type, iframe.contentWindow.navigator.mimeTypes[type]); + assert_not_equals(mime_type.enabledPlugin, iframe.contentWindow.navigator.plugins[mime_type.enabledPlugin.name]); + } + iframe.remove(); +}, "Tests that navigator.plugins and navigator.mimeTypes does not return the same object on different frames."); + +test(function () { + for (var i = 1; i < navigator.plugins.length; i++) { + assert_less_than_equal(navigator.plugins[i-1].name.localeCompare(navigator.plugins[i].name), 0); + } + for (var i = 1; i < navigator.mimeTypes.length; i++) { + assert_less_than_equal(navigator.mimeTypes[i-1].type.localeCompare(navigator.mimeTypes[i].type), 0); + } +}, "Tests that navigator.plugins and navigator.mimeTypes returns plugins sorted in alphabetical order by plugin name."); +</script> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/compile_worker.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/compile_worker.js similarity index 100% rename from third_party/WebKit/LayoutTests/http/tests/wasm/compile_worker.js rename to third_party/WebKit/LayoutTests/external/wpt/wasm/compile_worker.js
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/incrementer.wasm b/third_party/WebKit/LayoutTests/external/wpt/wasm/incrementer.wasm new file mode 100644 index 0000000..47afcde --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/incrementer.wasm Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/blank.html b/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/blank.html similarity index 100% rename from third_party/WebKit/LayoutTests/http/tests/wasm/resources/blank.html rename to third_party/WebKit/LayoutTests/external/wpt/wasm/resources/blank.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/frame.html b/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/frame.html similarity index 100% rename from third_party/WebKit/LayoutTests/http/tests/wasm/resources/frame.html rename to third_party/WebKit/LayoutTests/external/wpt/wasm/resources/frame.html
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/incrementer.wasm b/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/incrementer.wasm new file mode 100644 index 0000000..47afcde --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/incrementer.wasm Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/load_wasm.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/load_wasm.js new file mode 100644 index 0000000..eca4b8d --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/load_wasm.js
@@ -0,0 +1,18 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +function createWasmModule() { + // the file incrementer.wasm is copied from + // //v8/test/mjsunit/wasm. This is because currently we cannot + // reference files outside the LayoutTests folder. When wasm format + // changes require that file to be updated, there is a test on the + // v8 side (same folder), ensure-wasm-binaries-up-to-date.js, which + // fails and will require incrementer.wasm to be updated on that side. + return fetch('incrementer.wasm') + .then(response => { + if (!response.ok) throw new Error(response.statusText); + return response.arrayBuffer(); + }) + .then(WebAssembly.compile); +}
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/resources/service-worker.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/resources/service-worker.js similarity index 100% rename from third_party/WebKit/LayoutTests/http/tests/wasm/resources/service-worker.js rename to third_party/WebKit/LayoutTests/external/wpt/wasm/resources/service-worker.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/wasm_indexeddb_test.html b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.html similarity index 71% rename from third_party/WebKit/LayoutTests/http/tests/wasm/wasm_indexeddb_test.html rename to third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.html index 03d891c..ec91708 100644 --- a/third_party/WebKit/LayoutTests/http/tests/wasm/wasm_indexeddb_test.html +++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.html
@@ -1,9 +1,9 @@ <!DOCTYPE html> <html> <head> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> -<script src="../resources/get-host-info.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/common/get-host-info.sub.js"></script> <script src="resources/load_wasm.js"></script> <script src="wasm_indexeddb_test.js"></script> </head>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.js new file mode 100644 index 0000000..301cbd2f --- /dev/null +++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_indexeddb_test.js
@@ -0,0 +1,81 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +var db_name = 'db'; +var obj_store = 'store'; +var module_key = 'my_module'; + +function createAndSaveToIndexedDB() { + return new Promise((resolve, reject) => { + createWasmModule() + .then(mod => { + var delete_request = indexedDB.deleteDatabase(db_name); + delete_request.onsuccess = function() { + var open_request = indexedDB.open(db_name); + open_request.onupgradeneeded = function() { + var db = open_request.result; + db.createObjectStore(obj_store); + }; + open_request.onsuccess = function() { + var db = open_request.result; + var tx = db.transaction(obj_store, 'readwrite'); + var store = tx.objectStore(obj_store); + try { + store.put(mod, module_key); + } catch(e) { + reject(e); + return; + } + tx.oncomplete = function() { + resolve(); + }; + tx.onabort = function() { + reject(transaction.error); + }; + }; + }; + }) + .catch(error => reject(error)); + }); +} + +function loadFromIndexedDB(prev) { + return new Promise((resolve, reject) => { + prev.then(() => { + var open_request = indexedDB.open(db_name); + open_request.onsuccess = function() { + var db = open_request.result; + var tx = db.transaction(obj_store); + var store = tx.objectStore(obj_store); + var get_request = store.get(module_key); + get_request.onsuccess = function() { + var mod = get_request.result; + assert_true(mod instanceof WebAssembly.Module); + try { + var instance = new WebAssembly.Instance(mod); + } catch(e) { + reject(e); + return; + } + resolve(instance.exports.increment(1)); + }; + }; + }); + }); +} + +function TestIndexedDBLoadStoreSecure() { + return loadFromIndexedDB(createAndSaveToIndexedDB()) + .then(res => assert_equals(res, 2), + error => assert_unreached(error)); +} + +function TestIndexedDBLoadStoreInsecure() { + return createAndSaveToIndexedDB() + .then(assert_unreached, + error => { + assert_true(error instanceof DOMException); + assert_equals(error.name, 'DataCloneError'); + }); +}
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/wasm_local_iframe_test.html b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_local_iframe_test.html similarity index 100% rename from third_party/WebKit/LayoutTests/http/tests/wasm/wasm_local_iframe_test.html rename to third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_local_iframe_test.html
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/wasm_serialization_tests.html b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_serialization_tests.html similarity index 69% rename from third_party/WebKit/LayoutTests/http/tests/wasm/wasm_serialization_tests.html rename to third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_serialization_tests.html index 9e77140..0011095 100644 --- a/third_party/WebKit/LayoutTests/http/tests/wasm/wasm_serialization_tests.html +++ b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_serialization_tests.html
@@ -1,6 +1,6 @@ <!DOCTYPE html> -<script src="../../../resources/testharness.js"></script> -<script src="../../../resources/testharnessreport.js"></script> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> <script src="resources/load_wasm.js"></script> <script src="wasm_serialization_tests.js"></script> <script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/wasm_serialization_tests.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_serialization_tests.js similarity index 100% rename from third_party/WebKit/LayoutTests/http/tests/wasm/wasm_serialization_tests.js rename to third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_serialization_tests.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/wasm_serialization_worker.js b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_serialization_worker.js similarity index 100% rename from third_party/WebKit/LayoutTests/http/tests/wasm/wasm_serialization_worker.js rename to third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_serialization_worker.js
diff --git a/third_party/WebKit/LayoutTests/http/tests/wasm/wasm_service_worker_test.html b/third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_service_worker_test.html similarity index 100% rename from third_party/WebKit/LayoutTests/http/tests/wasm/wasm_service_worker_test.html rename to third_party/WebKit/LayoutTests/external/wpt/wasm/wasm_service_worker_test.html
diff --git a/third_party/WebKit/LayoutTests/virtual/enable_wasm/external/wpt/wasm/README.txt b/third_party/WebKit/LayoutTests/virtual/enable_wasm/external/wpt/wasm/README.txt new file mode 100644 index 0000000..5888cfc --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/enable_wasm/external/wpt/wasm/README.txt
@@ -0,0 +1 @@ +Tests that depend on --enable-features=WebAssembly
diff --git a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp index f7477a8..26347fa5 100644 --- a/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp +++ b/third_party/WebKit/Source/core/editing/markers/DocumentMarkerListEditor.cpp
@@ -72,25 +72,30 @@ return start_pos != end_pos; } -// TODO(rlanday): make this not take O(n^2) time when all the markers are -// removed bool DocumentMarkerListEditor::ShiftMarkersContentDependent( MarkerList* list, unsigned offset, unsigned old_length, unsigned new_length) { - bool did_shift_marker = false; - for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) { - DocumentMarker& marker = **it; + // Find first marker that ends after the start of the region being edited. + // Markers before this one can be left untouched. This saves us some time over + // scanning the entire list linearly if the edit region is near the end of the + // text node. + const MarkerList::iterator& shift_range_begin = + std::upper_bound(list->begin(), list->end(), offset, + [](size_t offset, const Member<DocumentMarker>& marker) { + return offset < marker->EndOffset(); + }); - // marked text is neither changed nor shifted - if (marker.EndOffset() <= offset) - continue; + MarkerList::iterator erase_range_end = shift_range_begin; + + bool did_shift_marker = false; + for (MarkerList::iterator it = shift_range_begin; it != list->end(); ++it) { + DocumentMarker& marker = **it; // marked text is (potentially) changed by edit, remove marker if (marker.StartOffset() < offset + old_length) { - list->erase(it - list->begin()); - --it; + erase_range_end = std::next(it); did_shift_marker = true; continue; } @@ -100,24 +105,41 @@ did_shift_marker = true; } + // Note: shift_range_begin could point at a marker being shifted instead of + // deleted, but if this is the case, we don't need to delete any markers, and + // erase() will get 0 for the length param + list->erase(shift_range_begin - list->begin(), + erase_range_end - shift_range_begin); return did_shift_marker; } -// TODO(rlanday): make this not take O(n^2) time when all the markers are -// removed bool DocumentMarkerListEditor::ShiftMarkersContentIndependent( MarkerList* list, unsigned offset, unsigned old_length, unsigned new_length) { + // Find first marker that ends after the start of the region being edited. + // Markers before this one can be left untouched. This saves us some time over + // scanning the entire list linearly if the edit region is near the end of the + // text node. + const MarkerList::iterator& shift_range_begin = + std::upper_bound(list->begin(), list->end(), offset, + [](size_t offset, const Member<DocumentMarker>& marker) { + return offset < marker->EndOffset(); + }); + + MarkerList::iterator erase_range_begin = list->end(); + MarkerList::iterator erase_range_end = list->end(); + bool did_shift_marker = false; - for (MarkerList::iterator it = list->begin(); it != list->end(); ++it) { + for (MarkerList::iterator it = shift_range_begin; it != list->end(); ++it) { DocumentMarker& marker = **it; Optional<DocumentMarker::MarkerOffsets> result = marker.ComputeOffsetsAfterShift(offset, old_length, new_length); if (result == WTF::nullopt) { - list->erase(it - list->begin()); - --it; + if (erase_range_begin == list->end()) + erase_range_begin = it; + erase_range_end = std::next(it); did_shift_marker = true; continue; } @@ -130,6 +152,8 @@ } } + list->erase(erase_range_begin - list->begin(), + erase_range_end - erase_range_begin); return did_shift_marker; }
diff --git a/third_party/WebKit/Source/core/editing/markers/SpellCheckMarkerListImpl.cpp b/third_party/WebKit/Source/core/editing/markers/SpellCheckMarkerListImpl.cpp index f7aebabe..cc62f80 100644 --- a/third_party/WebKit/Source/core/editing/markers/SpellCheckMarkerListImpl.cpp +++ b/third_party/WebKit/Source/core/editing/markers/SpellCheckMarkerListImpl.cpp
@@ -19,27 +19,42 @@ return; } - auto first_overlapping = std::lower_bound( + // Find first marker that ends after the one being inserted starts. If any + // markers overlap the one being inserted, this is the first one. + const auto& first_overlapping = std::lower_bound( markers_.begin(), markers_.end(), marker, [](const Member<DocumentMarker>& marker_in_list, const DocumentMarker* marker_to_insert) { return marker_in_list->EndOffset() < marker_to_insert->StartOffset(); }); - size_t index = first_overlapping - markers_.begin(); - markers_.insert(index, marker); - const auto inserted = markers_.begin() + index; - first_overlapping = inserted + 1; - // TODO(rlanday): optimize this loop so it runs in O(N) time and not O(N^2) - for (const auto i = first_overlapping; - i != markers_.end() && - (*i)->StartOffset() <= (*inserted)->EndOffset();) { - (*inserted)->SetStartOffset( - std::min((*inserted)->StartOffset(), (*i)->StartOffset())); - (*inserted)->SetEndOffset( - std::max((*inserted)->EndOffset(), (*i)->EndOffset())); - markers_.erase(i - markers_.begin()); + // If this marker does not overlap the one being inserted, insert before it + // and we are done. + if (marker->EndOffset() < (*first_overlapping)->StartOffset()) { + markers_.insert(first_overlapping - markers_.begin(), marker); + return; } + + // Otherwise, find the last overlapping marker, replace the first marker with + // the newly-inserted marker (to get the new description), set its start and + // end offsets to include all the overlapped markers, and erase the rest of + // the old markers. + + const auto& last_overlapping = std::upper_bound( + first_overlapping, markers_.end(), marker, + [](const DocumentMarker* marker_to_insert, + const Member<DocumentMarker>& marker_in_list) { + return marker_to_insert->EndOffset() < marker_in_list->StartOffset(); + }); + + marker->SetStartOffset( + std::min(marker->StartOffset(), (*first_overlapping)->StartOffset())); + marker->SetEndOffset( + std::max(marker->EndOffset(), (*(last_overlapping - 1))->EndOffset())); + + *first_overlapping = marker; + size_t num_to_erase = last_overlapping - (first_overlapping + 1); + markers_.erase(first_overlapping + 1 - markers_.begin(), num_to_erase); } void SpellCheckMarkerListImpl::Clear() {
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp index 53e8f65b..75179486 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
@@ -350,6 +350,9 @@ if (!node) return 0; + if (!node->IsElementNode() && !node->IsTextNode() && !node->IsDocumentNode()) + return 0; // Only documents, elements and text nodes get a11y objects + if (AXObjectImpl* obj = Get(node)) return obj;
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp index 7ff8a43..0f395ca 100644 --- a/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp +++ b/third_party/WebKit/Source/modules/accessibility/AXObjectImpl.cpp
@@ -821,11 +821,7 @@ } bool AXObjectImpl::CanReceiveAccessibilityFocus() const { - const Node* node = this->GetNode(); - if (!node) - return false; - - const Element* elem = ToElement(node); + const Element* elem = GetElement(); if (!elem) return false;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/moveable_auto_lock.h b/third_party/WebKit/Source/platform/scheduler/base/moveable_auto_lock.h index ac2b8a8..d7bcb9ff 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/moveable_auto_lock.h +++ b/third_party/WebKit/Source/platform/scheduler/base/moveable_auto_lock.h
@@ -16,7 +16,7 @@ lock_.Acquire(); } - explicit MoveableAutoLock(MoveableAutoLock&& other) + MoveableAutoLock(MoveableAutoLock&& other) : lock_(other.lock_), moved_(other.moved_) { lock_.AssertAcquired(); other.moved_ = true;
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc index 97ad1c53..c8049df 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.cc
@@ -68,10 +68,10 @@ this); selector_.SetTaskQueueSelectorObserver(this); - delayed_do_work_closure_ = - base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), true); - immediate_do_work_closure_ = - base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), false); + delayed_do_work_closure_ = base::BindRepeating( + &TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), true); + immediate_do_work_closure_ = base::BindRepeating( + &TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), false); // TODO(alexclarke): Change this to be a parameter that's passed in. RegisterTimeDomain(real_time_domain_.get()); @@ -208,7 +208,7 @@ void TaskQueueManager::MaybeScheduleImmediateWorkLocked( const tracked_objects::Location& from_here, - MoveableAutoLock&& lock) { + MoveableAutoLock lock) { { MoveableAutoLock auto_lock(std::move(lock)); // Unless we're nested, try to avoid posting redundant DoWorks. @@ -368,7 +368,7 @@ void TaskQueueManager::PostDoWorkContinuationLocked( base::Optional<NextTaskDelay> next_delay, LazyNow* lazy_now, - MoveableAutoLock&& lock) { + MoveableAutoLock lock) { DCHECK(main_thread_checker_.CalledOnValidThread()); {
diff --git a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h index 49be896..dd8e9a18 100644 --- a/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h +++ b/third_party/WebKit/Source/platform/scheduler/base/task_queue_manager.h
@@ -246,7 +246,7 @@ // Post a DoWork continuation if |next_delay| is not empty. void PostDoWorkContinuationLocked(base::Optional<NextTaskDelay> next_delay, LazyNow* lazy_now, - MoveableAutoLock&& lock); + MoveableAutoLock lock); // Delayed Tasks with run_times <= Now() are enqueued onto the work queue and // reloads any empty work queues. @@ -295,7 +295,7 @@ void MaybeScheduleImmediateWorkLocked( const tracked_objects::Location& from_here, - MoveableAutoLock&& lock); + MoveableAutoLock lock); // Adds |queue| to |any_thread().has_incoming_immediate_work_| and if // |queue_is_blocked| is false it makes sure a DoWork is posted. @@ -328,8 +328,8 @@ scoped_refptr<TaskQueueManagerDelegate> delegate_; internal::TaskQueueSelector selector_; - base::Closure immediate_do_work_closure_; - base::Closure delayed_do_work_closure_; + base::RepeatingClosure immediate_do_work_closure_; + base::RepeatingClosure delayed_do_work_closure_; base::CancelableClosure cancelable_delayed_do_work_closure_; bool task_was_run_on_quiescence_monitored_queue_;
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py index 3752a4e9..35ab4247 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/manager.py
@@ -270,9 +270,7 @@ def _test_input_for_file(self, test_file): return TestInput(test_file, self._options.slow_time_out_ms if self._test_is_slow(test_file) else self._options.time_out_ms, - self._test_requires_lock(test_file), - should_add_missing_baselines=(self._options.new_test_results and - not self._test_is_expected_missing(test_file))) + self._test_requires_lock(test_file)) def _test_requires_lock(self, test_file): """Return True if the test needs to be locked when running multiple
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py index f82824f..378b4e78 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/controllers/single_test_runner.py
@@ -57,8 +57,6 @@ class SingleTestRunner(object): - (ALONGSIDE_TEST, PLATFORM_DIR, VERSION_DIR, UPDATE) = ('alongside', 'platform', 'version', 'update') - def __init__(self, port, options, results_directory, worker_name, primary_driver, secondary_driver, test_input, stop_when_done): self._port = port @@ -73,7 +71,6 @@ self._should_run_pixel_test = test_input.should_run_pixel_test self._should_run_pixel_test_first = test_input.should_run_pixel_test_first self._reference_files = test_input.reference_files - self._should_add_missing_baselines = test_input.should_add_missing_baselines self._stop_when_done = stop_when_done # If this is a virtual test that uses the default flags instead of the @@ -105,7 +102,7 @@ self._port.expected_audio(self._test_name)) def _should_fetch_expected_checksum(self): - return self._should_run_pixel_test and not (self._options.new_baseline or self._options.reset_results) + return self._should_run_pixel_test and not self._options.reset_results def _driver_input(self): # The image hash is used to avoid doing an image dump if the @@ -166,8 +163,6 @@ expected_driver_output = self._expected_driver_output() test_result = self._compare_output(expected_driver_output, driver_output) - if self._should_add_missing_baselines: - self._add_missing_baselines(test_result, driver_output) test_result_writer.write_test_result(self._filesystem, self._port, self._results_directory, self._test_name, driver_output, expected_driver_output, test_result.failures) return test_result @@ -185,61 +180,32 @@ _render_tree_dump_pattern = re.compile(r"^layer at \(\d+,\d+\) size \d+x\d+\n") - def _add_missing_baselines(self, test_result, driver_output): - missing_image = test_result.has_failure_matching_types( - test_failures.FailureMissingImage, test_failures.FailureMissingImageHash) - if test_result.has_failure_matching_types(test_failures.FailureMissingResult): - self._save_baseline_data(driver_output.text, '.txt', self._location_for_missing_baseline(driver_output.text, '.txt')) - if test_result.has_failure_matching_types(test_failures.FailureMissingAudio): - self._save_baseline_data(driver_output.audio, '.wav', self._location_for_missing_baseline(driver_output.audio, '.wav')) - if missing_image: - self._save_baseline_data(driver_output.image, '.png', self._location_for_missing_baseline(driver_output.image, '.png')) - - def _location_for_missing_baseline(self, data, extension): - if self._options.add_platform_exceptions: - return self.VERSION_DIR - if extension == '.png': - return self.PLATFORM_DIR - if extension == '.wav': - return self.ALONGSIDE_TEST - if extension == '.txt' and self._render_tree_dump_pattern.match(data): - return self.PLATFORM_DIR - return self.ALONGSIDE_TEST - def _update_or_add_new_baselines(self, driver_output): - location = self.VERSION_DIR if self._options.add_platform_exceptions else self.UPDATE - self._save_baseline_data(driver_output.text, '.txt', location) - self._save_baseline_data(driver_output.audio, '.wav', location) + self._save_baseline_data(driver_output.text, '.txt') + self._save_baseline_data(driver_output.audio, '.wav') if self._should_run_pixel_test: - self._save_baseline_data(driver_output.image, '.png', location) + self._save_baseline_data(driver_output.image, '.png') - def _save_baseline_data(self, data, extension, location): + def _save_baseline_data(self, data, extension): if data is None: return port = self._port fs = self._filesystem - if location == self.ALONGSIDE_TEST: - output_dir = fs.dirname(port.abspath_for_test(self._test_name)) - elif location == self.VERSION_DIR: + if self._options.add_platform_exceptions: output_dir = fs.join(port.baseline_version_dir(), fs.dirname(self._test_name)) - elif location == self.PLATFORM_DIR: - output_dir = fs.join(port.baseline_platform_dir(), fs.dirname(self._test_name)) - elif location == self.UPDATE: - output_dir = fs.dirname(port.expected_filename(self._test_name, extension)) else: - raise AssertionError('unrecognized baseline location: %s' % location) + output_dir = fs.dirname(port.expected_filename(self._test_name, extension)) fs.maybe_make_directory(output_dir) output_basename = fs.basename(fs.splitext(self._test_name)[0] + '-expected' + extension) output_path = fs.join(output_dir, output_basename) - if location == self.VERSION_DIR: - fallback_path = port.expected_filename(self._test_name, extension) - if fallback_path != output_path and fs.sha1(fallback_path) == hashlib.sha1(data).hexdigest(): - _log.info('Not writing new expected result "%s" because it is the same as "%s"', - port.relative_test_filename(output_path), port.relative_test_filename(fallback_path)) - return + current_expected_path = port.expected_filename(self._test_name, extension) + if fs.exists(current_expected_path) and fs.sha1(current_expected_path) == hashlib.sha1(data).hexdigest(): + _log.info('Not writing new expected result "%s" because it is the same as the current expected result', + port.relative_test_filename(output_path)) + return _log.info('Writing new expected result "%s"', port.relative_test_filename(output_path)) port.update_baseline(output_path, data)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_input.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_input.py index a14f4ae..c08a82f 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_input.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/models/test_input.py
@@ -32,7 +32,7 @@ """Groups information about a test for easy passing of data.""" def __init__(self, test_name, timeout_ms=None, requires_lock=None, reference_files=None, - should_run_pixel_test=None, should_add_missing_baselines=True): + should_run_pixel_test=None): # TestInput objects are normally constructed by the manager and passed # to the workers, but these some fields are set lazily in the workers # where possible, because they require us to look at the filesystem, @@ -42,16 +42,13 @@ self.requires_lock = requires_lock self.reference_files = reference_files self.should_run_pixel_test = should_run_pixel_test - self.should_add_missing_baselines = should_add_missing_baselines def __repr__(self): return ( "TestInput('%s', timeout_ms=%s, requires_lock=%s, " - 'reference_files=%s, should_run_pixel_test=%s, ' - 'should_add_missing_baselines=%s)' % ( + 'reference_files=%s, should_run_pixel_test=%s)' % ( self.test_name, self.timeout_ms, self.requires_lock, self.reference_files, - self.should_run_pixel_test, - self.should_add_missing_baselines)) + self.should_run_pixel_test))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py index 37b0a644..df94420 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -80,6 +80,10 @@ return exit_codes.UNEXPECTED_ERROR_EXIT_STATUS +def deprecate(option, opt_str, _, parser): + parser.error('%s: %s' % (opt_str, option.help)) + + def parse_args(args): option_group_definitions = [] @@ -174,16 +178,16 @@ help='Path to write the JSON test results for only *failing* tests.'), optparse.make_option( '--new-baseline', - action='store_true', - default=False, - help=('Save generated results as new baselines into the *most-specific-platform* ' - "directory, overwriting whatever's already there. Equivalent to " - '--reset-results --add-platform-exceptions')), + action='callback', + callback=deprecate, + help=('Deprecated. Use "webkit-patch rebaseline-cl" instead, or ' + '"--reset-results --add-platform-exceptions" if you do want to create ' + 'platform-version-specific new baselines locally.')), optparse.make_option( '--new-test-results', - action='store_true', - default=False, - help='Create new baselines when no expected results exist'), + action='callback', + callback=deprecate, + help='Deprecated. Use --reset-results instead.'), optparse.make_option( '--no-show-results', dest='show_results', @@ -509,10 +513,6 @@ additional_platform_directories.append(port.host.filesystem.abspath(path)) options.additional_platform_directory = additional_platform_directories - if options.new_baseline: - options.reset_results = True - options.add_platform_exceptions = True - if options.pixel_test_directories: options.pixel_tests = True verified_dirs = set()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py index 9a81b7d8..aefcb5c 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -47,13 +47,11 @@ from webkitpy.layout_tests.port import test -def parse_args(extra_args=None, tests_included=False, new_results=False): +def parse_args(extra_args=None, tests_included=False): extra_args = extra_args or [] args = [] if not '--platform' in extra_args: args.extend(['--platform', 'test']) - if new_results: - args.append('--new-test-results') if not '--child-processes' in extra_args: args.extend(['--child-processes', 1]) @@ -83,10 +81,9 @@ return run_details.exit_code == 0 -def logging_run(extra_args=None, port_obj=None, tests_included=False, host=None, new_results=False, shared_port=True): +def logging_run(extra_args=None, port_obj=None, tests_included=False, host=None, shared_port=True): options, parsed_args = parse_args(extra_args=extra_args, - tests_included=tests_included, - new_results=new_results) + tests_included=tests_included) host = host or MockHost() if not port_obj: port_obj = host.port_factory.get(port_name=options.platform, options=options) @@ -609,7 +606,7 @@ host = MockHost() # Both tests have failing checksum. We include only the first in pixel tests so only that should fail. - args = ['--pixel-tests', '--retry-failures', '--pixel-test-directory', 'failures/unexpected/pixeldir', + args = ['--retry-failures', '--pixel-test-directory', 'failures/unexpected/pixeldir', 'failures/unexpected/pixeldir/image_in_pixeldir.html', 'failures/unexpected/image_not_in_pixeldir.html'] details, _, _ = logging_run(extra_args=args, host=host, tests_included=True) @@ -953,7 +950,7 @@ def test_output_diffs(self): host = MockHost() - logging_run(['--pixel-tests', 'failures/unexpected/text-image-checksum.html'], tests_included=True, host=host) + logging_run(['failures/unexpected/text-image-checksum.html'], tests_included=True, host=host) written_files = host.filesystem.written_files self.assertTrue(any(path.endswith('-diff.txt') for path in written_files.keys())) self.assertTrue(any(path.endswith('-pretty-diff.html') for path in written_files.keys())) @@ -1101,59 +1098,45 @@ # supposed to be. def test_reset_results(self): - # Test that we update expectations in place. If the expectation - # is missing, update the expected generic location. + # Test that we update expectations in place. host = MockHost() details, err, _ = logging_run( - ['--pixel-tests', '--reset-results', 'passes/image.html'], - tests_included=True, host=host, new_results=True) + ['--reset-results', 'failures/unexpected/text-image-checksum.html'], + tests_included=True, host=host) file_list = host.filesystem.written_files.keys() self.assertEqual(details.exit_code, 0) self.assertEqual(len(file_list), 8) - self.assert_baselines(file_list, 'passes/image', ['.txt', '.png'], err) + self.assert_baselines(file_list, 'failures/unexpected/text-image-checksum', ['.txt', '.png'], err) - def test_missing_results(self): - # Test that we update expectations in place. If the expectation - # is missing, update the expected generic location. + def test_reset_missing_results(self): + # Test that we create new baselines at the generic location for missing expectations. host = MockHost() - details, err, _ = logging_run(['--no-show-results', + details, err, _ = logging_run(['--reset-results', '--no-show-results', 'failures/unexpected/missing_text.html', 'failures/unexpected/missing_image.html', 'failures/unexpected/missing_render_tree_dump.html'], - tests_included=True, host=host, new_results=True) - file_list = host.filesystem.written_files.keys() - self.assertEqual(details.exit_code, 3) - self.assertEqual(len(file_list), 12) - self.assert_baselines(file_list, 'failures/unexpected/missing_text', ['.txt'], err) - self.assert_baselines(file_list, 'platform/test/failures/unexpected/missing_image', ['.png'], err) - self.assert_baselines(file_list, 'platform/test/failures/unexpected/missing_render_tree_dump', ['.txt'], err) - - def test_new_baseline(self): - # Test that we update the platform expectations in the version-specific directories - # for both existing and new baselines. - host = MockHost() - details, err, _ = logging_run( - ['--pixel-tests', '--new-baseline', 'failures/unexpected/text-image-checksum.html'], - tests_included=True, host=host, new_results=True) + tests_included=True, host=host) file_list = host.filesystem.written_files.keys() self.assertEqual(details.exit_code, 0) - self.assertEqual(len(file_list), 8) - self.assert_baselines(file_list, - 'platform/test-mac-mac10.10/failures/unexpected/text-image-checksum', - ['.txt', '.png'], err) + self.assertEqual(len(file_list), 9) + self.assert_baselines(file_list, 'failures/unexpected/missing_text', ['.txt'], err) + self.assert_baselines(file_list, 'failures/unexpected/missing_image', ['.png'], err) + self.assert_baselines(file_list, 'failures/unexpected/missing_render_tree_dump', ['.txt'], err) - def test_new_baseline_same_as_fallback(self): + def test_reset_platform_baseline(self): # Test that we update the platform expectations in the version-specific directories # if the new baseline is different from the fallback baseline. host = MockHost() host.filesystem.write_text_file( test.LAYOUT_TEST_DIR + '/failures/unexpected/text-image-checksum-expected.txt', - # Make the fallback baseline the same as the actual result of the test. - # The value is the same as actual_result of the test defined in test.py. + # Make the current text expectation the same as the actual text result of the test. + # The value is the same as actual_result of the test defined in + # webkitpy.layout_tests.port.test. 'text-image-checksum_fail-txt') details, err, _ = logging_run( - ['--pixel-tests', '--new-baseline', 'failures/unexpected/text-image-checksum.html'], - tests_included=True, host=host, new_results=True) + ['--reset-results', '--add-platform-exceptions', + 'failures/unexpected/text-image-checksum.html'], + tests_included=True, host=host) file_list = host.filesystem.written_files.keys() self.assertEqual(details.exit_code, 0) self.assertEqual(len(file_list), 8) @@ -1179,24 +1162,6 @@ self.assertEqual(len(file_list), 6) self.assert_baselines(file_list, 'passes/reftest', ['.txt'], err) - def test_reftest_new_baseline(self): - # Test rebaseline of reftests. - # Should ignore reftests without text expectations. - host = MockHost() - details, err, _ = logging_run(['--new-baseline', 'passes/reftest.html'], tests_included=True, host=host) - file_list = host.filesystem.written_files.keys() - self.assertEqual(details.exit_code, 0) - self.assertEqual(len(file_list), 6) - self.assert_baselines(file_list, '', [], err) - - host.filesystem.write_text_file(test.LAYOUT_TEST_DIR + '/passes/reftest-expected.txt', '') - host.filesystem.clear_written_files() - details, err, _ = logging_run(['--new-baseline', 'passes/reftest.html'], tests_included=True, host=host) - file_list = host.filesystem.written_files.keys() - self.assertEqual(details.exit_code, 0) - self.assertEqual(len(file_list), 6) - self.assert_baselines(file_list, 'platform/test-mac-mac10.10/passes/reftest', ['.txt'], err) - class PortTest(unittest.TestCase):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing.py index 836ceb5..748a78d 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing.py
@@ -81,10 +81,6 @@ if self._options.order == 'random': self._print_default('Using random order with seed: %d' % self._options.seed) - # FIXME: should these options be in printing_options? - if self._options.new_baseline: - self._print_default('Placing new baselines in %s' % self._port.baseline_version_dir()) - fs = self._port.host.filesystem fallback_path = [fs.split(x)[1] for x in self._port.baseline_search_path()] self._print_default('Baseline search path: %s -> generic' % ' -> '.join(fallback_path))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py index 233e2ec..8b33f9dd 100644 --- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py +++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/views/printing_unittest.py
@@ -122,7 +122,6 @@ # FIXME: Make it so these options don't have to be set directly. # pylint: disable=protected-access printer._options.pixel_tests = True - printer._options.new_baseline = True printer._options.time_out_ms = 6000 printer._options.slow_time_out_ms = 12000 printer._options.order = 'random'
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 7a56084..eaae8b92 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -378,6 +378,9 @@ <int value="5" label="Write to minidump failed"/> <int value="6" label="Debug file deletion failed"/> <int value="7" label="Finished writing crash report failed"/> + <int value="8" label="Unclean shutdown"/> + <int value="9" label="Unclean session"/> + <int value="10" label="Collection attempt"/> </enum> <enum name="ActivityTrackerRecordEvent" type="int"> @@ -2969,11 +2972,6 @@ <int value="1" label="Has worked at least once"/> </enum> -<enum name="BooleanExists" type="int"> - <int value="0" label="Does not exist"/> - <int value="1" label="Exists"/> -</enum> - <enum name="BooleanExpired" type="int"> <int value="0" label="Unexpired"/> <int value="1" label="Expired"/> @@ -21953,6 +21951,7 @@ <int value="-1746767834" label="ssl-interstitial-v2-gray"/> <int value="-1740519217" label="disable-software-rasterizer"/> <int value="-1735643253" label="enable-display-list-2d-canvas"/> + <int value="-1734254845" label="ash-enable-night-light"/> <int value="-1732561795" label="ConsistentOmniboxGeolocation:enabled"/> <int value="-1729926412" label="enable-webusb-notifications"/> <int value="-1725507605" label="enable-web-midi"/>
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 5c2f4eb9..3c69344 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -424,6 +424,9 @@ </histogram> <histogram name="ActivityTracker.Collect.UncleanShutdownCount" units="count"> + <obsolete> + Deprecated 05/2017 in favor of ActivityTracker.Collect.Status. + </obsolete> <owner>manzagop@chromium.org</owner> <summary> Number of unclean shutdowns, as derived from the stability instrumentation. @@ -432,6 +435,9 @@ </histogram> <histogram name="ActivityTracker.Collect.UncleanSystemCount" units="count"> + <obsolete> + Deprecated 05/2017 in favor of ActivityTracker.Collect.Status. + </obsolete> <owner>manzagop@chromium.org</owner> <summary> Number of unclean shutdowns that can potentially be attributed to system @@ -62376,14 +62382,6 @@ </summary> </histogram> -<histogram name="SafeBrowsing.V4UnusedStoreFileExists" enum="BooleanExists"> - <owner>vakh@chromium.org</owner> - <summary> - Track the presence of store files that were previously created but have been - deprecated since so need to be removed from disk. Logged once per startup. - </summary> -</histogram> - <histogram name="SafeBrowsing.V4Update.Network.Result" enum="CombinedHttpResponseAndNetErrorCode"> <owner>vakh@chromium.org</owner> @@ -93497,7 +93495,6 @@ name="SafeBrowsing.V4ReadFromDisk.DecodeAdditions.Result"/> <affected-histogram name="SafeBrowsing.V4ReadFromDisk.DecodeAdditions.Time"/> <affected-histogram name="SafeBrowsing.V4ReadFromDisk.MergeUpdate.Time"/> - <affected-histogram name="SafeBrowsing.V4UnusedStoreFileExists"/> </histogram_suffixes> <histogram_suffixes name="SafeBrowsingLists" separator=".">
diff --git a/tools/perf/benchmarks/media.py b/tools/perf/benchmarks/media.py index a985c75..f2d02c4 100644 --- a/tools/perf/benchmarks/media.py +++ b/tools/perf/benchmarks/media.py
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import re + from core import perf_benchmark from telemetry import benchmark @@ -16,6 +18,12 @@ import page_sets +# See tr.v.Numeric.getSummarizedScalarNumericsWithNames() +# https://github.com/catapult-project/catapult/blob/master/tracing/tracing/value/numeric.html#L323 +_IGNORED_STATS_RE = re.compile( + r'(?<!dump)(?<!process)_(std|count|max|min|sum|pct_\d{4}(_\d+)?)$') + + class _MSEMeasurement(legacy_page_test.LegacyPageTest): def __init__(self): @@ -116,6 +124,12 @@ def Name(cls): return 'media.tough_video_cases_tbmv2' + @classmethod + def ValueCanBeAddedPredicate(cls, value, is_first_result): + # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard + # is able to cope with the data load generated by TBMv2 metrics. + return not _IGNORED_STATS_RE.search(value.name) + @benchmark.Owner(emails=['johnchen@chromium.org', 'crouleau@chromium.org'], component='Internals>Media') @@ -149,6 +163,12 @@ ['--ignore-autoplay-restrictions', '--disable-gesture-requirement-for-media-playback']) + @classmethod + def ValueCanBeAddedPredicate(cls, value, is_first_result): + # TODO(crbug.com/610962): Remove this stopgap when the perf dashboard + # is able to cope with the data load generated by TBMv2 metrics. + return not _IGNORED_STATS_RE.search(value.name) + @benchmark.Disabled('all') # crbug/676345 @benchmark.Owner(emails=['crouleau@chromium.org', 'videostack-eng@google.com'],
diff --git a/tools/perf/benchmarks/octane.py b/tools/perf/benchmarks/octane.py index 6245c334..117c0fe 100644 --- a/tools/perf/benchmarks/octane.py +++ b/tools/perf/benchmarks/octane.py
@@ -148,8 +148,10 @@ ps = story.StorySet( archive_data_file='../page_sets/data/octane.json', base_dir=os.path.dirname(os.path.abspath(__file__)), - cloud_storage_bucket=story.PUBLIC_BUCKET) + cloud_storage_bucket=story.PUBLIC_BUCKET, + verify_names=True) ps.AddStory(page_module.Page( 'http://chromium.github.io/octane/index.html?auto=1', - ps, ps.base_dir, make_javascript_deterministic=False)) + ps, ps.base_dir, make_javascript_deterministic=False, + name='http://chromium.github.io/octane/index.html?auto=1')) return ps
diff --git a/tools/perf/page_sets/blink_memory_mobile.py b/tools/perf/page_sets/blink_memory_mobile.py index e6c53c94..68d9766 100644 --- a/tools/perf/page_sets/blink_memory_mobile.py +++ b/tools/perf/page_sets/blink_memory_mobile.py
@@ -92,7 +92,8 @@ def __init__(self): super(BlinkMemoryMobilePageSet, self).__init__( archive_data_file='data/blink_memory_mobile.json', - cloud_storage_bucket=story.PARTNER_BUCKET) + cloud_storage_bucket=story.PARTNER_BUCKET, + verify_names=True) # Why: High rate of Blink's memory consumption rate. self.AddStory(BlinkMemoryMobilePage(
diff --git a/tools/perf/page_sets/google_pages.py b/tools/perf/page_sets/google_pages.py index 6fb0ef4..f20394d 100644 --- a/tools/perf/page_sets/google_pages.py +++ b/tools/perf/page_sets/google_pages.py
@@ -31,7 +31,8 @@ super(GmailPage, self).__init__( url='https://mail.google.com/mail/', page_set=page_set, - shared_page_state_class=shared_page_state_class) + shared_page_state_class=shared_page_state_class, + name='https://mail.google.com/mail/') def RunNavigateSteps(self, action_runner): google_login.LoginGoogleAccount(action_runner, 'google',
diff --git a/tools/perf/page_sets/long_running_idle_google_cases.py b/tools/perf/page_sets/long_running_idle_google_cases.py index 302cddf..559e542 100644 --- a/tools/perf/page_sets/long_running_idle_google_cases.py +++ b/tools/perf/page_sets/long_running_idle_google_cases.py
@@ -35,7 +35,8 @@ def __init__(self): super(LongRunningIdleGmailPageSet, self).__init__( archive_data_file='data/long_running_idle_gmail_page.json', - cloud_storage_bucket=story.PARTNER_BUCKET) + cloud_storage_bucket=story.PARTNER_BUCKET, + verify_names=True) self.AddStory( _CreateIdlePageClass(google_pages.GmailPage)(self)) @@ -45,6 +46,7 @@ # Reuse the wpr of foreground gmail. super(LongRunningIdleGmailBackgroundPageSet, self).__init__( archive_data_file='data/long_running_idle_gmail_page.json', - cloud_storage_bucket=story.PARTNER_BUCKET) + cloud_storage_bucket=story.PARTNER_BUCKET, + verify_names=True) self.AddStory( _CreateIdleBackgroundPageClass(google_pages.GmailPage)(self))
diff --git a/tools/perf/page_sets/memory_top_10_mobile.py b/tools/perf/page_sets/memory_top_10_mobile.py index ceab901..7833d30 100644 --- a/tools/perf/page_sets/memory_top_10_mobile.py +++ b/tools/perf/page_sets/memory_top_10_mobile.py
@@ -68,7 +68,8 @@ def __init__(self): super(MemoryTop10Mobile, self).__init__( archive_data_file='data/memory_top_10_mobile.json', - cloud_storage_bucket=story.PARTNER_BUCKET) + cloud_storage_bucket=story.PARTNER_BUCKET, + verify_names=True) for url in top_10_mobile.URL_LIST: # We name pages so their foreground/background counterparts are easy
diff --git a/tools/perf/page_sets/oopif_basic_page_set.py b/tools/perf/page_sets/oopif_basic_page_set.py index 854b07a9..9276096 100644 --- a/tools/perf/page_sets/oopif_basic_page_set.py +++ b/tools/perf/page_sets/oopif_basic_page_set.py
@@ -13,7 +13,8 @@ def __init__(self, cache_temperatures=None): super(OopifBasicPageSet, self).__init__( archive_data_file='data/oopif_basic.json', - cloud_storage_bucket=story.PARTNER_BUCKET) + cloud_storage_bucket=story.PARTNER_BUCKET, + verify_names=True) if cache_temperatures is None: cache_temperatures = [cache_temperature_module.ANY] @@ -36,4 +37,4 @@ for url in urls: for temp in cache_temperatures: - self.AddStory(page.Page(url, self, cache_temperature=temp)) + self.AddStory(page.Page(url, self, cache_temperature=temp, name=url))
diff --git a/tools/perf/page_sets/oortonline.py b/tools/perf/page_sets/oortonline.py index 6e1f6e8..312f580 100644 --- a/tools/perf/page_sets/oortonline.py +++ b/tools/perf/page_sets/oortonline.py
@@ -24,7 +24,8 @@ url='http://oortonline.gl/#run', page_set=page_set, shared_page_state_class=( webgl_supported_shared_state.WebGLSupportedSharedState), - make_javascript_deterministic=False) + make_javascript_deterministic=False, + name='http://oortonline.gl/#run') self.archive_data_file = 'data/oortonline.json' self.script_to_evaluate_on_commit = STARTUP_SCRIPT @@ -42,7 +43,8 @@ def __init__(self): super(OortOnlinePageSet, self).__init__( archive_data_file='data/oortonline.json', - cloud_storage_bucket=story.PARTNER_BUCKET) + cloud_storage_bucket=story.PARTNER_BUCKET, + verify_names=True) self.AddStory(OortOnlinePage(self)) class OortOnlineTBMPage(OortOnlinePage): @@ -76,5 +78,6 @@ def __init__(self): super(OortOnlineTBMPageSet, self).__init__( archive_data_file='data/oortonline.json', - cloud_storage_bucket=story.PARTNER_BUCKET) + cloud_storage_bucket=story.PARTNER_BUCKET, + verify_names=True) self.AddStory(OortOnlineTBMPage(self))
diff --git a/ui/aura/mus/window_port_mus.cc b/ui/aura/mus/window_port_mus.cc index e550ddb..f47ba8a4d 100644 --- a/ui/aura/mus/window_port_mus.cc +++ b/ui/aura/mus/window_port_mus.cc
@@ -5,6 +5,7 @@ #include "ui/aura/mus/window_port_mus.h" #include "base/memory/ptr_util.h" +#include "components/viz/client/local_surface_id_provider.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/transient_window_client.h" #include "ui/aura/mus/client_surface_embedder.h" @@ -109,7 +110,9 @@ std::move(context_provider), nullptr /* worker_context_provider */, gpu_memory_buffer_manager, nullptr /* shared_bitmap_manager */, nullptr /* synthetic_begin_frame_source */, std::move(sink_info), - std::move(client_request), enable_surface_synchronization); + std::move(client_request), + base::MakeUnique<viz::DefaultLocalSurfaceIdProvider>(), + enable_surface_synchronization); window_tree_client_->AttachCompositorFrameSink( server_id(), std::move(sink_request), std::move(client)); return std::move(compositor_frame_sink);
diff --git a/ui/gfx/codec/jpeg_codec.cc b/ui/gfx/codec/jpeg_codec.cc index 6d926378b..3dc5ad62 100644 --- a/ui/gfx/codec/jpeg_codec.cc +++ b/ui/gfx/codec/jpeg_codec.cc
@@ -43,17 +43,6 @@ } // namespace -// This method helps identify at run time which library chromium is using. -JPEGCodec::LibraryVariant JPEGCodec::JpegLibraryVariant() { -#if defined(USE_SYSTEM_LIBJPEG) - return SYSTEM_LIBJPEG; -#elif defined(USE_LIBJPEG_TURBO) - return LIBJPEG_TURBO; -#else - return IJG_LIBJPEG; -#endif -} - // Encoder --------------------------------------------------------------------- // // This code is based on nsJPEGEncoder from Mozilla. @@ -144,33 +133,6 @@ state->out->resize(state->image_buffer_used); } -#if !defined(JCS_EXTENSIONS) -// Converts RGBA to RGB (removing the alpha values) to prepare to send data to -// libjpeg. This converts one row of data in rgba with the given width in -// pixels the the given rgb destination buffer (which should have enough space -// reserved for the final data). -void StripAlpha(const unsigned char* rgba, int pixel_width, unsigned char* rgb) -{ - for (int x = 0; x < pixel_width; x++) - memcpy(&rgb[x * 3], &rgba[x * 4], 3); -} - -// Converts BGRA to RGB by reordering the color components and dropping the -// alpha. This converts one row of data in rgba with the given width in -// pixels the the given rgb destination buffer (which should have enough space -// reserved for the final data). -void BGRAtoRGB(const unsigned char* bgra, int pixel_width, unsigned char* rgb) -{ - for (int x = 0; x < pixel_width; x++) { - const unsigned char* pixel_in = &bgra[x * 4]; - unsigned char* pixel_out = &rgb[x * 3]; - pixel_out[0] = pixel_in[2]; - pixel_out[1] = pixel_in[1]; - pixel_out[2] = pixel_in[0]; - } -} -#endif // !defined(JCS_EXTENSIONS) - // This class destroys the given jpeg_compress object when it goes out of // scope. It simplifies the error handling in Encode (and even applies to the // success case). @@ -204,9 +166,6 @@ CompressDestroyer destroyer; destroyer.SetManagedObject(&cinfo); output->clear(); -#if !defined(JCS_EXTENSIONS) - unsigned char* row_buffer = NULL; -#endif // We set up the normal JPEG error routines, then override error_exit. // This must be done before the call to create_compress. @@ -222,9 +181,6 @@ // goto using a call to longjmp." So we delete the CompressDestroyer's // object manually instead. destroyer.DestroyManagedObject(); -#if !defined(JCS_EXTENSIONS) - delete[] row_buffer; -#endif return false; } @@ -233,22 +189,16 @@ cinfo.image_width = w; cinfo.image_height = h; - cinfo.input_components = 3; -#ifdef JCS_EXTENSIONS + cinfo.input_components = 4; // Choose an input colorspace and return if it is an unsupported one. Since // libjpeg-turbo supports all input formats used by Chromium (i.e. RGB, RGBA, // and BGRA), we just map the input parameters to a colorspace used by // libjpeg-turbo. - if (format == FORMAT_RGB) { - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - } else if (format == FORMAT_RGBA || - (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { - cinfo.input_components = 4; + if (format == FORMAT_RGBA || + (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { cinfo.in_color_space = JCS_EXT_RGBX; } else if (format == FORMAT_BGRA || (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { - cinfo.input_components = 4; cinfo.in_color_space = JCS_EXT_BGRX; } else { // We can exit this function without calling jpeg_destroy_compress() because @@ -256,9 +206,6 @@ NOTREACHED() << "Invalid pixel format"; return false; } -#else - cinfo.in_color_space = JCS_RGB; -#endif cinfo.data_precision = 8; jpeg_set_defaults(&cinfo); @@ -277,7 +224,6 @@ jpeg_start_compress(&cinfo, 1); // feed it the rows, doing necessary conversions for the color format -#ifdef JCS_EXTENSIONS // This function already returns when the input format is not supported by // libjpeg-turbo and needs conversion. Therefore, we just encode lines without // conversions. @@ -285,37 +231,6 @@ const unsigned char* row = &input[cinfo.next_scanline * row_byte_width]; jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1); } -#else - if (format == FORMAT_RGB) { - // no conversion necessary - while (cinfo.next_scanline < cinfo.image_height) { - const unsigned char* row = &input[cinfo.next_scanline * row_byte_width]; - jpeg_write_scanlines(&cinfo, const_cast<unsigned char**>(&row), 1); - } - } else { - // get the correct format converter - void (*converter)(const unsigned char* in, int w, unsigned char* rgb); - if (format == FORMAT_RGBA || - (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { - converter = StripAlpha; - } else if (format == FORMAT_BGRA || - (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { - converter = BGRAtoRGB; - } else { - NOTREACHED() << "Invalid pixel format"; - return false; - } - - // output row after converting - row_buffer = new unsigned char[w * 3]; - - while (cinfo.next_scanline < cinfo.image_height) { - converter(&input[cinfo.next_scanline * row_byte_width], w, row_buffer); - jpeg_write_scanlines(&cinfo, &row_buffer, 1); - } - delete[] row_buffer; - } -#endif jpeg_finish_compress(&cinfo); return true; @@ -398,31 +313,6 @@ void TermSource(j_decompress_ptr cinfo) { } -#if !defined(JCS_EXTENSIONS) -// Converts one row of rgb data to rgba data by adding a fully-opaque alpha -// value. -void AddAlpha(const unsigned char* rgb, int pixel_width, unsigned char* rgba) { - for (int x = 0; x < pixel_width; x++) { - memcpy(&rgba[x * 4], &rgb[x * 3], 3); - rgba[x * 4 + 3] = 0xff; - } -} - -// Converts one row of RGB data to BGRA by reordering the color components and -// adding alpha values of 0xff. -void RGBtoBGRA(const unsigned char* bgra, int pixel_width, unsigned char* rgb) -{ - for (int x = 0; x < pixel_width; x++) { - const unsigned char* pixel_in = &bgra[x * 3]; - unsigned char* pixel_out = &rgb[x * 4]; - pixel_out[0] = pixel_in[2]; - pixel_out[1] = pixel_in[1]; - pixel_out[2] = pixel_in[0]; - pixel_out[3] = 0xff; - } -} -#endif // !defined(JCS_EXTENSIONS) - // This class destroys the given jpeg_decompress object when it goes out of // scope. It simplifies the error handling in Decode (and even applies to the // success case). @@ -496,16 +386,12 @@ case JCS_GRAYSCALE: case JCS_RGB: case JCS_YCbCr: -#ifdef JCS_EXTENSIONS // Choose an output colorspace and return if it is an unsupported one. // Same as JPEGCodec::Encode(), libjpeg-turbo supports all input formats // used by Chromium (i.e. RGB, RGBA, and BGRA) and we just map the input // parameters to a colorspace. - if (format == FORMAT_RGB) { - cinfo.out_color_space = JCS_RGB; - cinfo.output_components = 3; - } else if (format == FORMAT_RGBA || - (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { + if (format == FORMAT_RGBA || + (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { cinfo.out_color_space = JCS_EXT_RGBX; cinfo.output_components = 4; } else if (format == FORMAT_BGRA || @@ -518,9 +404,6 @@ NOTREACHED() << "Invalid pixel format"; return false; } -#else - cinfo.out_color_space = JCS_RGB; -#endif break; case JCS_CMYK: case JCS_YCCK: @@ -530,9 +413,6 @@ // care about these anyway. return false; } -#ifndef JCS_EXTENSIONS - cinfo.output_components = 3; -#endif jpeg_calc_output_dimensions(&cinfo); *w = cinfo.output_width; @@ -544,7 +424,6 @@ // how to align row lengths as we do for the compressor. int row_read_stride = cinfo.output_width * cinfo.output_components; -#ifdef JCS_EXTENSIONS // Create memory for a decoded image and write decoded lines to the memory // without conversions same as JPEGCodec::Encode(). int row_write_stride = row_read_stride; @@ -555,49 +434,6 @@ if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) return false; } -#else - if (format == FORMAT_RGB) { - // easy case, row needs no conversion - int row_write_stride = row_read_stride; - output->resize(row_write_stride * cinfo.output_height); - - for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { - unsigned char* rowptr = &(*output)[row * row_write_stride]; - if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) - return false; - } - } else { - // Rows need conversion to output format: read into a temporary buffer and - // expand to the final one. Performance: we could avoid the extra - // allocation by doing the expansion in-place. - int row_write_stride; - void (*converter)(const unsigned char* rgb, int w, unsigned char* out); - if (format == FORMAT_RGBA || - (format == FORMAT_SkBitmap && SK_R32_SHIFT == 0)) { - row_write_stride = cinfo.output_width * 4; - converter = AddAlpha; - } else if (format == FORMAT_BGRA || - (format == FORMAT_SkBitmap && SK_B32_SHIFT == 0)) { - row_write_stride = cinfo.output_width * 4; - converter = RGBtoBGRA; - } else { - NOTREACHED() << "Invalid pixel format"; - jpeg_destroy_decompress(&cinfo); - return false; - } - - output->resize(row_write_stride * cinfo.output_height); - - std::unique_ptr<unsigned char[]> row_data( - new unsigned char[row_read_stride]); - unsigned char* rowptr = row_data.get(); - for (int row = 0; row < static_cast<int>(cinfo.output_height); row++) { - if (!jpeg_read_scanlines(&cinfo, &rowptr, 1)) - return false; - converter(rowptr, *w, &(*output)[row * row_write_stride]); - } - } -#endif jpeg_finish_decompress(&cinfo); jpeg_destroy_decompress(&cinfo);
diff --git a/ui/gfx/codec/jpeg_codec.h b/ui/gfx/codec/jpeg_codec.h index 5d10be5..fbc07903 100644 --- a/ui/gfx/codec/jpeg_codec.h +++ b/ui/gfx/codec/jpeg_codec.h
@@ -23,10 +23,6 @@ class CODEC_EXPORT JPEGCodec { public: enum ColorFormat { - // 3 bytes per pixel (packed), in RGB order regardless of endianness. - // This is the native JPEG format. - FORMAT_RGB, - // 4 bytes per pixel, in RGBA order in mem regardless of endianness. FORMAT_RGBA, @@ -39,15 +35,6 @@ FORMAT_SkBitmap }; - enum LibraryVariant { - SYSTEM_LIBJPEG = 0, - LIBJPEG_TURBO, - IJG_LIBJPEG, - }; - - // This method helps identify at run time which library chromium is using. - static LibraryVariant JpegLibraryVariant(); - // Encodes the given raw 'input' data, with each pixel being represented as // given in 'format'. The encoded JPEG data will be written into the supplied // vector and true will be returned on success. On failure (false), the
diff --git a/ui/gfx/codec/jpeg_codec_unittest.cc b/ui/gfx/codec/jpeg_codec_unittest.cc index 8849102e..9c4c8f1 100644 --- a/ui/gfx/codec/jpeg_codec_unittest.cc +++ b/ui/gfx/codec/jpeg_codec_unittest.cc
@@ -88,62 +88,26 @@ return acc / static_cast<double>(a.size()); } -static void MakeRGBImage(int w, int h, std::vector<unsigned char>* dat) { - dat->resize(w * h * 3); +static void MakeRGBAImage(int w, int h, std::vector<unsigned char>* dat) { + dat->resize(w * h * 4); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { - unsigned char* org_px = &(*dat)[(y * w + x) * 3]; + unsigned char* org_px = &(*dat)[(y * w + x) * 4]; org_px[0] = x * 3; // r org_px[1] = x * 3 + 1; // g org_px[2] = x * 3 + 2; // b + org_px[3] = 0xFF; // a } } } -TEST(JPEGCodec, EncodeDecodeRGB) { - int w = 20, h = 20; - - // create an image with known values - std::vector<unsigned char> original; - MakeRGBImage(w, h, &original); - - // encode, making sure it was compressed some - std::vector<unsigned char> encoded; - EXPECT_TRUE(JPEGCodec::Encode(&original[0], JPEGCodec::FORMAT_RGB, w, h, - w * 3, jpeg_quality, &encoded)); - EXPECT_GT(original.size(), encoded.size()); - - // decode, it should have the same size as the original - std::vector<unsigned char> decoded; - int outw, outh; - EXPECT_TRUE(JPEGCodec::Decode(&encoded[0], encoded.size(), - JPEGCodec::FORMAT_RGB, &decoded, - &outw, &outh)); - ASSERT_EQ(w, outw); - ASSERT_EQ(h, outh); - ASSERT_EQ(original.size(), decoded.size()); - - // Images must be approximately equal (compression will have introduced some - // minor artifacts). - ASSERT_GE(jpeg_equality_threshold, AveragePixelDelta(original, decoded)); -} - TEST(JPEGCodec, EncodeDecodeRGBA) { int w = 20, h = 20; // create an image with known values, a must be opaque because it will be // lost during compression std::vector<unsigned char> original; - original.resize(w * h * 4); - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - unsigned char* org_px = &original[(y * w + x) * 4]; - org_px[0] = x * 3; // r - org_px[1] = x * 3 + 1; // g - org_px[2] = x * 3 + 2; // b - org_px[3] = 0xFF; // a (opaque) - } - } + MakeRGBAImage(w, h, &original); // encode, making sure it was compressed some std::vector<unsigned char> encoded; @@ -172,31 +136,31 @@ // some random data (an uncompressed image) std::vector<unsigned char> original; - MakeRGBImage(w, h, &original); + MakeRGBAImage(w, h, &original); // it should fail when given non-JPEG compressed data std::vector<unsigned char> output; int outw, outh; ASSERT_FALSE(JPEGCodec::Decode(&original[0], original.size(), - JPEGCodec::FORMAT_RGB, &output, - &outw, &outh)); + JPEGCodec::FORMAT_RGBA, &output, &outw, + &outh)); // make some compressed data std::vector<unsigned char> compressed; - ASSERT_TRUE(JPEGCodec::Encode(&original[0], JPEGCodec::FORMAT_RGB, w, h, + ASSERT_TRUE(JPEGCodec::Encode(&original[0], JPEGCodec::FORMAT_RGBA, w, h, w * 3, jpeg_quality, &compressed)); // try decompressing a truncated version ASSERT_FALSE(JPEGCodec::Decode(&compressed[0], compressed.size() / 2, - JPEGCodec::FORMAT_RGB, &output, - &outw, &outh)); + JPEGCodec::FORMAT_RGBA, &output, &outw, + &outh)); // corrupt it and try decompressing that for (int i = 10; i < 30; i++) compressed[i] = i; ASSERT_FALSE(JPEGCodec::Decode(&compressed[0], compressed.size(), - JPEGCodec::FORMAT_RGB, &output, - &outw, &outh)); + JPEGCodec::FORMAT_RGBA, &output, &outw, + &outh)); } // Test that we can decode JPEG images without invalid-read errors on valgrind. @@ -207,11 +171,6 @@ int outw, outh; JPEGCodec::Decode(kTopSitesMigrationTestImage, arraysize(kTopSitesMigrationTestImage), - JPEGCodec::FORMAT_RGB, &output, - &outw, &outh); - - JPEGCodec::Decode(kTopSitesMigrationTestImage, - arraysize(kTopSitesMigrationTestImage), JPEGCodec::FORMAT_RGBA, &output, &outw, &outh); }
diff --git a/ui/views/focus/focus_manager.cc b/ui/views/focus/focus_manager.cc index 530da58..b4b827d 100644 --- a/ui/views/focus/focus_manager.cc +++ b/ui/views/focus/focus_manager.cc
@@ -550,12 +550,6 @@ // such that ViewRemoved() is never called. CHECK_EQ(view, focused_view_); SetFocusedView(nullptr); - if (GetStoredFocusView() == view) { - // SetFocusedView() stored |view|. As |view| is being deleting and because - // a ViewObserver was just added, ViewTracker won't get - // OnViewIsDeleting() to properly clean up. Force that cleanup by - SetStoredFocusView(nullptr); - } } } // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc index b1f2574c..09c44ee 100644 --- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc +++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -364,11 +364,18 @@ if (!view_for_activation) { view_for_activation = GetWidget()->GetRootView(); } else if (view_for_activation == focus_manager->GetStoredFocusView()) { - focus_manager->RestoreFocusedView(); - // Set to false if desktop native widget has activated activation - // change, so that aura window activation change focus restore operation - // can be ignored. - restore_focus_on_activate_ = false; + // When desktop native widget has modal transient child, we don't + // restore focused view here, as the modal transient child window will + // get activated and focused. Thus, we are not left with multiple + // focuses. For aura child widgets, since their views are managed by + // |focus_manager|, we then allow restoring focused view. + if (!wm::GetModalTransient(GetWidget()->GetNativeView())) { + focus_manager->RestoreFocusedView(); + // Set to false if desktop native widget has activated activation + // change, so that aura window activation change focus restore + // operation can be ignored. + restore_focus_on_activate_ = false; + } } activation_client->ActivateWindow( view_for_activation->GetWidget()->GetNativeView());
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc index a1e82b4..cd58ae0 100644 --- a/ui/views/widget/widget_interactive_uitest.cc +++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -1271,6 +1271,53 @@ widget->CloseNow(); } +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(OS_WIN) +// TODO(warx): Investigate the flakiness on OS_WIN (crbug.com/729331). +// Tests that when a desktop native widget has modal transient child, it should +// avoid restore focused view itself as the modal transient child window will do +// that, thus avoids having multiple focused view visually (crbug.com/727641). +TEST_F(WidgetTestInteractive, DesktopNativeWidgetWithModalTransientChild) { + // Create a top level desktop native widget. + Widget* top_level = CreateWidget(); + + Textfield* textfield = new Textfield; + textfield->SetBounds(0, 0, 200, 20); + top_level->GetRootView()->AddChildView(textfield); + ShowSync(top_level); + textfield->RequestFocus(); + EXPECT_TRUE(textfield->HasFocus()); + + // Create a modal dialog. + // This instance will be destroyed when the dialog is destroyed. + ModalDialogDelegate* dialog_delegate = + new ModalDialogDelegate(ui::MODAL_TYPE_WINDOW); + Widget* modal_dialog_widget = DialogDelegate::CreateDialogWidget( + dialog_delegate, nullptr, top_level->GetNativeView()); + modal_dialog_widget->SetBounds(gfx::Rect(0, 0, 100, 10)); + Textfield* dialog_textfield = new Textfield; + dialog_textfield->SetBounds(0, 0, 50, 5); + modal_dialog_widget->GetRootView()->AddChildView(dialog_textfield); + // Dialog widget doesn't need a ShowSync as it gains active status + // synchronously. + modal_dialog_widget->Show(); + dialog_textfield->RequestFocus(); + EXPECT_TRUE(dialog_textfield->HasFocus()); + EXPECT_FALSE(textfield->HasFocus()); + + DeactivateSync(top_level); + EXPECT_FALSE(dialog_textfield->HasFocus()); + EXPECT_FALSE(textfield->HasFocus()); + + // After deactivation and activation of top level widget, only modal dialog + // should restore focused view. + ActivateSync(top_level); + EXPECT_TRUE(dialog_textfield->HasFocus()); + EXPECT_FALSE(textfield->HasFocus()); + + top_level->CloseNow(); +} +#endif // defined(USE_AURA) && !defined(OS_CHROMEOS) && !defined(OS_WIN) + namespace { // Helper class for CaptureLostTrackingWidget to store whether