summaryrefslogtreecommitdiff
path: root/chromium/services
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-03 13:42:47 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-05-15 10:27:51 +0000
commit8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec (patch)
treed29d987c4d7b173cf853279b79a51598f104b403 /chromium/services
parent830c9e163d31a9180fadca926b3e1d7dfffb5021 (diff)
downloadqtwebengine-chromium-8c5c43c7b138c9b4b0bf56d946e61d3bbc111bec.tar.gz
BASELINE: Update Chromium to 66.0.3359.156
Change-Id: I0c9831ad39911a086b6377b16f995ad75a51e441 Reviewed-by: Michal Klocek <michal.klocek@qt.io>
Diffstat (limited to 'chromium/services')
-rw-r--r--chromium/services/BUILD.gn18
-rw-r--r--chromium/services/OWNERS1
-rw-r--r--chromium/services/audio/BUILD.gn18
-rw-r--r--chromium/services/audio/DEPS1
-rw-r--r--chromium/services/audio/debug_recording.cc73
-rw-r--r--chromium/services/audio/debug_recording.h51
-rw-r--r--chromium/services/audio/debug_recording_unittest.cc81
-rw-r--r--chromium/services/audio/manifest.json3
-rw-r--r--chromium/services/audio/output_stream.cc238
-rw-r--r--chromium/services/audio/output_stream.h100
-rw-r--r--chromium/services/audio/output_stream_unittest.cc514
-rw-r--r--chromium/services/audio/public/cpp/BUILD.gn24
-rw-r--r--chromium/services/audio/public/cpp/OWNERS4
-rw-r--r--chromium/services/audio/public/cpp/audio_device_description.typemap6
-rw-r--r--chromium/services/audio/public/cpp/audio_device_description_mojom_traits.cc (renamed from chromium/services/audio/public/cpp/audio_device_description_struct_traits.cc)2
-rw-r--r--chromium/services/audio/public/cpp/audio_device_description_mojom_traits.h (renamed from chromium/services/audio/public/cpp/audio_device_description_struct_traits.h)8
-rw-r--r--chromium/services/audio/public/cpp/audio_system_factory.cc18
-rw-r--r--chromium/services/audio/public/cpp/audio_system_factory.h27
-rw-r--r--chromium/services/audio/public/cpp/audio_system_to_service_adapter.cc24
-rw-r--r--chromium/services/audio/public/cpp/audio_system_to_service_adapter.h2
-rw-r--r--chromium/services/audio/public/cpp/debug_recording_session.cc63
-rw-r--r--chromium/services/audio/public/cpp/debug_recording_session.h63
-rw-r--r--chromium/services/audio/public/cpp/debug_recording_session_factory.cc25
-rw-r--r--chromium/services/audio/public/cpp/debug_recording_session_factory.h31
-rw-r--r--chromium/services/audio/public/cpp/fake_system_info.cc74
-rw-r--r--chromium/services/audio/public/cpp/fake_system_info.h64
-rw-r--r--chromium/services/audio/public/mojom/BUILD.gn (renamed from chromium/services/audio/public/interfaces/BUILD.gn)3
-rw-r--r--chromium/services/audio/public/mojom/OWNERS (renamed from chromium/services/device/public/interfaces/OWNERS)4
-rw-r--r--chromium/services/audio/public/mojom/audio_device_description.mojom (renamed from chromium/services/audio/public/interfaces/audio_device_description.mojom)0
-rw-r--r--chromium/services/audio/public/mojom/constants.mojom (renamed from chromium/services/audio/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/audio/public/mojom/debug_recording.mojom29
-rw-r--r--chromium/services/audio/public/mojom/system_info.mojom (renamed from chromium/services/audio/public/interfaces/system_info.mojom)2
-rw-r--r--chromium/services/audio/service.cc23
-rw-r--r--chromium/services/audio/service.h9
-rw-r--r--chromium/services/audio/service_factory.cc19
-rw-r--r--chromium/services/audio/service_factory.h28
-rw-r--r--chromium/services/audio/system_info.h2
-rw-r--r--chromium/services/catalog/BUILD.gn2
-rw-r--r--chromium/services/catalog/catalog.h4
-rw-r--r--chromium/services/catalog/entry.cc2
-rw-r--r--chromium/services/catalog/entry.h2
-rw-r--r--chromium/services/catalog/entry_unittest.cc2
-rw-r--r--chromium/services/catalog/instance.h2
-rw-r--r--chromium/services/catalog/public/cpp/resource_loader.cc2
-rw-r--r--chromium/services/catalog/public/mojom/BUILD.gn (renamed from chromium/services/catalog/public/interfaces/BUILD.gn)2
-rw-r--r--chromium/services/catalog/public/mojom/OWNERS (renamed from chromium/services/catalog/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/catalog/public/mojom/catalog.mojom (renamed from chromium/services/catalog/public/interfaces/catalog.mojom)0
-rw-r--r--chromium/services/catalog/public/mojom/constants.mojom (renamed from chromium/services/catalog/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/data_decoder/BUILD.gn2
-rw-r--r--chromium/services/data_decoder/data_decoder_service.cc11
-rw-r--r--chromium/services/data_decoder/image_decoder_impl.h2
-rw-r--r--chromium/services/data_decoder/image_decoder_impl_unittest.cc15
-rw-r--r--chromium/services/data_decoder/json_parser_impl.h2
-rw-r--r--chromium/services/data_decoder/public/cpp/BUILD.gn2
-rw-r--r--chromium/services/data_decoder/public/cpp/decode_image.cc2
-rw-r--r--chromium/services/data_decoder/public/cpp/decode_image.h2
-rw-r--r--chromium/services/data_decoder/public/cpp/safe_json_parser_impl.cc4
-rw-r--r--chromium/services/data_decoder/public/cpp/safe_json_parser_impl.h2
-rw-r--r--chromium/services/data_decoder/public/cpp/safe_xml_parser.cc6
-rw-r--r--chromium/services/data_decoder/public/mojom/BUILD.gn (renamed from chromium/services/data_decoder/public/interfaces/BUILD.gn)2
-rw-r--r--chromium/services/data_decoder/public/mojom/OWNERS (renamed from chromium/services/data_decoder/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/data_decoder/public/mojom/constants.mojom (renamed from chromium/services/data_decoder/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/data_decoder/public/mojom/image_decoder.mojom (renamed from chromium/services/data_decoder/public/interfaces/image_decoder.mojom)0
-rw-r--r--chromium/services/data_decoder/public/mojom/json_parser.mojom (renamed from chromium/services/data_decoder/public/interfaces/json_parser.mojom)0
-rw-r--r--chromium/services/data_decoder/public/mojom/xml_parser.mojom (renamed from chromium/services/data_decoder/public/interfaces/xml_parser.mojom)0
-rw-r--r--chromium/services/data_decoder/xml_parser.h2
-rw-r--r--chromium/services/device/BUILD.gn20
-rw-r--r--chromium/services/device/battery/BUILD.gn2
-rw-r--r--chromium/services/device/battery/android/BUILD.gn2
-rw-r--r--chromium/services/device/battery/battery_monitor_impl.h2
-rw-r--r--chromium/services/device/battery/battery_monitor_impl_unittest.cc4
-rw-r--r--chromium/services/device/battery/battery_status_manager_linux.cc14
-rw-r--r--chromium/services/device/battery/battery_status_manager_linux.h2
-rw-r--r--chromium/services/device/battery/battery_status_manager_win.h2
-rw-r--r--chromium/services/device/battery/battery_status_service.h2
-rw-r--r--chromium/services/device/device_service.cc9
-rw-r--r--chromium/services/device/device_service.h32
-rw-r--r--chromium/services/device/device_service_test_base.cc5
-rw-r--r--chromium/services/device/device_service_test_base.h2
-rw-r--r--chromium/services/device/fingerprint/BUILD.gn2
-rw-r--r--chromium/services/device/fingerprint/fingerprint.h2
-rw-r--r--chromium/services/device/fingerprint/fingerprint_chromeos.h2
-rw-r--r--chromium/services/device/fingerprint/fingerprint_default.cc2
-rw-r--r--chromium/services/device/generic_sensor/BUILD.gn2
-rw-r--r--chromium/services/device/generic_sensor/README.md2
-rw-r--r--chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.cc2
-rw-r--r--chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.h6
-rw-r--r--chromium/services/device/generic_sensor/generic_sensor_service_unittest.cc49
-rw-r--r--chromium/services/device/generic_sensor/linux/sensor_data_linux.h2
-rw-r--r--chromium/services/device/generic_sensor/linux/sensor_device_manager.h2
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor.h2
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc2
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_fusion.cc20
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_fusion.h1
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_fusion_unittest.cc29
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_base.cc2
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_provider_win.cc18
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_reader_win.cc38
-rw-r--r--chromium/services/device/generic_sensor/platform_sensor_reader_win.h2
-rw-r--r--chromium/services/device/generic_sensor/sensor_impl.h2
-rw-r--r--chromium/services/device/generic_sensor/sensor_provider_impl.cc12
-rw-r--r--chromium/services/device/generic_sensor/sensor_provider_impl.h2
-rw-r--r--chromium/services/device/geolocation/BUILD.gn2
-rw-r--r--chromium/services/device/geolocation/DEPS1
-rw-r--r--chromium/services/device/geolocation/geolocation_service_unittest.cc159
-rw-r--r--chromium/services/device/geolocation/public_ip_address_geolocation_provider.h4
-rw-r--r--chromium/services/device/geolocation/public_ip_address_geolocator.h4
-rw-r--r--chromium/services/device/geolocation/public_ip_address_location_notifier.h2
-rw-r--r--chromium/services/device/geolocation/public_ip_address_location_notifier_unittest.cc2
-rw-r--r--chromium/services/device/hid/BUILD.gn4
-rw-r--r--chromium/services/device/hid/hid_connection.cc2
-rw-r--r--chromium/services/device/hid/hid_connection_impl.h2
-rw-r--r--chromium/services/device/hid/hid_connection_unittest.cc2
-rw-r--r--chromium/services/device/hid/hid_device_info.h2
-rw-r--r--chromium/services/device/hid/hid_manager_impl.h2
-rw-r--r--chromium/services/device/hid/hid_manager_unittest.cc4
-rw-r--r--chromium/services/device/hid/hid_report_descriptor_fuzzer.cc2
-rw-r--r--chromium/services/device/hid/hid_service.h2
-rw-r--r--chromium/services/device/hid/hid_service_unittest.cc2
-rw-r--r--chromium/services/device/hid/hid_service_win.cc2
-rw-r--r--chromium/services/device/hid/input_service_linux.h2
-rw-r--r--chromium/services/device/hid/input_service_linux_unittest.cc2
-rw-r--r--chromium/services/device/manifest.json2
-rw-r--r--chromium/services/device/nfc/android/BUILD.gn4
-rw-r--r--chromium/services/device/power_monitor/BUILD.gn2
-rw-r--r--chromium/services/device/power_monitor/power_monitor_message_broadcaster.h2
-rw-r--r--chromium/services/device/public/cpp/generic_sensor/BUILD.gn2
-rw-r--r--chromium/services/device/public/cpp/generic_sensor/OWNERS4
-rw-r--r--chromium/services/device/public/cpp/generic_sensor/sensor_mojom_traits.cc (renamed from chromium/services/device/public/cpp/generic_sensor/sensor_struct_traits.cc)2
-rw-r--r--chromium/services/device/public/cpp/generic_sensor/sensor_mojom_traits.h (renamed from chromium/services/device/public/cpp/generic_sensor/sensor_struct_traits.h)8
-rw-r--r--chromium/services/device/public/cpp/generic_sensor/sensor_reading.h2
-rw-r--r--chromium/services/device/public/cpp/generic_sensor/sensor_traits.h2
-rw-r--r--chromium/services/device/public/cpp/hid/BUILD.gn2
-rw-r--r--chromium/services/device/public/cpp/hid/fake_input_service_linux.h2
-rw-r--r--chromium/services/device/public/cpp/hid/hid_device_filter.h2
-rw-r--r--chromium/services/device/public/cpp/hid/hid_device_filter_unittest.cc2
-rw-r--r--chromium/services/device/public/cpp/hid/hid_report_descriptor.h2
-rw-r--r--chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc2
-rw-r--r--chromium/services/device/public/cpp/hid/hid_usage_and_page.h2
-rw-r--r--chromium/services/device/public/cpp/power_monitor/BUILD.gn2
-rw-r--r--chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc2
-rw-r--r--chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h2
-rw-r--r--chromium/services/device/public/cpp/test/BUILD.gn2
-rw-r--r--chromium/services/device/public/interfaces/sensor.typemap13
-rw-r--r--chromium/services/device/public/mojom/BUILD.gn (renamed from chromium/services/device/public/interfaces/BUILD.gn)12
-rw-r--r--chromium/services/device/public/mojom/OWNERS (renamed from chromium/services/audio/public/interfaces/OWNERS)4
-rw-r--r--chromium/services/device/public/mojom/README(WakeLock).md (renamed from chromium/services/device/public/interfaces/README(WakeLock).md)0
-rw-r--r--chromium/services/device/public/mojom/battery_monitor.mojom (renamed from chromium/services/device/public/interfaces/battery_monitor.mojom)2
-rw-r--r--chromium/services/device/public/mojom/battery_status.mojom (renamed from chromium/services/device/public/interfaces/battery_status.mojom)0
-rw-r--r--chromium/services/device/public/mojom/constants.mojom (renamed from chromium/services/device/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/device/public/mojom/fingerprint.mojom (renamed from chromium/services/device/public/interfaces/fingerprint.mojom)0
-rw-r--r--chromium/services/device/public/mojom/geolocation.mojom30
-rw-r--r--chromium/services/device/public/mojom/geolocation_config.mojom (renamed from chromium/services/device/public/interfaces/geolocation_config.mojom)0
-rw-r--r--chromium/services/device/public/mojom/geolocation_context.mojom (renamed from chromium/services/device/public/interfaces/geolocation_context.mojom)4
-rw-r--r--chromium/services/device/public/mojom/geolocation_control.mojom (renamed from chromium/services/device/public/interfaces/geolocation_control.mojom)0
-rw-r--r--chromium/services/device/public/mojom/geoposition.mojom60
-rw-r--r--chromium/services/device/public/mojom/hid.mojom (renamed from chromium/services/device/public/interfaces/hid.mojom)0
-rw-r--r--chromium/services/device/public/mojom/input_service.mojom (renamed from chromium/services/device/public/interfaces/input_service.mojom)0
-rw-r--r--chromium/services/device/public/mojom/nfc.mojom (renamed from chromium/services/device/public/interfaces/nfc.mojom)0
-rw-r--r--chromium/services/device/public/mojom/nfc_provider.mojom (renamed from chromium/services/device/public/interfaces/nfc_provider.mojom)2
-rw-r--r--chromium/services/device/public/mojom/power_monitor.mojom (renamed from chromium/services/device/public/interfaces/power_monitor.mojom)0
-rw-r--r--chromium/services/device/public/mojom/public_ip_address_geolocation_provider.mojom (renamed from chromium/services/device/public/interfaces/public_ip_address_geolocation_provider.mojom)4
-rw-r--r--chromium/services/device/public/mojom/screen_orientation.mojom35
-rw-r--r--chromium/services/device/public/mojom/screen_orientation_lock_types.mojom31
-rw-r--r--chromium/services/device/public/mojom/sensor.mojom (renamed from chromium/services/device/public/interfaces/sensor.mojom)0
-rw-r--r--chromium/services/device/public/mojom/sensor.typemap15
-rw-r--r--chromium/services/device/public/mojom/sensor_provider.mojom (renamed from chromium/services/device/public/interfaces/sensor_provider.mojom)15
-rw-r--r--chromium/services/device/public/mojom/serial.mojom (renamed from chromium/services/device/public/interfaces/serial.mojom)0
-rw-r--r--chromium/services/device/public/mojom/time_zone_monitor.mojom (renamed from chromium/services/device/public/interfaces/time_zone_monitor.mojom)0
-rw-r--r--chromium/services/device/public/mojom/typemaps.gni (renamed from chromium/services/device/public/interfaces/typemaps.gni)2
-rw-r--r--chromium/services/device/public/mojom/vibration_manager.mojom (renamed from chromium/services/device/public/interfaces/vibration_manager.mojom)0
-rw-r--r--chromium/services/device/public/mojom/wake_lock.mojom (renamed from chromium/services/device/public/interfaces/wake_lock.mojom)0
-rw-r--r--chromium/services/device/public/mojom/wake_lock_context.mojom (renamed from chromium/services/device/public/interfaces/wake_lock_context.mojom)2
-rw-r--r--chromium/services/device/public/mojom/wake_lock_provider.mojom (renamed from chromium/services/device/public/interfaces/wake_lock_provider.mojom)4
-rw-r--r--chromium/services/device/screen_orientation/BUILD.gn2
-rw-r--r--chromium/services/device/screen_orientation/OWNERS4
-rw-r--r--chromium/services/device/screen_orientation/screen_orientation_listener_android.h2
-rw-r--r--chromium/services/device/serial/BUILD.gn2
-rw-r--r--chromium/services/device/serial/serial_device_enumerator_impl.h2
-rw-r--r--chromium/services/device/serial/serial_device_enumerator_impl_unittest.cc4
-rw-r--r--chromium/services/device/serial/serial_io_handler_impl.h2
-rw-r--r--chromium/services/device/serial/serial_io_handler_impl_unittest.cc4
-rw-r--r--chromium/services/device/time_zone_monitor/BUILD.gn2
-rw-r--r--chromium/services/device/time_zone_monitor/time_zone_monitor.h2
-rw-r--r--chromium/services/device/unittest_manifest.json3
-rw-r--r--chromium/services/device/vibration/BUILD.gn2
-rw-r--r--chromium/services/device/vibration/android/BUILD.gn2
-rw-r--r--chromium/services/device/vibration/vibration_manager_impl.h2
-rw-r--r--chromium/services/device/vibration/vibration_manager_impl_unittest.cc4
-rw-r--r--chromium/services/device/wake_lock/BUILD.gn2
-rw-r--r--chromium/services/device/wake_lock/power_save_blocker/BUILD.gn2
-rw-r--r--chromium/services/device/wake_lock/power_save_blocker/power_save_blocker.h2
-rw-r--r--chromium/services/device/wake_lock/power_save_blocker/power_save_blocker_x11.cc31
-rw-r--r--chromium/services/device/wake_lock/wake_lock.h4
-rw-r--r--chromium/services/device/wake_lock/wake_lock_context.h2
-rw-r--r--chromium/services/device/wake_lock/wake_lock_for_testing.h4
-rw-r--r--chromium/services/device/wake_lock/wake_lock_provider.h4
-rw-r--r--chromium/services/device/wake_lock/wake_lock_unittest.cc8
-rw-r--r--chromium/services/file/BUILD.gn4
-rw-r--r--chromium/services/file/file_service.h2
-rw-r--r--chromium/services/file/file_system.h2
-rw-r--r--chromium/services/file/public/mojom/BUILD.gn (renamed from chromium/services/file/public/interfaces/BUILD.gn)2
-rw-r--r--chromium/services/file/public/mojom/OWNERS (renamed from chromium/services/file/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/file/public/mojom/constants.mojom (renamed from chromium/services/file/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/file/public/mojom/file_system.mojom (renamed from chromium/services/file/public/interfaces/file_system.mojom)0
-rw-r--r--chromium/services/identity/BUILD.gn6
-rw-r--r--chromium/services/identity/DEPS1
-rw-r--r--chromium/services/identity/identity_manager_impl.cc2
-rw-r--r--chromium/services/identity/identity_manager_impl.h2
-rw-r--r--chromium/services/identity/identity_manager_impl_unittest.cc6
-rw-r--r--chromium/services/identity/identity_service.h2
-rw-r--r--chromium/services/identity/public/cpp/BUILD.gn2
-rw-r--r--chromium/services/identity/public/cpp/OWNERS4
-rw-r--r--chromium/services/identity/public/cpp/account_info.typemap6
-rw-r--r--chromium/services/identity/public/cpp/account_info_mojom_traits.cc (renamed from chromium/services/identity/public/cpp/account_info_struct_traits.cc)2
-rw-r--r--chromium/services/identity/public/cpp/account_info_mojom_traits.h (renamed from chromium/services/identity/public/cpp/account_info_struct_traits.h)8
-rw-r--r--chromium/services/identity/public/cpp/account_state.typemap6
-rw-r--r--chromium/services/identity/public/cpp/account_state_mojom_traits.cc (renamed from chromium/services/identity/public/cpp/account_state_struct_traits.cc)2
-rw-r--r--chromium/services/identity/public/cpp/account_state_mojom_traits.h (renamed from chromium/services/identity/public/cpp/account_state_struct_traits.h)8
-rw-r--r--chromium/services/identity/public/cpp/google_service_auth_error.typemap8
-rw-r--r--chromium/services/identity/public/cpp/google_service_auth_error_mojom_traits.cc (renamed from chromium/services/identity/public/cpp/google_service_auth_error_struct_traits.cc)4
-rw-r--r--chromium/services/identity/public/cpp/google_service_auth_error_mojom_traits.h (renamed from chromium/services/identity/public/cpp/google_service_auth_error_struct_traits.h)8
-rw-r--r--chromium/services/identity/public/cpp/identity_manager.cc47
-rw-r--r--chromium/services/identity/public/cpp/identity_manager.h65
-rw-r--r--chromium/services/identity/public/cpp/identity_manager_unittest.cc130
-rw-r--r--chromium/services/identity/public/cpp/identity_test_environment.cc24
-rw-r--r--chromium/services/identity/public/cpp/identity_test_environment.h23
-rw-r--r--chromium/services/identity/public/cpp/identity_test_utils.cc117
-rw-r--r--chromium/services/identity/public/cpp/identity_test_utils.h53
-rw-r--r--chromium/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc13
-rw-r--r--chromium/services/identity/public/cpp/scope_set.typemap4
-rw-r--r--chromium/services/identity/public/cpp/scope_set_mojom_traits.h (renamed from chromium/services/identity/public/cpp/scope_set_struct_traits.h)6
-rw-r--r--chromium/services/identity/public/mojom/BUILD.gn (renamed from chromium/services/identity/public/interfaces/BUILD.gn)4
-rw-r--r--chromium/services/identity/public/mojom/OWNERS (renamed from chromium/services/identity/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/identity/public/mojom/account.mojom (renamed from chromium/services/identity/public/interfaces/account.mojom)4
-rw-r--r--chromium/services/identity/public/mojom/account_info.mojom (renamed from chromium/services/identity/public/interfaces/account_info.mojom)0
-rw-r--r--chromium/services/identity/public/mojom/account_state.mojom (renamed from chromium/services/identity/public/interfaces/account_state.mojom)0
-rw-r--r--chromium/services/identity/public/mojom/constants.mojom (renamed from chromium/services/identity/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/identity/public/mojom/google_service_auth_error.mojom (renamed from chromium/services/identity/public/interfaces/google_service_auth_error.mojom)2
-rw-r--r--chromium/services/identity/public/mojom/identity_manager.mojom (renamed from chromium/services/identity/public/interfaces/identity_manager.mojom)10
-rw-r--r--chromium/services/identity/public/mojom/scope_set.mojom (renamed from chromium/services/identity/public/interfaces/scope_set.mojom)0
-rw-r--r--chromium/services/metrics/BUILD.gn2
-rw-r--r--chromium/services/metrics/public/cpp/BUILD.gn16
-rw-r--r--chromium/services/metrics/public/cpp/delegating_ukm_recorder.h2
-rw-r--r--chromium/services/metrics/public/cpp/metrics_utils.cc23
-rw-r--r--chromium/services/metrics/public/cpp/metrics_utils.h8
-rw-r--r--chromium/services/metrics/public/cpp/metrics_utils_unittest.cc63
-rw-r--r--chromium/services/metrics/public/cpp/mojo_ukm_recorder.cc2
-rw-r--r--chromium/services/metrics/public/cpp/mojo_ukm_recorder.h2
-rw-r--r--chromium/services/metrics/public/cpp/ukm_entry_builder.cc2
-rw-r--r--chromium/services/metrics/public/cpp/ukm_entry_builder.h2
-rw-r--r--chromium/services/metrics/public/cpp/ukm_entry_builder_base.cc2
-rw-r--r--chromium/services/metrics/public/cpp/ukm_entry_builder_base.h2
-rw-r--r--chromium/services/metrics/public/cpp/ukm_recorder.h15
-rw-r--r--chromium/services/metrics/public/mojom/BUILD.gn (renamed from chromium/services/metrics/public/interfaces/BUILD.gn)4
-rw-r--r--chromium/services/metrics/public/mojom/OWNERS (renamed from chromium/services/metrics/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/metrics/public/mojom/constants.mojom (renamed from chromium/services/metrics/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/metrics/public/mojom/ukm_interface.mojom (renamed from chromium/services/metrics/public/interfaces/ukm_interface.mojom)2
-rw-r--r--chromium/services/metrics/ukm_recorder_interface.h2
-rw-r--r--chromium/services/network/BUILD.gn154
-rw-r--r--chromium/services/network/DEPS11
-rw-r--r--chromium/services/network/OWNERS13
-rw-r--r--chromium/services/network/PRESUBMIT.py22
-rw-r--r--chromium/services/network/cookie_manager.cc147
-rw-r--r--chromium/services/network/cookie_manager.h58
-rw-r--r--chromium/services/network/cookie_manager_unittest.cc293
-rw-r--r--chromium/services/network/cors/cors_url_loader_unittest.cc262
-rw-r--r--chromium/services/network/cors/preflight_controller.cc96
-rw-r--r--chromium/services/network/cors/preflight_controller.h39
-rw-r--r--chromium/services/network/cors/preflight_controller_unittest.cc108
-rw-r--r--chromium/services/network/data_pipe_element_reader.cc130
-rw-r--r--chromium/services/network/data_pipe_element_reader.h88
-rw-r--r--chromium/services/network/data_pipe_element_reader_unittest.cc228
-rw-r--r--chromium/services/network/http_server_properties_pref_delegate.cc54
-rw-r--r--chromium/services/network/http_server_properties_pref_delegate.h44
-rw-r--r--chromium/services/network/ignore_errors_cert_verifier.cc137
-rw-r--r--chromium/services/network/ignore_errors_cert_verifier.h79
-rw-r--r--chromium/services/network/ignore_errors_cert_verifier_unittest.cc199
-rw-r--r--chromium/services/network/keepalive_statistics_recorder.cc95
-rw-r--r--chromium/services/network/keepalive_statistics_recorder.h65
-rw-r--r--chromium/services/network/keepalive_statistics_recorder_unittest.cc185
-rw-r--r--chromium/services/network/loader_util.cc (renamed from chromium/services/network/public/cpp/loader_util.cc)2
-rw-r--r--chromium/services/network/loader_util.h (renamed from chromium/services/network/public/cpp/loader_util.h)14
-rw-r--r--chromium/services/network/manifest.json23
-rw-r--r--chromium/services/network/network_change_manager.cc67
-rw-r--r--chromium/services/network/network_change_manager.h64
-rw-r--r--chromium/services/network/network_change_manager_unittest.cc220
-rw-r--r--chromium/services/network/network_context.cc476
-rw-r--r--chromium/services/network/network_context.h174
-rw-r--r--chromium/services/network/network_context_unittest.cc784
-rw-r--r--chromium/services/network/network_sandbox_hook_linux.cc38
-rw-r--r--chromium/services/network/network_sandbox_hook_linux.h18
-rw-r--r--chromium/services/network/network_service.cc224
-rw-r--r--chromium/services/network/network_service.h148
-rw-r--r--chromium/services/network/network_service_unittest.cc469
-rw-r--r--chromium/services/network/proxy_config_service_mojo.h12
-rw-r--r--chromium/services/network/proxy_config_service_mojo_unittest.cc6
-rw-r--r--chromium/services/network/proxy_resolver_factory_mojo.cc377
-rw-r--r--chromium/services/network/proxy_resolver_factory_mojo.h64
-rw-r--r--chromium/services/network/proxy_resolver_factory_mojo_unittest.cc916
-rw-r--r--chromium/services/network/proxy_resolving_client_socket.cc (renamed from chromium/services/network/public/cpp/proxy_resolving_client_socket.cc)132
-rw-r--r--chromium/services/network/proxy_resolving_client_socket.h (renamed from chromium/services/network/public/cpp/proxy_resolving_client_socket.h)40
-rw-r--r--chromium/services/network/proxy_resolving_client_socket_factory.cc89
-rw-r--r--chromium/services/network/proxy_resolving_client_socket_factory.h56
-rw-r--r--chromium/services/network/proxy_resolving_client_socket_unittest.cc (renamed from chromium/services/network/public/cpp/proxy_resolving_client_socket_unittest.cc)357
-rw-r--r--chromium/services/network/proxy_service_mojo.cc50
-rw-r--r--chromium/services/network/proxy_service_mojo.h50
-rw-r--r--chromium/services/network/public/cpp/BUILD.gn69
-rw-r--r--chromium/services/network/public/cpp/DEPS12
-rw-r--r--chromium/services/network/public/cpp/OWNERS4
-rw-r--r--chromium/services/network/public/cpp/cookie_manager.typemap6
-rw-r--r--chromium/services/network/public/cpp/cookie_manager_mojom_traits.cc (renamed from chromium/services/network/public/cpp/cookie_manager_struct_traits.cc)2
-rw-r--r--chromium/services/network/public/cpp/cookie_manager_mojom_traits.h (renamed from chromium/services/network/public/cpp/cookie_manager_struct_traits.h)8
-rw-r--r--chromium/services/network/public/cpp/cors/cors.cc147
-rw-r--r--chromium/services/network/public/cpp/cors/cors.h36
-rw-r--r--chromium/services/network/public/cpp/cors/cors_error_status.h5
-rw-r--r--chromium/services/network/public/cpp/cors/cors_legacy.cc42
-rw-r--r--chromium/services/network/public/cpp/cors/cors_legacy.h41
-rw-r--r--chromium/services/network/public/cpp/cors/cors_unittest.cc106
-rw-r--r--chromium/services/network/public/cpp/cors/cors_url_loader.cc237
-rw-r--r--chromium/services/network/public/cpp/cors/cors_url_loader.h102
-rw-r--r--chromium/services/network/public/cpp/cors/cors_url_loader_factory.cc45
-rw-r--r--chromium/services/network/public/cpp/cors/cors_url_loader_factory.h54
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_cache.cc68
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_cache.h66
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_cache_unittest.cc116
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_result.cc212
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_result.h100
-rw-r--r--chromium/services/network/public/cpp/cors/preflight_result_unittest.cc245
-rw-r--r--chromium/services/network/public/cpp/cors_error_status.typemap4
-rw-r--r--chromium/services/network/public/cpp/data_element.cc37
-rw-r--r--chromium/services/network/public/cpp/data_element.h34
-rw-r--r--chromium/services/network/public/cpp/features.cc27
-rw-r--r--chromium/services/network/public/cpp/features.h28
-rw-r--r--chromium/services/network/public/cpp/http_raw_request_response_info.h5
-rw-r--r--chromium/services/network/public/cpp/http_request_headers.typemap8
-rw-r--r--chromium/services/network/public/cpp/http_request_headers_mojom_traits.cc (renamed from chromium/services/network/public/cpp/http_request_headers_struct_traits.cc)2
-rw-r--r--chromium/services/network/public/cpp/http_request_headers_mojom_traits.h (renamed from chromium/services/network/public/cpp/http_request_headers_struct_traits.h)8
-rw-r--r--chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag.typemap4
-rw-r--r--chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_mojom_traits.h (renamed from chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_struct_traits.h)8
-rw-r--r--chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_mojom_traits_unittest.cc (renamed from chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_struct_traits_unittest.cc)4
-rw-r--r--chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag.typemap4
-rw-r--r--chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_mojom_traits.h (renamed from chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_struct_traits.h)8
-rw-r--r--chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_mojom_traits_unittest.cc (renamed from chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_struct_traits_unittest.cc)4
-rw-r--r--chromium/services/network/public/cpp/net_adapters.h17
-rw-r--r--chromium/services/network/public/cpp/network_mojom_traits_unittest.cc (renamed from chromium/services/network/public/cpp/network_struct_traits_unittest.cc)2
-rw-r--r--chromium/services/network/public/cpp/network_param.typemap7
-rw-r--r--chromium/services/network/public/cpp/network_param_ipc_traits.cc148
-rw-r--r--chromium/services/network/public/cpp/network_param_ipc_traits.h91
-rw-r--r--chromium/services/network/public/cpp/network_switches.cc22
-rw-r--r--chromium/services/network/public/cpp/network_switches.h18
-rw-r--r--chromium/services/network/public/cpp/network_traits_test_service.mojom2
-rw-r--r--chromium/services/network/public/cpp/network_types.typemap4
-rw-r--r--chromium/services/network/public/cpp/proxy_config.typemap14
-rw-r--r--chromium/services/network/public/cpp/proxy_config_mojom_traits.cc (renamed from chromium/services/network/public/cpp/proxy_config_traits.cc)31
-rw-r--r--chromium/services/network/public/cpp/proxy_config_mojom_traits.h (renamed from chromium/services/network/public/cpp/proxy_config_traits.h)44
-rw-r--r--chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc (renamed from chromium/services/network/public/cpp/proxy_config_traits_unittest.cc)14
-rw-r--r--chromium/services/network/public/cpp/resource_request.h16
-rw-r--r--chromium/services/network/public/cpp/resource_request_body.cc10
-rw-r--r--chromium/services/network/public/cpp/resource_request_body.h8
-rw-r--r--chromium/services/network/public/cpp/resource_response.cc2
-rw-r--r--chromium/services/network/public/cpp/resource_response.h7
-rw-r--r--chromium/services/network/public/cpp/resource_response_info.cc4
-rw-r--r--chromium/services/network/public/cpp/resource_response_info.h19
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader.cc1499
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader.h279
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader_stream_consumer.h71
-rw-r--r--chromium/services/network/public/cpp/simple_url_loader_unittest.cc2614
-rw-r--r--chromium/services/network/public/cpp/url_loader_completion_status.h5
-rw-r--r--chromium/services/network/public/cpp/url_loader_completion_status.typemap4
-rw-r--r--chromium/services/network/public/cpp/url_request.typemap6
-rw-r--r--chromium/services/network/public/cpp/url_request_mojom_traits.cc (renamed from chromium/services/network/public/cpp/url_request_struct_traits.cc)2
-rw-r--r--chromium/services/network/public/cpp/url_request_mojom_traits.h (renamed from chromium/services/network/public/cpp/url_request_struct_traits.h)12
-rw-r--r--chromium/services/network/public/cpp/url_request_redirect_info.typemap2
-rw-r--r--chromium/services/network/public/cpp/url_response_head.typemap4
-rw-r--r--chromium/services/network/public/mojom/BUILD.gn (renamed from chromium/services/network/public/interfaces/BUILD.gn)33
-rw-r--r--chromium/services/network/public/mojom/OWNERS (renamed from chromium/services/network/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/network/public/mojom/cookie_manager.mojom (renamed from chromium/services/network/public/interfaces/cookie_manager.mojom)35
-rw-r--r--chromium/services/network/public/mojom/cors.mojom (renamed from chromium/services/network/public/interfaces/cors.mojom)15
-rw-r--r--chromium/services/network/public/mojom/data_pipe_getter.mojom (renamed from chromium/services/network/public/interfaces/data_pipe_getter.mojom)0
-rw-r--r--chromium/services/network/public/mojom/fetch_api.mojom (renamed from chromium/services/network/public/interfaces/fetch_api.mojom)0
-rw-r--r--chromium/services/network/public/mojom/http_request_headers.mojom (renamed from chromium/services/network/public/interfaces/http_request_headers.mojom)0
-rw-r--r--chromium/services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom (renamed from chromium/services/network/public/interfaces/mutable_network_traffic_annotation_tag.mojom)0
-rw-r--r--chromium/services/network/public/mojom/mutable_partial_network_traffic_annotation_tag.mojom (renamed from chromium/services/network/public/interfaces/mutable_partial_network_traffic_annotation_tag.mojom)0
-rw-r--r--chromium/services/network/public/mojom/network_change_manager.mojom (renamed from chromium/services/network/public/interfaces/network_change_manager.mojom)0
-rw-r--r--chromium/services/network/public/mojom/network_service.mojom (renamed from chromium/services/network/public/interfaces/network_service.mojom)71
-rw-r--r--chromium/services/network/public/mojom/network_service_test.mojom (renamed from chromium/services/network/public/interfaces/network_service_test.mojom)0
-rw-r--r--chromium/services/network/public/mojom/network_types.mojom (renamed from chromium/services/network/public/interfaces/network_types.mojom)0
-rw-r--r--chromium/services/network/public/mojom/proxy_config.mojom (renamed from chromium/services/network/public/interfaces/proxy_config.mojom)10
-rw-r--r--chromium/services/network/public/mojom/request_context_frame_type.mojom (renamed from chromium/services/network/public/interfaces/request_context_frame_type.mojom)0
-rw-r--r--chromium/services/network/public/mojom/restricted_cookie_manager.mojom (renamed from chromium/services/network/public/interfaces/restricted_cookie_manager.mojom)2
-rw-r--r--chromium/services/network/public/mojom/udp_socket.mojom198
-rw-r--r--chromium/services/network/public/mojom/url_loader.mojom (renamed from chromium/services/network/public/interfaces/url_loader.mojom)31
-rw-r--r--chromium/services/network/public/mojom/url_loader_factory.mojom (renamed from chromium/services/network/public/interfaces/url_loader_factory.mojom)0
-rw-r--r--chromium/services/network/resource_scheduler.cc1311
-rw-r--r--chromium/services/network/resource_scheduler.h300
-rw-r--r--chromium/services/network/resource_scheduler_client.cc45
-rw-r--r--chromium/services/network/resource_scheduler_client.h55
-rw-r--r--chromium/services/network/resource_scheduler_unittest.cc2014
-rw-r--r--chromium/services/network/restricted_cookie_manager.cc131
-rw-r--r--chromium/services/network/restricted_cookie_manager.h73
-rw-r--r--chromium/services/network/restricted_cookie_manager_unittest.cc240
-rw-r--r--chromium/services/network/throttling/network_conditions.cc30
-rw-r--r--chromium/services/network/throttling/network_conditions.h46
-rw-r--r--chromium/services/network/throttling/throttling_controller.cc76
-rw-r--r--chromium/services/network/throttling/throttling_controller.h54
-rw-r--r--chromium/services/network/throttling/throttling_controller_unittest.cc327
-rw-r--r--chromium/services/network/throttling/throttling_network_interceptor.cc288
-rw-r--r--chromium/services/network/throttling/throttling_network_interceptor.h110
-rw-r--r--chromium/services/network/throttling/throttling_network_transaction.cc321
-rw-r--r--chromium/services/network/throttling/throttling_network_transaction.h136
-rw-r--r--chromium/services/network/throttling/throttling_network_transaction_factory.cc46
-rw-r--r--chromium/services/network/throttling/throttling_network_transaction_factory.h45
-rw-r--r--chromium/services/network/throttling/throttling_upload_data_stream.cc95
-rw-r--r--chromium/services/network/throttling/throttling_upload_data_stream.h55
-rw-r--r--chromium/services/network/udp_socket.cc428
-rw-r--r--chromium/services/network/udp_socket.h176
-rw-r--r--chromium/services/network/udp_socket_factory.cc40
-rw-r--r--chromium/services/network/udp_socket_factory.h41
-rw-r--r--chromium/services/network/udp_socket_factory_unittest.cc63
-rw-r--r--chromium/services/network/udp_socket_test_util.cc198
-rw-r--r--chromium/services/network/udp_socket_test_util.h85
-rw-r--r--chromium/services/network/udp_socket_unittest.cc747
-rw-r--r--chromium/services/network/upload_progress_tracker.cc89
-rw-r--r--chromium/services/network/upload_progress_tracker.h70
-rw-r--r--chromium/services/network/upload_progress_tracker_unittest.cc279
-rw-r--r--chromium/services/network/url_loader.cc847
-rw-r--r--chromium/services/network/url_loader.h180
-rw-r--r--chromium/services/network/url_loader_factory.cc74
-rw-r--r--chromium/services/network/url_loader_factory.h59
-rw-r--r--chromium/services/network/url_loader_unittest.cc1411
-rw-r--r--chromium/services/network/url_request_context_builder_mojo.cc72
-rw-r--r--chromium/services/network/url_request_context_builder_mojo.h79
-rw-r--r--chromium/services/network/url_request_context_owner.cc62
-rw-r--r--chromium/services/network/url_request_context_owner.h58
-rw-r--r--chromium/services/preferences/BUILD.gn4
-rw-r--r--chromium/services/preferences/persistent_pref_store_impl.h4
-rw-r--r--chromium/services/preferences/persistent_pref_store_impl_unittest.cc2
-rw-r--r--chromium/services/preferences/pref_service_factory_unittest.cc5
-rw-r--r--chromium/services/preferences/pref_store_consistency_unittest.cc9
-rw-r--r--chromium/services/preferences/pref_store_impl.h2
-rw-r--r--chromium/services/preferences/pref_store_impl_unittest.cc2
-rw-r--r--chromium/services/preferences/pref_store_manager_impl.cc1
-rw-r--r--chromium/services/preferences/pref_store_manager_impl.h2
-rw-r--r--chromium/services/preferences/public/cpp/BUILD.gn2
-rw-r--r--chromium/services/preferences/public/cpp/OWNERS4
-rw-r--r--chromium/services/preferences/public/cpp/persistent_pref_store_client.h2
-rw-r--r--chromium/services/preferences/public/cpp/pref_registry_serializer.h2
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_factory.cc8
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_factory.h2
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_main.cc1
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client.h2
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client_mixin.h2
-rw-r--r--chromium/services/preferences/public/cpp/preferences.typemap6
-rw-r--r--chromium/services/preferences/public/cpp/preferences_mojom_traits.cc (renamed from chromium/services/preferences/public/cpp/preferences_struct_traits.cc)2
-rw-r--r--chromium/services/preferences/public/cpp/preferences_mojom_traits.h (renamed from chromium/services/preferences/public/cpp/preferences_struct_traits.h)8
-rw-r--r--chromium/services/preferences/public/cpp/tests/BUILD.gn2
-rw-r--r--chromium/services/preferences/public/cpp/tracked/BUILD.gn4
-rw-r--r--chromium/services/preferences/public/cpp/tracked/configuration.h2
-rw-r--r--chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h4
-rw-r--r--chromium/services/preferences/public/mojom/BUILD.gn (renamed from chromium/services/preferences/public/interfaces/BUILD.gn)2
-rw-r--r--chromium/services/preferences/public/mojom/OWNERS (renamed from chromium/services/preferences/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/preferences/public/mojom/preferences.mojom (renamed from chromium/services/preferences/public/interfaces/preferences.mojom)6
-rw-r--r--chromium/services/preferences/public/mojom/tracked_preference_validation_delegate.mojom (renamed from chromium/services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom)0
-rw-r--r--chromium/services/preferences/scoped_pref_connection_builder.h2
-rw-r--r--chromium/services/preferences/shared_pref_registry.h2
-rw-r--r--chromium/services/preferences/tracked/BUILD.gn2
-rw-r--r--chromium/services/preferences/tracked/pref_hash_filter.h2
-rw-r--r--chromium/services/preferences/tracked/pref_hash_store_transaction.h2
-rw-r--r--chromium/services/preferences/tracked/segregated_pref_store.h2
-rw-r--r--chromium/services/preferences/tracked/tracked_atomic_preference.cc2
-rw-r--r--chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc2
-rw-r--r--chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h2
-rw-r--r--chromium/services/preferences/tracked/tracked_split_preference.cc2
-rw-r--r--chromium/services/proxy_resolver/BUILD.gn2
-rw-r--r--chromium/services/proxy_resolver/OWNERS2
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_factory_impl.cc6
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_factory_impl.h2
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_factory_impl_unittest.cc4
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_impl.cc8
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_impl.h4
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_impl_unittest.cc8
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_service.cc5
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_service.h2
-rw-r--r--chromium/services/proxy_resolver/proxy_resolver_service_unittest.cc2
-rw-r--r--chromium/services/proxy_resolver/public/cpp/OWNERS4
-rw-r--r--chromium/services/proxy_resolver/public/cpp/proxy_resolver.typemap10
-rw-r--r--chromium/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc (renamed from chromium/services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.cc)6
-rw-r--r--chromium/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h (renamed from chromium/services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.h)14
-rw-r--r--chromium/services/proxy_resolver/public/mojom/BUILD.gn (renamed from chromium/services/proxy_resolver/public/interfaces/BUILD.gn)4
-rw-r--r--chromium/services/proxy_resolver/public/mojom/OWNERS (renamed from chromium/services/proxy_resolver/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/proxy_resolver/public/mojom/proxy_resolver.mojom (renamed from chromium/services/proxy_resolver/public/interfaces/proxy_resolver.mojom)2
-rw-r--r--chromium/services/resource_coordinator/BUILD.gn14
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.cc8
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.h6
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/coordination_unit_base_unittest.cc2
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.h2
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h2
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.cc4
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h7
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc55
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h27
-rw-r--r--chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc55
-rw-r--r--chromium/services/resource_coordinator/manifest.json6
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc229
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h43
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc138
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/process_map.cc6
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/process_map.h2
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/process_map_unittest.cc2
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/queued_request.cc28
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/queued_request.h43
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc91
-rw-r--r--chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.h12
-rw-r--r--chromium/services/resource_coordinator/observers/coordination_unit_graph_observer.h2
-rw-r--r--chromium/services/resource_coordinator/observers/coordination_unit_graph_observer_unittest.cc2
-rw-r--r--chromium/services/resource_coordinator/observers/page_signal_generator_impl.cc204
-rw-r--r--chromium/services/resource_coordinator/observers/page_signal_generator_impl.h84
-rw-r--r--chromium/services/resource_coordinator/observers/page_signal_generator_impl_unittest.cc162
-rw-r--r--chromium/services/resource_coordinator/public/cpp/BUILD.gn4
-rw-r--r--chromium/services/resource_coordinator/public/cpp/OWNERS4
-rw-r--r--chromium/services/resource_coordinator/public/cpp/coordination_unit.typemap11
-rw-r--r--chromium/services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.cc (renamed from chromium/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.cc)2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.h (renamed from chromium/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h)14
-rw-r--r--chromium/services/resource_coordinator/public/cpp/frame_resource_coordinator.h2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/OWNERS4
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc9
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.cc6
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h6
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap8
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.cc (renamed from chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.cc)11
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h (renamed from chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.h)29
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits_unittest.cc (renamed from chromium/services/resource_coordinator/public/cpp/memory_instrumentation/struct_traits_unittest.cc)4
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc1
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc6
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.cc4
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.cc6
-rw-r--r--chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.h3
-rw-r--r--chromium/services/resource_coordinator/public/cpp/process_resource_coordinator.h2
-rw-r--r--chromium/services/resource_coordinator/public/cpp/resource_coordinator_interface.h4
-rw-r--r--chromium/services/resource_coordinator/public/cpp/tracing/OWNERS2
-rw-r--r--chromium/services/resource_coordinator/public/mojom/BUILD.gn (renamed from chromium/services/resource_coordinator/public/interfaces/BUILD.gn)15
-rw-r--r--chromium/services/resource_coordinator/public/mojom/OWNERS (renamed from chromium/services/resource_coordinator/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/resource_coordinator/public/mojom/coordination_unit.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/coordination_unit.mojom)1
-rw-r--r--chromium/services/resource_coordinator/public/mojom/coordination_unit_introspector.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom)0
-rw-r--r--chromium/services/resource_coordinator/public/mojom/coordination_unit_provider.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom)0
-rw-r--r--chromium/services/resource_coordinator/public/mojom/memory_instrumentation/OWNERS (renamed from chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/OWNERS)0
-rw-r--r--chromium/services/resource_coordinator/public/mojom/memory_instrumentation/constants.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/constants.mojom)0
-rw-r--r--chromium/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom)59
-rw-r--r--chromium/services/resource_coordinator/public/mojom/page_signal.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/page_signal.mojom)0
-rw-r--r--chromium/services/resource_coordinator/public/mojom/service_constants.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/service_constants.mojom)0
-rw-r--r--chromium/services/resource_coordinator/public/mojom/signals.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/signals.mojom)2
-rw-r--r--chromium/services/resource_coordinator/resource_coordinator_service.cc19
-rw-r--r--chromium/services/resource_coordinator/resource_coordinator_service.h6
-rw-r--r--chromium/services/resource_coordinator/resource_coordinator_service_unittest.cc4
-rw-r--r--chromium/services/resource_coordinator/tracing/BUILD.gn20
-rw-r--r--chromium/services/resource_coordinator/tracing/OWNER1
-rw-r--r--chromium/services/service_manager/BUILD.gn4
-rw-r--r--chromium/services/service_manager/README.md6
-rw-r--r--chromium/services/service_manager/background/background_service_manager.h4
-rw-r--r--chromium/services/service_manager/background/tests/BUILD.gn2
-rw-r--r--chromium/services/service_manager/connect_params.h4
-rw-r--r--chromium/services/service_manager/connect_util.cc8
-rw-r--r--chromium/services/service_manager/connect_util.h2
-rw-r--r--chromium/services/service_manager/embedder/BUILD.gn2
-rw-r--r--chromium/services/service_manager/embedder/embedded_instance_manager_unittest.cc3
-rw-r--r--chromium/services/service_manager/embedder/embedded_service_runner.h2
-rw-r--r--chromium/services/service_manager/embedder/main.cc5
-rw-r--r--chromium/services/service_manager/public/cpp/BUILD.gn8
-rw-r--r--chromium/services/service_manager/public/cpp/OWNERS4
-rw-r--r--chromium/services/service_manager/public/cpp/bind_source_info.typemap4
-rw-r--r--chromium/services/service_manager/public/cpp/bind_source_info_mojom_traits.h (renamed from chromium/services/service_manager/public/cpp/bind_source_info_struct_traits.h)5
-rw-r--r--chromium/services/service_manager/public/cpp/connect.h2
-rw-r--r--chromium/services/service_manager/public/cpp/connector.cc19
-rw-r--r--chromium/services/service_manager/public/cpp/connector.h28
-rw-r--r--chromium/services/service_manager/public/cpp/identity.cc2
-rw-r--r--chromium/services/service_manager/public/cpp/identity.typemap4
-rw-r--r--chromium/services/service_manager/public/cpp/identity_mojom_traits.h (renamed from chromium/services/service_manager/public/cpp/identity_struct_traits.h)5
-rw-r--r--chromium/services/service_manager/public/cpp/interface_provider.cc2
-rw-r--r--chromium/services/service_manager/public/cpp/interface_provider.h24
-rw-r--r--chromium/services/service_manager/public/cpp/interface_provider_spec.h2
-rw-r--r--chromium/services/service_manager/public/cpp/interface_provider_spec.typemap5
-rw-r--r--chromium/services/service_manager/public/cpp/interface_provider_spec_mojom_traits.h (renamed from chromium/services/service_manager/public/cpp/interface_provider_spec_struct_traits.h)13
-rw-r--r--chromium/services/service_manager/public/cpp/service_context.cc5
-rw-r--r--chromium/services/service_manager/public/cpp/service_context.h17
-rw-r--r--chromium/services/service_manager/public/cpp/service_context_ref.cc4
-rw-r--r--chromium/services/service_manager/public/cpp/service_context_ref.h4
-rw-r--r--chromium/services/service_manager/public/cpp/standalone_service/BUILD.gn2
-rw-r--r--chromium/services/service_manager/public/cpp/standalone_service/main.cc9
-rw-r--r--chromium/services/service_manager/public/cpp/standalone_service/standalone_service.h2
-rw-r--r--chromium/services/service_manager/public/cpp/standalone_service/switches.h5
-rw-r--r--chromium/services/service_manager/public/cpp/test/BUILD.gn2
-rw-r--r--chromium/services/service_manager/public/java/BUILD.gn2
-rw-r--r--chromium/services/service_manager/public/mojom/BUILD.gn (renamed from chromium/services/service_manager/public/interfaces/BUILD.gn)2
-rw-r--r--chromium/services/service_manager/public/mojom/OWNERS (renamed from chromium/services/resource_coordinator/public/interfaces/tracing/OWNERS)0
-rw-r--r--chromium/services/service_manager/public/mojom/connector.mojom (renamed from chromium/services/service_manager/public/interfaces/connector.mojom)4
-rw-r--r--chromium/services/service_manager/public/mojom/constants.mojom (renamed from chromium/services/service_manager/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/service_manager/public/mojom/interface_provider.mojom (renamed from chromium/services/service_manager/public/interfaces/interface_provider.mojom)0
-rw-r--r--chromium/services/service_manager/public/mojom/interface_provider_spec.mojom (renamed from chromium/services/service_manager/public/interfaces/interface_provider_spec.mojom)0
-rw-r--r--chromium/services/service_manager/public/mojom/service.mojom (renamed from chromium/services/service_manager/public/interfaces/service.mojom)8
-rw-r--r--chromium/services/service_manager/public/mojom/service_control.mojom (renamed from chromium/services/service_manager/public/interfaces/service_control.mojom)0
-rw-r--r--chromium/services/service_manager/public/mojom/service_factory.mojom (renamed from chromium/services/service_manager/public/interfaces/service_factory.mojom)4
-rw-r--r--chromium/services/service_manager/public/mojom/service_manager.mojom (renamed from chromium/services/service_manager/public/interfaces/service_manager.mojom)2
-rw-r--r--chromium/services/service_manager/public/service_manifest.gni2
-rwxr-xr-xchromium/services/service_manager/public/tools/manifest/manifest_collator.py12
-rw-r--r--chromium/services/service_manager/runner/common/BUILD.gn2
-rw-r--r--chromium/services/service_manager/runner/common/client_util.h2
-rw-r--r--chromium/services/service_manager/runner/host/service_process_launcher.h2
-rw-r--r--chromium/services/service_manager/sandbox/linux/bpf_broker_policy_linux.cc2
-rw-r--r--chromium/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc15
-rw-r--r--chromium/services/service_manager/sandbox/linux/sandbox_linux.cc15
-rw-r--r--chromium/services/service_manager/sandbox/linux/sandbox_linux.h13
-rw-r--r--chromium/services/service_manager/sandbox/mac/cdm.sb3
-rw-r--r--chromium/services/service_manager/sandbox/mac/common_v2.sb2
-rw-r--r--chromium/services/service_manager/sandbox/mac/gpu_v2.sb6
-rw-r--r--chromium/services/service_manager/sandbox/mac/ppapi_v2.sb19
-rw-r--r--chromium/services/service_manager/sandbox/mac/renderer.sb2
-rw-r--r--chromium/services/service_manager/sandbox/sandbox_delegate.h6
-rw-r--r--chromium/services/service_manager/sandbox/switches.cc12
-rw-r--r--chromium/services/service_manager/sandbox/switches.h4
-rw-r--r--chromium/services/service_manager/sandbox/win/sandbox_win.cc117
-rw-r--r--chromium/services/service_manager/sandbox/win/sandbox_win.h15
-rw-r--r--chromium/services/service_manager/service_manager.cc12
-rw-r--r--chromium/services/service_manager/service_manager.h10
-rw-r--r--chromium/services/service_manager/tests/BUILD.gn4
-rw-r--r--chromium/services/service_manager/tests/connect/BUILD.gn10
-rw-r--r--chromium/services/service_manager/tests/connect/connect_test.mojom2
-rw-r--r--chromium/services/service_manager/tests/lifecycle/BUILD.gn6
-rw-r--r--chromium/services/service_manager/tests/sandbox/BUILD.gn5
-rw-r--r--chromium/services/service_manager/tests/service_manager/BUILD.gn6
-rw-r--r--chromium/services/service_manager/tests/service_manager/service_manager_unittest.mojom2
-rw-r--r--chromium/services/service_manager/tests/shutdown/BUILD.gn6
-rw-r--r--chromium/services/shape_detection/BUILD.gn11
-rw-r--r--chromium/services/shape_detection/barcode_detection_impl.h2
-rw-r--r--chromium/services/shape_detection/barcode_detection_impl_mac.h2
-rw-r--r--chromium/services/shape_detection/detection_utils_mac.h2
-rw-r--r--chromium/services/shape_detection/detection_utils_win.h3
-rw-r--r--chromium/services/shape_detection/face_detection_impl_mac.h2
-rw-r--r--chromium/services/shape_detection/face_detection_impl_mac.mm10
-rw-r--r--chromium/services/shape_detection/face_detection_impl_win.h2
-rw-r--r--chromium/services/shape_detection/face_detection_impl_win_unittest.cc2
-rw-r--r--chromium/services/shape_detection/face_detection_provider_impl.h2
-rw-r--r--chromium/services/shape_detection/face_detection_provider_mac.h34
-rw-r--r--chromium/services/shape_detection/face_detection_provider_mac.mm34
-rw-r--r--chromium/services/shape_detection/face_detection_provider_win.h2
-rw-r--r--chromium/services/shape_detection/public/mojom/BUILD.gn (renamed from chromium/services/shape_detection/public/interfaces/BUILD.gn)2
-rw-r--r--chromium/services/shape_detection/public/mojom/OWNERS (renamed from chromium/services/service_manager/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/shape_detection/public/mojom/barcodedetection.mojom (renamed from chromium/services/shape_detection/public/interfaces/barcodedetection.mojom)0
-rw-r--r--chromium/services/shape_detection/public/mojom/constants.mojom (renamed from chromium/services/shape_detection/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/shape_detection/public/mojom/facedetection.mojom (renamed from chromium/services/shape_detection/public/interfaces/facedetection.mojom)0
-rw-r--r--chromium/services/shape_detection/public/mojom/facedetection_provider.mojom (renamed from chromium/services/shape_detection/public/interfaces/facedetection_provider.mojom)0
-rw-r--r--chromium/services/shape_detection/public/mojom/textdetection.mojom (renamed from chromium/services/shape_detection/public/interfaces/textdetection.mojom)0
-rw-r--r--chromium/services/shape_detection/shape_detection_service.cc13
-rw-r--r--chromium/services/shape_detection/text_detection_impl.h2
-rw-r--r--chromium/services/shape_detection/text_detection_impl_mac.h2
-rw-r--r--chromium/services/shape_detection/text_detection_impl_win.h2
-rw-r--r--chromium/services/shape_detection/text_detection_impl_win_unittest.cc2
-rw-r--r--chromium/services/test/BUILD.gn38
-rw-r--r--chromium/services/test/echo/BUILD.gn4
-rw-r--r--chromium/services/test/echo/public/mojom/BUILD.gn (renamed from chromium/services/test/echo/public/interfaces/BUILD.gn)2
-rw-r--r--chromium/services/test/echo/public/mojom/echo.mojom (renamed from chromium/services/test/echo/public/interfaces/echo.mojom)0
-rw-r--r--chromium/services/test/user_id/BUILD.gn4
-rw-r--r--chromium/services/test/user_id/public/mojom/BUILD.gn (renamed from chromium/services/test/user_id/public/interfaces/BUILD.gn)2
-rw-r--r--chromium/services/test/user_id/public/mojom/user_id.mojom (renamed from chromium/services/test/user_id/public/interfaces/user_id.mojom)0
-rw-r--r--chromium/services/tracing/BUILD.gn92
-rw-r--r--chromium/services/tracing/DEPS3
-rw-r--r--chromium/services/tracing/OWNERS8
-rw-r--r--chromium/services/tracing/agent_registry.cc (renamed from chromium/services/resource_coordinator/tracing/agent_registry.cc)27
-rw-r--r--chromium/services/tracing/agent_registry.h (renamed from chromium/services/resource_coordinator/tracing/agent_registry.h)18
-rw-r--r--chromium/services/tracing/agent_registry_unittest.cc (renamed from chromium/services/resource_coordinator/tracing/agent_registry_unittest.cc)12
-rw-r--r--chromium/services/tracing/coordinator.cc (renamed from chromium/services/resource_coordinator/tracing/coordinator.cc)15
-rw-r--r--chromium/services/tracing/coordinator.h (renamed from chromium/services/resource_coordinator/tracing/coordinator.h)16
-rw-r--r--chromium/services/tracing/coordinator_unittest.cc (renamed from chromium/services/resource_coordinator/tracing/coordinator_unittest.cc)14
-rw-r--r--chromium/services/tracing/manifest.json21
-rw-r--r--chromium/services/tracing/public/cpp/BUILD.gn22
-rw-r--r--chromium/services/tracing/public/cpp/base_agent.cc57
-rw-r--r--chromium/services/tracing/public/cpp/base_agent.h51
-rw-r--r--chromium/services/tracing/public/cpp/chrome_trace_event_agent.cc (renamed from chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent.cc)30
-rw-r--r--chromium/services/tracing/public/cpp/chrome_trace_event_agent.h (renamed from chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent.h)19
-rw-r--r--chromium/services/tracing/public/cpp/chrome_trace_event_agent_unittest.cc (renamed from chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent_unittest.cc)8
-rw-r--r--chromium/services/tracing/public/mojom/BUILD.gn22
-rw-r--r--chromium/services/tracing/public/mojom/OWNERS (renamed from chromium/services/shape_detection/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/tracing/public/mojom/constants.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/tracing/tracing_constants.mojom)2
-rw-r--r--chromium/services/tracing/public/mojom/tracing.mojom (renamed from chromium/services/resource_coordinator/public/interfaces/tracing/tracing.mojom)0
-rw-r--r--chromium/services/tracing/recorder.cc (renamed from chromium/services/resource_coordinator/tracing/recorder.cc)6
-rw-r--r--chromium/services/tracing/recorder.h (renamed from chromium/services/resource_coordinator/tracing/recorder.h)19
-rw-r--r--chromium/services/tracing/recorder_unittest.cc (renamed from chromium/services/resource_coordinator/tracing/recorder_unittest.cc)4
-rw-r--r--chromium/services/tracing/service_main.cc12
-rw-r--r--chromium/services/tracing/test_util.cc (renamed from chromium/services/resource_coordinator/tracing/test_util.cc)4
-rw-r--r--chromium/services/tracing/test_util.h (renamed from chromium/services/resource_coordinator/tracing/test_util.h)8
-rw-r--r--chromium/services/tracing/tracing_service.cc47
-rw-r--r--chromium/services/tracing/tracing_service.h58
-rw-r--r--chromium/services/tracing/tracing_service_unittest.cc52
-rw-r--r--chromium/services/tracing/unittest_manifest.json11
-rw-r--r--chromium/services/ui/BUILD.gn2
-rw-r--r--chromium/services/ui/common/BUILD.gn12
-rw-r--r--chromium/services/ui/common/switches.cc4
-rw-r--r--chromium/services/ui/common/switches.h1
-rw-r--r--chromium/services/ui/common/types.h4
-rw-r--r--chromium/services/ui/common/util.h16
-rw-r--r--chromium/services/ui/demo/BUILD.gn1
-rw-r--r--chromium/services/ui/demo/mus_demo_unittests.cc11
-rw-r--r--chromium/services/ui/ime/ime_unittest.cc2
-rw-r--r--chromium/services/ui/manifest.json3
-rw-r--r--chromium/services/ui/public/cpp/BUILD.gn12
-rw-r--r--chromium/services/ui/public/cpp/gpu/BUILD.gn1
-rw-r--r--chromium/services/ui/public/cpp/gpu/command_buffer_metrics.cc1
-rw-r--r--chromium/services/ui/public/cpp/gpu/context_provider_command_buffer.cc3
-rw-r--r--chromium/services/ui/public/cpp/gpu/gpu.cc1
-rw-r--r--chromium/services/ui/public/cpp/input_devices/input_device_controller.cc6
-rw-r--r--chromium/services/ui/public/cpp/input_devices/input_device_controller.h4
-rw-r--r--chromium/services/ui/public/interfaces/BUILD.gn5
-rw-r--r--chromium/services/ui/public/interfaces/ime/ime.mojom15
-rw-r--r--chromium/services/ui/public/interfaces/ime/ime_struct_traits.cc1
-rw-r--r--chromium/services/ui/public/interfaces/ime/ime_struct_traits.h25
-rw-r--r--chromium/services/ui/public/interfaces/ime/ime_struct_traits_unittest.cc1
-rw-r--r--chromium/services/ui/public/interfaces/user_access_manager.mojom11
-rw-r--r--chromium/services/ui/public/interfaces/window_manager.mojom42
-rw-r--r--chromium/services/ui/public/interfaces/window_manager_constants.mojom4
-rw-r--r--chromium/services/ui/public/interfaces/window_tree.mojom164
-rw-r--r--chromium/services/ui/public/interfaces/window_tree_constants.mojom6
-rw-r--r--chromium/services/ui/service.cc108
-rw-r--r--chromium/services/ui/service.h33
-rw-r--r--chromium/services/ui/ws/BUILD.gn19
-rw-r--r--chromium/services/ui/ws/access_policy_delegate.h7
-rw-r--r--chromium/services/ui/ws/accessibility_manager.cc7
-rw-r--r--chromium/services/ui/ws/accessibility_manager.h4
-rw-r--r--chromium/services/ui/ws/compositor_frame_sink_client_binding.cc11
-rw-r--r--chromium/services/ui/ws/compositor_frame_sink_client_binding.h3
-rw-r--r--chromium/services/ui/ws/cursor_state_unittest.cc8
-rw-r--r--chromium/services/ui/ws/cursor_unittest.cc16
-rw-r--r--chromium/services/ui/ws/debug_utils.cc2
-rw-r--r--chromium/services/ui/ws/default_access_policy.cc2
-rw-r--r--chromium/services/ui/ws/display.cc168
-rw-r--r--chromium/services/ui/ws/display.h57
-rw-r--r--chromium/services/ui/ws/display_binding.cc6
-rw-r--r--chromium/services/ui/ws/display_binding.h3
-rw-r--r--chromium/services/ui/ws/display_manager.cc105
-rw-r--r--chromium/services/ui/ws/display_manager.h44
-rw-r--r--chromium/services/ui/ws/display_unittest.cc211
-rw-r--r--chromium/services/ui/ws/drag_controller.cc37
-rw-r--r--chromium/services/ui/ws/drag_controller.h11
-rw-r--r--chromium/services/ui/ws/drag_controller_unittest.cc19
-rw-r--r--chromium/services/ui/ws/drag_source.h3
-rw-r--r--chromium/services/ui/ws/event_dispatcher.cc2
-rw-r--r--chromium/services/ui/ws/event_dispatcher_unittest.cc201
-rw-r--r--chromium/services/ui/ws/event_targeter.cc6
-rw-r--r--chromium/services/ui/ws/focus_controller_unittest.cc16
-rw-r--r--chromium/services/ui/ws/frame_generator_unittest.cc5
-rw-r--r--chromium/services/ui/ws/gpu_host.cc41
-rw-r--r--chromium/services/ui/ws/gpu_host.h13
-rw-r--r--chromium/services/ui/ws/gpu_host_unittest.cc6
-rw-r--r--chromium/services/ui/ws/ids.h69
-rw-r--r--chromium/services/ui/ws/modal_window_controller_unittest.cc22
-rw-r--r--chromium/services/ui/ws/server_window.cc40
-rw-r--r--chromium/services/ui/ws/server_window.h29
-rw-r--r--chromium/services/ui/ws/server_window_drawn_tracker_unittest.cc34
-rw-r--r--chromium/services/ui/ws/test_change_tracker.cc5
-rw-r--r--chromium/services/ui/ws/test_change_tracker.h3
-rw-r--r--chromium/services/ui/ws/test_utils.cc103
-rw-r--r--chromium/services/ui/ws/test_utils.h95
-rw-r--r--chromium/services/ui/ws/threaded_image_cursors.cc27
-rw-r--r--chromium/services/ui/ws/threaded_image_cursors.h4
-rw-r--r--chromium/services/ui/ws/transient_windows_unittest.cc44
-rw-r--r--chromium/services/ui/ws/user_display_manager.cc10
-rw-r--r--chromium/services/ui/ws/user_display_manager.h7
-rw-r--r--chromium/services/ui/ws/user_display_manager_delegate.h9
-rw-r--r--chromium/services/ui/ws/user_display_manager_unittest.cc59
-rw-r--r--chromium/services/ui/ws/user_id.h22
-rw-r--r--chromium/services/ui/ws/user_id_tracker.cc71
-rw-r--r--chromium/services/ui/ws/user_id_tracker.h62
-rw-r--r--chromium/services/ui/ws/user_id_tracker_observer.h29
-rw-r--r--chromium/services/ui/ws/window_coordinate_conversions_unittest.cc6
-rw-r--r--chromium/services/ui/ws/window_finder.cc20
-rw-r--r--chromium/services/ui/ws/window_finder_unittest.cc78
-rw-r--r--chromium/services/ui/ws/window_manager_access_policy.cc2
-rw-r--r--chromium/services/ui/ws/window_manager_client_unittest.cc21
-rw-r--r--chromium/services/ui/ws/window_manager_display_root.cc6
-rw-r--r--chromium/services/ui/ws/window_manager_state.cc97
-rw-r--r--chromium/services/ui/ws/window_manager_state.h18
-rw-r--r--chromium/services/ui/ws/window_manager_state_unittest.cc54
-rw-r--r--chromium/services/ui/ws/window_manager_window_tree_factory.cc53
-rw-r--r--chromium/services/ui/ws/window_manager_window_tree_factory.h31
-rw-r--r--chromium/services/ui/ws/window_manager_window_tree_factory_observer.h (renamed from chromium/services/ui/ws/window_manager_window_tree_factory_set_observer.h)12
-rw-r--r--chromium/services/ui/ws/window_manager_window_tree_factory_set.cc92
-rw-r--r--chromium/services/ui/ws/window_manager_window_tree_factory_set.h86
-rw-r--r--chromium/services/ui/ws/window_server.cc133
-rw-r--r--chromium/services/ui/ws/window_server.h60
-rw-r--r--chromium/services/ui/ws/window_server_test_base.cc5
-rw-r--r--chromium/services/ui/ws/window_server_test_base.h3
-rw-r--r--chromium/services/ui/ws/window_tree.cc220
-rw-r--r--chromium/services/ui/ws/window_tree.h45
-rw-r--r--chromium/services/ui/ws/window_tree_client_unittest.cc217
-rw-r--r--chromium/services/ui/ws/window_tree_factory.cc5
-rw-r--r--chromium/services/ui/ws/window_tree_factory.h3
-rw-r--r--chromium/services/ui/ws/window_tree_host_factory.cc10
-rw-r--r--chromium/services/ui/ws/window_tree_host_factory.h4
-rw-r--r--chromium/services/ui/ws/window_tree_unittest.cc187
-rw-r--r--chromium/services/ui/ws2/OWNERS4
-rw-r--r--chromium/services/ui/ws2/ids.h100
-rw-r--r--chromium/services/ui/ws2/test_change_tracker.cc503
-rw-r--r--chromium/services/ui/ws2/test_change_tracker.h210
-rw-r--r--chromium/services/ui/ws2/test_manifest.json22
-rw-r--r--chromium/services/ui/ws2/window_tree_client_unittest.cc2525
-rw-r--r--chromium/services/video_capture/BUILD.gn11
-rw-r--r--chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc12
-rw-r--r--chromium/services/video_capture/device_factory_media_to_mojo_adapter.h2
-rw-r--r--chromium/services/video_capture/device_factory_provider_impl.cc5
-rw-r--r--chromium/services/video_capture/device_factory_provider_impl.h2
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter.cc16
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter.h6
-rw-r--r--chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc115
-rw-r--r--chromium/services/video_capture/public/cpp/BUILD.gn4
-rw-r--r--chromium/services/video_capture/public/cpp/constants.cc20
-rw-r--r--chromium/services/video_capture/public/cpp/constants.h16
-rw-r--r--chromium/services/video_capture/public/cpp/device_to_feedback_observer_adapter.h2
-rw-r--r--chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h2
-rw-r--r--chromium/services/video_capture/public/mojom/BUILD.gn (renamed from chromium/services/video_capture/public/interfaces/BUILD.gn)4
-rw-r--r--chromium/services/video_capture/public/mojom/OWNERS (renamed from chromium/services/video_capture/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/video_capture/public/mojom/constants.mojom (renamed from chromium/services/video_capture/public/interfaces/constants.mojom)0
-rw-r--r--chromium/services/video_capture/public/mojom/device.mojom (renamed from chromium/services/video_capture/public/interfaces/device.mojom)2
-rw-r--r--chromium/services/video_capture/public/mojom/device_factory.mojom (renamed from chromium/services/video_capture/public/interfaces/device_factory.mojom)6
-rw-r--r--chromium/services/video_capture/public/mojom/device_factory_provider.mojom (renamed from chromium/services/video_capture/public/interfaces/device_factory_provider.mojom)2
-rw-r--r--chromium/services/video_capture/public/mojom/producer.mojom (renamed from chromium/services/video_capture/public/interfaces/producer.mojom)0
-rw-r--r--chromium/services/video_capture/public/mojom/receiver.mojom (renamed from chromium/services/video_capture/public/interfaces/receiver.mojom)0
-rw-r--r--chromium/services/video_capture/public/mojom/testing_controls.mojom (renamed from chromium/services/video_capture/public/interfaces/testing_controls.mojom)0
-rw-r--r--chromium/services/video_capture/public/mojom/virtual_device.mojom (renamed from chromium/services/video_capture/public/interfaces/virtual_device.mojom)2
-rw-r--r--chromium/services/video_capture/receiver_mojo_to_media_adapter.cc4
-rw-r--r--chromium/services/video_capture/receiver_mojo_to_media_adapter.h4
-rw-r--r--chromium/services/video_capture/scoped_access_permission_media_to_mojo_adapter.h2
-rw-r--r--chromium/services/video_capture/service_impl.cc15
-rw-r--r--chromium/services/video_capture/service_impl.h6
-rw-r--r--chromium/services/video_capture/testing_controls_impl.h2
-rw-r--r--chromium/services/video_capture/virtual_device_enabled_device_factory.h6
-rw-r--r--chromium/services/video_capture/virtual_device_mojo_adapter.cc2
-rw-r--r--chromium/services/video_capture/virtual_device_mojo_adapter.h6
-rw-r--r--chromium/services/viz/privileged/interfaces/BUILD.gn3
-rw-r--r--chromium/services/viz/privileged/interfaces/compositing/BUILD.gn2
-rw-r--r--chromium/services/viz/privileged/interfaces/compositing/display_private.mojom12
-rw-r--r--chromium/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom18
-rw-r--r--chromium/services/viz/privileged/interfaces/compositing/renderer_settings.mojom4
-rw-r--r--chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc3
-rw-r--r--chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h9
-rw-r--r--chromium/services/viz/privileged/interfaces/gl/BUILD.gn2
-rw-r--r--chromium/services/viz/privileged/interfaces/gl/gpu_host.mojom2
-rw-r--r--chromium/services/viz/privileged/interfaces/struct_traits_unittest.cc14
-rw-r--r--chromium/services/viz/privileged/interfaces/viz_main.mojom9
-rw-r--r--chromium/services/viz/public/cpp/compositing/BUILD.gn2
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap1
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc3
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h9
-rw-r--r--chromium/services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc4
-rw-r--r--chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc13
-rw-r--r--chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h6
-rw-r--r--chromium/services/viz/public/cpp/compositing/copy_output_result.typemap5
-rw-r--r--chromium/services/viz/public/cpp/compositing/filter_operation_struct_traits.h9
-rw-r--r--chromium/services/viz/public/cpp/compositing/filter_operations.typemap7
-rw-r--r--chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.cc29
-rw-r--r--chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.h18
-rw-r--r--chromium/services/viz/public/cpp/compositing/frame_deadline.typemap5
-rw-r--r--chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.cc25
-rw-r--r--chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.h26
-rw-r--r--chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.cc3
-rw-r--r--chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.h6
-rw-r--r--chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc2
-rw-r--r--chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.h5
-rw-r--r--chromium/services/viz/public/cpp/compositing/struct_traits_unittest.cc40
-rw-r--r--chromium/services/viz/public/cpp/compositing/surface_sequence.typemap12
-rw-r--r--chromium/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h35
-rw-r--r--chromium/services/viz/public/cpp/compositing/typemaps.gni1
-rw-r--r--chromium/services/viz/public/interfaces/BUILD.gn1
-rw-r--r--chromium/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom3
-rw-r--r--chromium/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom15
-rw-r--r--chromium/services/viz/public/interfaces/compositing/copy_output_request.mojom1
-rw-r--r--chromium/services/viz/public/interfaces/compositing/frame_deadline.mojom7
-rw-r--r--chromium/services/viz/public/interfaces/compositing/render_pass.mojom3
-rw-r--r--chromium/services/viz/public/interfaces/compositing/resource_settings.mojom1
-rw-r--r--chromium/services/viz/public/interfaces/compositing/surface_sequence.mojom15
883 files changed, 34885 insertions, 4861 deletions
diff --git a/chromium/services/BUILD.gn b/chromium/services/BUILD.gn
index 6cbbd73fd53..89feff18731 100644
--- a/chromium/services/BUILD.gn
+++ b/chromium/services/BUILD.gn
@@ -19,6 +19,8 @@ service_test("services_unittests") {
# section below. If you are unsure, contact blundell@chromium.org.
deps = [
"//services/identity:tests",
+ "//services/metrics/public/cpp:tests",
+ "//services/network:tests",
"//services/network/public/cpp:tests",
]
@@ -31,7 +33,6 @@ service_test("services_unittests") {
"//services/audio:tests",
"//services/data_decoder:tests",
"//services/device:tests",
- "//services/network:tests",
"//services/preferences:tests",
"//services/proxy_resolver:tests",
"//services/resource_coordinator:tests",
@@ -65,6 +66,9 @@ service_test("services_unittests") {
"//services/data_decoder/public/cpp/android:safe_json_java",
"//services/device:java",
+ # Some tests make network requests.
+ "//net/android:net_java",
+
# Some tests need to initialize V8.
"//v8:v8_external_startup_data_assets",
]
@@ -91,7 +95,10 @@ catalog("services_unittests_catalog") {
# The division between "all platforms" and "!iOS" here needs to match that
# for the main deps list in the services_unittests target above.
- catalog_deps = [ "//services/identity:tests_catalog" ]
+ catalog_deps = [
+ "//services/identity:tests_catalog",
+ "//services/network:tests_catalog",
+ ]
if (!is_ios) {
catalog_deps += [
@@ -134,13 +141,14 @@ if (is_android) {
"$google_play_services_package:google_play_services_vision_java",
"//base:base_java",
"//base:base_java_test_support",
+ "//base:base_junit_test_support",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
"//services/device/generic_sensor:java",
"//services/device/nfc/android:java",
- "//services/device/public/interfaces:generic_sensor_java",
- "//services/device/public/interfaces:interfaces_java",
"//services/device/public/java:nfc_java",
+ "//services/device/public/mojom:generic_sensor_java",
+ "//services/device/public/mojom:mojom_java",
"//services/shape_detection:shape_detection_java",
"//skia/public/interfaces:interfaces_java",
"//third_party/android_tools:android_support_annotations_java",
@@ -164,7 +172,7 @@ if (is_android) {
"//base:base_java_test_support",
"//mojo/public/java:bindings_java",
"//services/shape_detection:shape_detection_java",
- "//services/shape_detection/public/interfaces:interfaces_java",
+ "//services/shape_detection/public/mojom:mojom_java",
"//skia/public/interfaces:interfaces_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/junit",
diff --git a/chromium/services/OWNERS b/chromium/services/OWNERS
index 82541da8157..28e613e9138 100644
--- a/chromium/services/OWNERS
+++ b/chromium/services/OWNERS
@@ -3,4 +3,3 @@ blundell@chromium.org
jam@chromium.org
rockot@chromium.org
sky@chromium.org
-yzshen@chromium.org
diff --git a/chromium/services/audio/BUILD.gn b/chromium/services/audio/BUILD.gn
index 1d74f7195bf..b5a0b532b3e 100644
--- a/chromium/services/audio/BUILD.gn
+++ b/chromium/services/audio/BUILD.gn
@@ -15,10 +15,16 @@ service_manifest("manifest") {
source_set("lib") {
sources = [
+ "debug_recording.cc",
+ "debug_recording.h",
"in_process_audio_manager_accessor.cc",
"in_process_audio_manager_accessor.h",
+ "output_stream.cc",
+ "output_stream.h",
"service.cc",
"service.h",
+ "service_factory.cc",
+ "service_factory.h",
"system_info.cc",
"system_info.h",
]
@@ -26,7 +32,7 @@ source_set("lib") {
public_deps = [
"//base",
"//media",
- "//services/audio/public/interfaces",
+ "//services/audio/public/mojom",
"//services/service_manager/public/cpp",
]
}
@@ -35,18 +41,26 @@ source_set("tests") {
testonly = true
sources = [
+ "debug_recording_unittest.cc",
+ "output_stream_unittest.cc",
"test/audio_system_to_service_adapter_test.cc",
+ "test/debug_recording_session_unittest.cc",
"test/in_process_service_test.cc",
+ "test/mock_log.cc",
+ "test/mock_log.h",
]
deps = [
":lib",
"//base/test:test_support",
"//media:test_support",
+ "//mojo/edk/system:system",
"//services/audio/public/cpp",
- "//services/audio/public/interfaces",
+ "//services/audio/public/cpp:test_support",
+ "//services/audio/public/mojom",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
+ "//services/service_manager/public/cpp/test:test_support",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/services/audio/DEPS b/chromium/services/audio/DEPS
index 66918d3d32c..88e0aca4c1e 100644
--- a/chromium/services/audio/DEPS
+++ b/chromium/services/audio/DEPS
@@ -2,4 +2,5 @@ include_rules = [
"+media/audio",
"+media/base",
"+media/mojo",
+ "+services/audio/public",
]
diff --git a/chromium/services/audio/debug_recording.cc b/chromium/services/audio/debug_recording.cc
new file mode 100644
index 00000000000..81d92bf2a28
--- /dev/null
+++ b/chromium/services/audio/debug_recording.cc
@@ -0,0 +1,73 @@
+// Copyright 2018 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/audio/debug_recording.h"
+
+#include <memory>
+#include <utility>
+
+#include "media/audio/audio_debug_recording_manager.h"
+#include "media/audio/audio_manager.h"
+
+namespace audio {
+
+DebugRecording::DebugRecording(mojom::DebugRecordingRequest request,
+ media::AudioManager* audio_manager)
+ : binding_(this, std::move(request)),
+ audio_manager_(audio_manager),
+ weak_factory_(this) {
+ DCHECK(audio_manager_ != nullptr);
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+
+ // On connection error debug recording is disabled, but object is not
+ // destroyed, it will be cleaned-up by service either on next bind request on
+ // or when service is shut down.
+ binding_.set_connection_error_handler(
+ base::BindOnce(&DebugRecording::Disable, base::Unretained(this)));
+}
+
+DebugRecording::~DebugRecording() {
+ Disable();
+}
+
+void DebugRecording::Enable(
+ mojom::DebugRecordingFileProviderPtr recording_file_provider) {
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+ DCHECK(!IsEnabled());
+ file_provider_ = std::move(recording_file_provider);
+ media::AudioDebugRecordingManager* debug_recording_manager =
+ audio_manager_->GetAudioDebugRecordingManager();
+ if (debug_recording_manager == nullptr)
+ return;
+ debug_recording_manager->EnableDebugRecording(base::BindRepeating(
+ &DebugRecording::CreateWavFile, weak_factory_.GetWeakPtr()));
+}
+
+void DebugRecording::Disable() {
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+ if (!IsEnabled())
+ return;
+ file_provider_.reset();
+ binding_.Close();
+
+ media::AudioDebugRecordingManager* debug_recording_manager =
+ audio_manager_->GetAudioDebugRecordingManager();
+ if (debug_recording_manager == nullptr)
+ return;
+ debug_recording_manager->DisableDebugRecording();
+}
+
+void DebugRecording::CreateWavFile(
+ const base::FilePath& file_suffix,
+ mojom::DebugRecordingFileProvider::CreateWavFileCallback reply_callback) {
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+ file_provider_->CreateWavFile(file_suffix, std::move(reply_callback));
+}
+
+bool DebugRecording::IsEnabled() {
+ DCHECK(audio_manager_->GetTaskRunner()->BelongsToCurrentThread());
+ return file_provider_.is_bound();
+}
+
+} // namespace audio
diff --git a/chromium/services/audio/debug_recording.h b/chromium/services/audio/debug_recording.h
new file mode 100644
index 00000000000..4c9f66a7f1c
--- /dev/null
+++ b/chromium/services/audio/debug_recording.h
@@ -0,0 +1,51 @@
+// Copyright 2018 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 SERVICES_AUDIO_DEBUG_RECORDING_H_
+#define SERVICES_AUDIO_DEBUG_RECORDING_H_
+
+#include <utility>
+
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/audio/public/mojom/debug_recording.mojom.h"
+
+namespace media {
+class AudioManager;
+}
+
+namespace audio {
+
+// Implementation for controlling audio debug recording.
+class DebugRecording : public mojom::DebugRecording {
+ public:
+ DebugRecording(mojom::DebugRecordingRequest request,
+ media::AudioManager* audio_manager);
+
+ // Disables audio debug recording if Enable() was called before.
+ ~DebugRecording() override;
+
+ // Enables audio debug recording.
+ void Enable(mojom::DebugRecordingFileProviderPtr file_provider) override;
+
+ private:
+ // Called on binding connection error.
+ void Disable();
+
+ void CreateWavFile(
+ const base::FilePath& file_suffix,
+ mojom::DebugRecordingFileProvider::CreateWavFileCallback reply_callback);
+ bool IsEnabled();
+
+ mojo::Binding<mojom::DebugRecording> binding_;
+ mojom::DebugRecordingFileProviderPtr file_provider_;
+ media::AudioManager* const audio_manager_;
+
+ base::WeakPtrFactory<DebugRecording> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(DebugRecording);
+};
+
+} // namespace audio
+
+#endif // SERVICES_AUDIO_DEBUG_RECORDING_H_
diff --git a/chromium/services/audio/debug_recording_unittest.cc b/chromium/services/audio/debug_recording_unittest.cc
new file mode 100644
index 00000000000..73c92bf249e
--- /dev/null
+++ b/chromium/services/audio/debug_recording_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright 2018 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/audio/debug_recording.h"
+
+#include <memory>
+
+#include "base/files/file_path.h"
+#include "base/test/scoped_task_environment.h"
+#include "media/audio/audio_debug_recording_test.h"
+#include "media/audio/mock_audio_debug_recording_manager.h"
+#include "media/audio/mock_audio_manager.h"
+#include "services/audio/public/cpp/debug_recording_session.h"
+#include "services/audio/public/mojom/debug_recording.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace audio {
+
+namespace {
+const base::FilePath::CharType kBaseFileName[] =
+ FILE_PATH_LITERAL("base_file_name");
+}
+
+class DebugRecordingTest : public media::AudioDebugRecordingTest {
+ public:
+ DebugRecordingTest() = default;
+ ~DebugRecordingTest() override = default;
+
+ void SetUp() override {
+ CreateAudioManager();
+ InitializeAudioDebugRecordingManager();
+ }
+
+ void TearDown() override { ShutdownAudioManager(); }
+
+ protected:
+ void CreateDebugRecording() {
+ debug_recording_ = std::make_unique<DebugRecording>(
+ mojo::MakeRequest(&debug_recording_ptr_),
+ static_cast<media::AudioManager*>(mock_audio_manager_.get()));
+ EXPECT_TRUE(debug_recording_ptr_.is_bound());
+ }
+
+ void EnableDebugRecording() {
+ mojom::DebugRecordingFileProviderPtr file_provider_ptr;
+ DebugRecordingSession::DebugRecordingFileProvider file_provider(
+ mojo::MakeRequest(&file_provider_ptr), base::FilePath(kBaseFileName));
+ ASSERT_TRUE(file_provider_ptr.is_bound());
+ debug_recording_ptr_->Enable(std::move(file_provider_ptr));
+ }
+
+ void DestroyDebugRecording() { debug_recording_ptr_.reset(); }
+
+ MOCK_METHOD0(OnConnectionError, void());
+
+ private:
+ std::unique_ptr<DebugRecording> debug_recording_;
+ mojom::DebugRecordingPtr debug_recording_ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(DebugRecordingTest);
+};
+
+TEST_F(DebugRecordingTest, EnableResetEnablesDisablesDebugRecording) {
+ CreateDebugRecording();
+
+ EXPECT_CALL(*mock_debug_recording_manager_, EnableDebugRecording(testing::_));
+ EnableDebugRecording();
+
+ EXPECT_CALL(*mock_debug_recording_manager_, DisableDebugRecording());
+ DestroyDebugRecording();
+}
+
+TEST_F(DebugRecordingTest, ResetWithoutEnableDoesNotDisableDebugRecording) {
+ CreateDebugRecording();
+
+ EXPECT_CALL(*mock_debug_recording_manager_, DisableDebugRecording()).Times(0);
+ DestroyDebugRecording();
+}
+
+} // namespace audio
diff --git a/chromium/services/audio/manifest.json b/chromium/services/audio/manifest.json
index de01fc388cc..d7157b15154 100644
--- a/chromium/services/audio/manifest.json
+++ b/chromium/services/audio/manifest.json
@@ -5,7 +5,8 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "device": [ "audio::mojom::SystemInfo" ]
+ "info": [ "audio::mojom::SystemInfo" ],
+ "debug_recording": [ "audio::mojom::DebugRecording" ]
},
"requires": {
"service_manager": [ "service_manager:all_users" ]
diff --git a/chromium/services/audio/output_stream.cc b/chromium/services/audio/output_stream.cc
new file mode 100644
index 00000000000..e4b24772c1f
--- /dev/null
+++ b/chromium/services/audio/output_stream.cc
@@ -0,0 +1,238 @@
+// Copyright 2018 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/audio/output_stream.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "media/audio/audio_sync_reader.h"
+
+namespace audio {
+
+const float kSilenceThresholdDBFS = -72.24719896f;
+
+// Desired polling frequency. Note: If this is set too low, short-duration
+// "blip" sounds won't be detected. http://crbug.com/339133#c4
+const int kPowerMeasurementsPerSecond = 15;
+
+OutputStream::OutputStream(
+ CreatedCallback created_callback,
+ DeleteCallback delete_callback,
+ media::mojom::AudioOutputStreamRequest stream_request,
+ media::mojom::AudioOutputStreamClientPtr client,
+ media::mojom::AudioOutputStreamObserverAssociatedPtr observer,
+ media::mojom::AudioLogPtr log,
+ media::AudioManager* audio_manager,
+ const std::string& output_device_id,
+ const media::AudioParameters& params)
+ : foreign_socket_(),
+ created_callback_(std::move(created_callback)),
+ delete_callback_(std::move(delete_callback)),
+ binding_(this, std::move(stream_request)),
+ client_(std::move(client)),
+ observer_(std::move(observer)),
+ log_(media::mojom::ThreadSafeAudioLogPtr::Create(std::move(log))),
+ // Unretained is safe since we own |reader_|
+ reader_(media::AudioSyncReader::Create(
+ base::BindRepeating(&media::mojom::AudioLog::OnLogMessage,
+ base::Unretained(log_->get())),
+ params,
+ &foreign_socket_)),
+ weak_factory_(this) {
+ DCHECK(audio_manager);
+ DCHECK(binding_.is_bound());
+ DCHECK(client_.is_bound());
+ DCHECK(observer_.is_bound());
+ DCHECK(created_callback_);
+ DCHECK(delete_callback_);
+
+ // |this| owns these objects, so unretained is safe.
+ base::RepeatingClosure error_handler =
+ base::BindRepeating(&OutputStream::OnError, base::Unretained(this));
+ binding_.set_connection_error_handler(error_handler);
+ client_.set_connection_error_handler(error_handler);
+
+ // We allow the observer to terminate the stream by closing the message pipe.
+ observer_.set_connection_error_handler(std::move(error_handler));
+
+ log_->get()->OnCreated(params, output_device_id);
+
+ if (!reader_) {
+ // Failed to create reader. Since we failed to initialize, don't bind the
+ // request.
+ OnError();
+ return;
+ }
+
+ controller_ = media::AudioOutputController::Create(
+ audio_manager, this, params, output_device_id, reader_.get());
+}
+
+OutputStream::~OutputStream() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ log_->get()->OnClosed();
+
+ if (created_callback_) {
+ // Didn't manage to create the stream. Call the callback anyways as mandated
+ // by mojo.
+ std::move(created_callback_).Run(nullptr);
+ }
+
+ if (!controller_) {
+ // Didn't initialize properly, nothing to clean up.
+ return;
+ }
+
+ // TODO(803102): remove AudioOutputController::Close() after content/ streams
+ // are removed, destructor should suffice.
+ controller_->Close(base::OnceClosure());
+}
+
+void OutputStream::Play() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ controller_->Play();
+ log_->get()->OnStarted();
+}
+
+void OutputStream::Pause() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ controller_->Pause();
+ log_->get()->OnStopped();
+}
+
+void OutputStream::SetVolume(double volume) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ if (volume < 0 || volume > 1) {
+ mojo::ReportBadMessage("Invalid volume");
+ OnError();
+ return;
+ }
+
+ controller_->SetVolume(volume);
+ log_->get()->OnSetVolume(volume);
+}
+
+void OutputStream::OnControllerCreated() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ // TODO(803102): Get rid of the OnControllerCreated event after removing
+ // content/ streams.
+ const base::SharedMemory* memory = reader_->shared_memory();
+
+ base::SharedMemoryHandle foreign_memory_handle =
+ base::SharedMemory::DuplicateHandle(memory->handle());
+ if (!base::SharedMemory::IsHandleValid(foreign_memory_handle)) {
+ OnError();
+ return;
+ }
+
+ mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
+ foreign_memory_handle, memory->requested_size(),
+ mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
+
+ mojo::ScopedHandle socket_handle =
+ mojo::WrapPlatformFile(foreign_socket_.Release());
+
+ DCHECK(buffer_handle.is_valid());
+ DCHECK(socket_handle.is_valid());
+
+ std::move(created_callback_)
+ .Run(
+ {base::in_place, std::move(buffer_handle), std::move(socket_handle)});
+}
+
+void OutputStream::OnControllerPlaying() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ if (playing_)
+ return;
+
+ playing_ = true;
+ observer_->DidStartPlaying();
+ if (media::AudioOutputController::will_monitor_audio_levels()) {
+ DCHECK(!poll_timer_.IsRunning());
+ // base::Unretained is safe because |this| owns |poll_timer_|.
+ poll_timer_.Start(
+ FROM_HERE,
+ base::TimeDelta::FromSeconds(1) / kPowerMeasurementsPerSecond,
+ base::BindRepeating(&OutputStream::PollAudioLevel,
+ base::Unretained(this)));
+ return;
+ }
+
+ // In case we don't monitor audio levels, we assume a stream is audible when
+ // it's playing.
+ observer_->DidChangeAudibleState(true);
+}
+
+void OutputStream::OnControllerPaused() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ if (!playing_)
+ return;
+
+ playing_ = false;
+ if (media::AudioOutputController::will_monitor_audio_levels()) {
+ DCHECK(poll_timer_.IsRunning());
+ poll_timer_.Stop();
+ }
+ observer_->DidStopPlaying();
+}
+
+void OutputStream::OnControllerError() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ // Only propagate platform errors to the renderer.
+ client_->OnError();
+ log_->get()->OnError();
+ OnError();
+}
+
+void OutputStream::OnLog(base::StringPiece message) {
+ // No sequence check: |log_| is thread-safe.
+ log_->get()->OnLogMessage(message.as_string());
+}
+
+void OutputStream::OnError() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ // Defer callback so we're not destructed while in the constructor.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&OutputStream::CallDeleter, weak_factory_.GetWeakPtr()));
+
+ // Ignore any incoming calls.
+ binding_.Close();
+}
+
+void OutputStream::CallDeleter() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ std::move(delete_callback_).Run(this);
+}
+
+void OutputStream::PollAudioLevel() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ bool was_audible = is_audible_;
+ is_audible_ = IsAudible();
+
+ if (is_audible_ != was_audible)
+ observer_->DidChangeAudibleState(is_audible_);
+}
+
+bool OutputStream::IsAudible() const {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
+
+ float power_dbfs = controller_->ReadCurrentPowerAndClip().first;
+ return power_dbfs >= kSilenceThresholdDBFS;
+}
+
+} // namespace audio
diff --git a/chromium/services/audio/output_stream.h b/chromium/services/audio/output_stream.h
new file mode 100644
index 00000000000..a1416a3430b
--- /dev/null
+++ b/chromium/services/audio/output_stream.h
@@ -0,0 +1,100 @@
+// Copyright 2018 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 SERVICES_AUDIO_OUTPUT_STREAM_H_
+#define SERVICES_AUDIO_OUTPUT_STREAM_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/strings/string_piece.h"
+#include "base/sync_socket.h"
+#include "base/timer/timer.h"
+#include "media/audio/audio_output_controller.h"
+#include "media/mojo/interfaces/audio_data_pipe.mojom.h"
+#include "media/mojo/interfaces/audio_logging.mojom.h"
+#include "media/mojo/interfaces/audio_output_stream.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/buffer.h"
+#include "mojo/public/cpp/system/handle.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace media {
+class AudioManager;
+class AudioParameters;
+class AudioSyncReader;
+} // namespace media
+
+namespace audio {
+
+class OutputStream final : public media::mojom::AudioOutputStream,
+ public media::AudioOutputController::EventHandler {
+ public:
+ using DeleteCallback = base::OnceCallback<void(OutputStream*)>;
+ using CreatedCallback =
+ base::OnceCallback<void(media::mojom::AudioDataPipePtr)>;
+
+ OutputStream(CreatedCallback created_callback,
+ DeleteCallback delete_callback,
+ media::mojom::AudioOutputStreamRequest stream_request,
+ media::mojom::AudioOutputStreamClientPtr client,
+ media::mojom::AudioOutputStreamObserverAssociatedPtr observer,
+ media::mojom::AudioLogPtr log,
+ media::AudioManager* audio_manager,
+ const std::string& output_device_id,
+ const media::AudioParameters& params);
+
+ ~OutputStream() final;
+
+ // media::mojom::AudioOutputStream implementation.
+ void Play() final;
+ void Pause() final;
+ void SetVolume(double volume) final;
+
+ // AudioOutputController::EventHandler implementation.
+ void OnControllerCreated() final;
+ void OnControllerPlaying() final;
+ void OnControllerPaused() final;
+ void OnControllerError() final;
+ void OnLog(base::StringPiece message) final;
+
+ private:
+ void OnError();
+ void CallDeleter();
+ void PollAudioLevel();
+ bool IsAudible() const;
+
+ SEQUENCE_CHECKER(owning_sequence_);
+
+ base::CancelableSyncSocket foreign_socket_;
+ CreatedCallback created_callback_;
+ DeleteCallback delete_callback_;
+ mojo::Binding<AudioOutputStream> binding_;
+ media::mojom::AudioOutputStreamClientPtr client_;
+ media::mojom::AudioOutputStreamObserverAssociatedPtr observer_;
+ scoped_refptr<media::mojom::ThreadSafeAudioLogPtr> log_;
+
+ const std::unique_ptr<media::AudioSyncReader> reader_;
+ scoped_refptr<media::AudioOutputController> controller_;
+
+ // This flag ensures that we only send OnStreamStateChanged notifications
+ // and (de)register with the stream monitor when the state actually changes.
+ bool playing_ = false;
+
+ // Calls PollAudioLevel() at regular intervals while |playing_| is true.
+ base::RepeatingTimer poll_timer_;
+ bool is_audible_ = false;
+
+ base::WeakPtrFactory<OutputStream> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(OutputStream);
+};
+
+} // namespace audio
+
+#endif // SERVICES_AUDIO_OUTPUT_STREAM_H_
diff --git a/chromium/services/audio/output_stream_unittest.cc b/chromium/services/audio/output_stream_unittest.cc
new file mode 100644
index 00000000000..650b0fc3aa7
--- /dev/null
+++ b/chromium/services/audio/output_stream_unittest.cc
@@ -0,0 +1,514 @@
+// Copyright 2018 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/audio/output_stream.h"
+
+#include <utility>
+
+#include "base/test/mock_callback.h"
+#include "base/test/scoped_task_environment.h"
+#include "media/audio/audio_io.h"
+#include "media/audio/mock_audio_manager.h"
+#include "media/audio/test_audio_thread.h"
+#include "mojo/edk/system/core.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "services/audio/test/mock_log.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::AtMost;
+using testing::DeleteArg;
+using testing::Mock;
+using testing::NiceMock;
+using testing::NotNull;
+using testing::Return;
+using testing::SaveArg;
+using testing::StrictMock;
+using testing::_;
+
+namespace audio {
+
+class MockStream : public media::AudioOutputStream {
+ public:
+ MockStream() {}
+
+ MOCK_METHOD0(Open, bool());
+ MOCK_METHOD1(Start, void(AudioSourceCallback* callback));
+ MOCK_METHOD0(Stop, void());
+ MOCK_METHOD1(SetVolume, void(double volume));
+ MOCK_METHOD1(GetVolume, void(double* volume));
+ MOCK_METHOD0(Close, void());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockStream);
+};
+
+class MockClient : public media::mojom::AudioOutputStreamClient {
+ public:
+ MockClient() : binding_(this) {}
+
+ // Should only be called once.
+ media::mojom::AudioOutputStreamClientPtr MakePtr() {
+ media::mojom::AudioOutputStreamClientPtr ptr;
+ binding_.Bind(mojo::MakeRequest(&ptr));
+ binding_.set_connection_error_handler(base::BindOnce(
+ &MockClient::BindingConnectionError, base::Unretained(this)));
+ return ptr;
+ }
+
+ void CloseBinding() { binding_.Close(); }
+
+ MOCK_METHOD0(OnError, void());
+
+ MOCK_METHOD0(BindingConnectionError, void());
+
+ private:
+ mojo::Binding<media::mojom::AudioOutputStreamClient> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockClient);
+};
+
+class MockObserver : public media::mojom::AudioOutputStreamObserver {
+ public:
+ MockObserver() : binding_(this) {}
+
+ // Should only be called once.
+ media::mojom::AudioOutputStreamObserverAssociatedPtr MakePtr() {
+ media::mojom::AudioOutputStreamObserverAssociatedPtr ptr;
+ binding_.Bind(mojo::MakeRequestAssociatedWithDedicatedPipe(&ptr));
+ binding_.set_connection_error_handler(base::BindOnce(
+ &MockObserver::BindingConnectionError, base::Unretained(this)));
+ return ptr;
+ }
+
+ void CloseBinding() { binding_.Close(); }
+
+ MOCK_METHOD0(DidStartPlaying, void());
+ MOCK_METHOD0(DidStopPlaying, void());
+ MOCK_METHOD1(DidChangeAudibleState, void(bool));
+
+ MOCK_METHOD0(BindingConnectionError, void());
+
+ private:
+ mojo::AssociatedBinding<media::mojom::AudioOutputStreamObserver> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockObserver);
+};
+
+// Aliases for use with MockCreatedCallback::Created().
+
+namespace {
+const bool successfully_ = true;
+const bool unsuccessfully_ = false;
+} // namespace
+
+class MockCreatedCallback {
+ public:
+ MockCreatedCallback() {}
+
+ MOCK_METHOD1(Created, void(bool /*valid*/));
+
+ void OnCreated(media::mojom::AudioDataPipePtr ptr) { Created(!!ptr); }
+
+ OutputStream::CreatedCallback Get() {
+ return base::BindOnce(&MockCreatedCallback::OnCreated,
+ base::Unretained(this));
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCreatedCallback);
+};
+
+// Instantiates various classes that we're going to want in most test cases.
+class TestEnvironment {
+ public:
+ TestEnvironment()
+ : audio_manager_(std::make_unique<media::TestAudioThread>(false)) {
+ mojo::edk::SetDefaultProcessErrorCallback(bad_message_callback_.Get());
+ }
+
+ ~TestEnvironment() { audio_manager_.Shutdown(); }
+
+ using MockDeleteCallback = base::MockCallback<OutputStream::DeleteCallback>;
+ using MockBadMessageCallback =
+ base::MockCallback<base::RepeatingCallback<void(const std::string&)>>;
+
+ std::unique_ptr<OutputStream> CreateStream(
+ media::mojom::AudioOutputStreamRequest request) {
+ return std::make_unique<OutputStream>(
+ created_callback_.Get(), delete_callback_.Get(), std::move(request),
+ client_.MakePtr(), observer_.MakePtr(), log_.MakePtr(), &audio_manager_,
+ "", media::AudioParameters::UnavailableDeviceParams());
+ }
+
+ media::MockAudioManager& audio_manager() { return audio_manager_; }
+
+ MockClient& client() { return client_; }
+
+ MockObserver& observer() { return observer_; }
+
+ MockLog& log() { return log_; }
+
+ MockCreatedCallback& created_callback() { return created_callback_; }
+
+ MockDeleteCallback& delete_callback() { return delete_callback_; }
+
+ MockBadMessageCallback& bad_message_callback() {
+ return bad_message_callback_;
+ }
+
+ private:
+ base::test::ScopedTaskEnvironment tasks_;
+ media::MockAudioManager audio_manager_;
+ StrictMock<MockClient> client_;
+ StrictMock<MockObserver> observer_;
+ NiceMock<MockLog> log_;
+ StrictMock<MockCreatedCallback> created_callback_;
+ StrictMock<MockDeleteCallback> delete_callback_;
+ StrictMock<MockBadMessageCallback> bad_message_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestEnvironment);
+};
+
+TEST(OutputStreamTest, ConstructDestruct) {
+ TestEnvironment env;
+ MockStream mock_stream;
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+ EXPECT_CALL(env.log(), OnCreated(_, _));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(env.log(), OnClosed());
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+}
+
+TEST(OutputStreamTest, ConstructStreamAndDestructObserver_DestructsStream) {
+ TestEnvironment env;
+ MockStream mock_stream;
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+ EXPECT_CALL(env.delete_callback(), Run(stream.release()))
+ .WillOnce(DeleteArg<0>());
+
+ env.observer().CloseBinding();
+ base::RunLoop().RunUntilIdle();
+
+ Mock::VerifyAndClear(&env.delete_callback());
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.client());
+}
+
+TEST(OutputStreamTest, ConstructStreamAndDestructClient_DestructsStream) {
+ TestEnvironment env;
+ MockStream mock_stream;
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.delete_callback(), Run(stream.release()))
+ .WillOnce(DeleteArg<0>());
+
+ env.client().CloseBinding();
+ base::RunLoop().RunUntilIdle();
+
+ Mock::VerifyAndClear(&env.delete_callback());
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.observer());
+}
+
+TEST(OutputStreamTest, ConstructStreamAndReleaseStreamPtr_DestructsStream) {
+ TestEnvironment env;
+ MockStream mock_stream;
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+ EXPECT_CALL(env.delete_callback(), Run(stream.release()))
+ .WillOnce(DeleteArg<0>());
+
+ stream_ptr.reset();
+ base::RunLoop().RunUntilIdle();
+
+ Mock::VerifyAndClear(&env.delete_callback());
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.client());
+ Mock::VerifyAndClear(&env.observer());
+}
+
+TEST(OutputStreamTest, Play_Plays) {
+ TestEnvironment env;
+ MockStream mock_stream;
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(mock_stream, Start(NotNull()));
+ EXPECT_CALL(env.log(), OnStarted());
+ EXPECT_CALL(env.observer(), DidStartPlaying());
+ // May or may not get an audibility notification depending on if power
+ // monitoring is enabled.
+ EXPECT_CALL(env.observer(), DidChangeAudibleState(true)).Times(AtMost(1));
+ stream_ptr->Play();
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.observer());
+
+ EXPECT_CALL(mock_stream, Stop());
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.observer(), DidChangeAudibleState(false)).Times(AtMost(1));
+ EXPECT_CALL(env.observer(), DidStopPlaying()).Times(AtMost(1));
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+}
+
+TEST(OutputStreamTest, PlayAndPause_PlaysAndStops) {
+ TestEnvironment env;
+ MockStream mock_stream;
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(mock_stream, Start(NotNull()));
+ EXPECT_CALL(env.observer(), DidStartPlaying());
+ // May or may not get an audibility notification depending on if power
+ // monitoring is enabled.
+ EXPECT_CALL(env.observer(), DidChangeAudibleState(true)).Times(AtMost(1));
+ stream_ptr->Play();
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.observer());
+
+ EXPECT_CALL(mock_stream, Stop());
+ EXPECT_CALL(env.log(), OnStopped());
+ EXPECT_CALL(env.observer(), DidChangeAudibleState(false)).Times(AtMost(1));
+ EXPECT_CALL(env.observer(), DidStopPlaying());
+ stream_ptr->Pause();
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.observer());
+
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+}
+
+TEST(OutputStreamTest, SetVolume_SetsVolume) {
+ double new_volume = 0.618;
+ TestEnvironment env;
+ MockStream mock_stream;
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(mock_stream, SetVolume(new_volume));
+ EXPECT_CALL(env.log(), OnSetVolume(new_volume));
+ stream_ptr->SetVolume(new_volume);
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+}
+
+TEST(OutputStreamTest, SetNegativeVolume_BadMessage) {
+ TestEnvironment env;
+ MockStream mock_stream;
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+ EXPECT_CALL(env.bad_message_callback(), Run(_));
+ EXPECT_CALL(env.delete_callback(), Run(stream.release()))
+ .WillOnce(DeleteArg<0>());
+ stream_ptr->SetVolume(-0.1);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(OutputStreamTest, SetVolumeGreaterThanOne_BadMessage) {
+ TestEnvironment env;
+ MockStream mock_stream;
+ EXPECT_CALL(env.created_callback(), Created(successfully_));
+ env.audio_manager().SetMakeOutputStreamCB(base::BindRepeating(
+ [](media::AudioOutputStream* stream, const media::AudioParameters& params,
+ const std::string& device_id) { return stream; },
+ &mock_stream));
+
+ EXPECT_CALL(mock_stream, Open()).WillOnce(Return(true));
+ EXPECT_CALL(mock_stream, SetVolume(1));
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&mock_stream);
+ Mock::VerifyAndClear(&env.created_callback());
+
+ EXPECT_CALL(mock_stream, Close());
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+ EXPECT_CALL(env.bad_message_callback(), Run(_));
+ EXPECT_CALL(env.delete_callback(), Run(stream.release()))
+ .WillOnce(DeleteArg<0>());
+ stream_ptr->SetVolume(1.1);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(OutputStreamTest, ConstructWithStreamCreationFailure_SignalsError) {
+ TestEnvironment env;
+
+ // By default, the MockAudioManager fails to create a stream.
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+
+ EXPECT_CALL(env.created_callback(), Created(unsuccessfully_));
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.log(), OnError());
+ EXPECT_CALL(env.client(), OnError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+ EXPECT_CALL(env.delete_callback(), Run(stream.release()))
+ .WillOnce(DeleteArg<0>());
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&env.delete_callback());
+ Mock::VerifyAndClear(&env.client());
+ Mock::VerifyAndClear(&env.observer());
+}
+
+TEST(OutputStreamTest,
+ ConstructWithStreamCreationFailureAndDestructBeforeErrorFires_NoCrash) {
+ // The main purpose of this test is to make sure that that delete callback
+ // call is deferred, and that it is canceled in case of destruction.
+ TestEnvironment env;
+
+ // By default, the MockAudioManager fails to create a stream.
+
+ media::mojom::AudioOutputStreamPtr stream_ptr;
+ {
+ EXPECT_CALL(env.created_callback(), Created(unsuccessfully_));
+ std::unique_ptr<OutputStream> stream =
+ env.CreateStream(mojo::MakeRequest(&stream_ptr));
+
+ EXPECT_CALL(env.observer(), BindingConnectionError());
+ EXPECT_CALL(env.client(), OnError());
+ EXPECT_CALL(env.client(), BindingConnectionError());
+ }
+
+ base::RunLoop().RunUntilIdle();
+ Mock::VerifyAndClear(&env.client());
+ Mock::VerifyAndClear(&env.observer());
+}
+
+} // namespace audio
diff --git a/chromium/services/audio/public/cpp/BUILD.gn b/chromium/services/audio/public/cpp/BUILD.gn
index 8975eeb4520..c86efc1eb82 100644
--- a/chromium/services/audio/public/cpp/BUILD.gn
+++ b/chromium/services/audio/public/cpp/BUILD.gn
@@ -4,14 +4,36 @@
source_set("cpp") {
sources = [
+ "audio_system_factory.cc",
+ "audio_system_factory.h",
"audio_system_to_service_adapter.cc",
"audio_system_to_service_adapter.h",
+ "debug_recording_session.cc",
+ "debug_recording_session.h",
+ "debug_recording_session_factory.cc",
+ "debug_recording_session_factory.h",
]
public_deps = [
"//base",
"//media",
- "//services/audio/public/interfaces",
+ "//services/audio/public/mojom",
+ "//services/service_manager/public/cpp",
+ ]
+}
+
+source_set("test_support") {
+ testonly = true
+
+ sources = [
+ "fake_system_info.cc",
+ "fake_system_info.h",
+ ]
+
+ public_deps = [
+ "//base",
+ "//media",
+ "//services/audio/public/mojom",
"//services/service_manager/public/cpp",
]
}
diff --git a/chromium/services/audio/public/cpp/OWNERS b/chromium/services/audio/public/cpp/OWNERS
index 2e8915ff7bd..a3060033221 100644
--- a/chromium/services/audio/public/cpp/OWNERS
+++ b/chromium/services/audio/public/cpp/OWNERS
@@ -1,5 +1,5 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/audio/public/cpp/audio_device_description.typemap b/chromium/services/audio/public/cpp/audio_device_description.typemap
index 974e487f539..3b7d33f79a3 100644
--- a/chromium/services/audio/public/cpp/audio_device_description.typemap
+++ b/chromium/services/audio/public/cpp/audio_device_description.typemap
@@ -2,12 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/audio/public/interfaces/audio_device_description.mojom"
+mojom = "//services/audio/public/mojom/audio_device_description.mojom"
public_headers = [ "//media/audio/audio_device_description.h" ]
traits_headers =
- [ "//services/audio/public/cpp/audio_device_description_struct_traits.h" ]
+ [ "//services/audio/public/cpp/audio_device_description_mojom_traits.h" ]
sources = [
- "//services/audio/public/cpp/audio_device_description_struct_traits.cc",
+ "//services/audio/public/cpp/audio_device_description_mojom_traits.cc",
]
deps = [
"//media",
diff --git a/chromium/services/audio/public/cpp/audio_device_description_struct_traits.cc b/chromium/services/audio/public/cpp/audio_device_description_mojom_traits.cc
index 7aedc9d2c8d..6c675283f50 100644
--- a/chromium/services/audio/public/cpp/audio_device_description_struct_traits.cc
+++ b/chromium/services/audio/public/cpp/audio_device_description_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/audio/public/cpp/audio_device_description_struct_traits.h"
+#include "services/audio/public/cpp/audio_device_description_mojom_traits.h"
namespace mojo {
// static
diff --git a/chromium/services/audio/public/cpp/audio_device_description_struct_traits.h b/chromium/services/audio/public/cpp/audio_device_description_mojom_traits.h
index d5be825c349..c8064ef57e4 100644
--- a/chromium/services/audio/public/cpp/audio_device_description_struct_traits.h
+++ b/chromium/services/audio/public/cpp/audio_device_description_mojom_traits.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_AUDIO_PUBLIC_INTERFACES_AUDIO_DEVICE_DESCRIPTION_STRUCT_TRAITS_H_
-#define SERVICES_AUDIO_PUBLIC_INTERFACES_AUDIO_DEVICE_DESCRIPTION_STRUCT_TRAITS_H_
+#ifndef SERVICES_AUDIO_PUBLIC_INTERFACES_AUDIO_DEVICE_DESCRIPTION_MOJOM_TRAITS_H_
+#define SERVICES_AUDIO_PUBLIC_INTERFACES_AUDIO_DEVICE_DESCRIPTION_MOJOM_TRAITS_H_
#include <string>
#include "media/audio/audio_device_description.h"
-#include "services/audio/public/interfaces/system_info.mojom.h"
+#include "services/audio/public/mojom/system_info.mojom.h"
namespace mojo {
@@ -31,4 +31,4 @@ struct StructTraits<audio::mojom::AudioDeviceDescriptionDataView,
} // namespace mojo
-#endif // SERVICES_AUDIO_PUBLIC_INTERFACES_AUDIO_DEVICE_DESCRIPTION_STRUCT_TRAITS_H_
+#endif // SERVICES_AUDIO_PUBLIC_INTERFACES_AUDIO_DEVICE_DESCRIPTION_MOJOM_TRAITS_H_
diff --git a/chromium/services/audio/public/cpp/audio_system_factory.cc b/chromium/services/audio/public/cpp/audio_system_factory.cc
new file mode 100644
index 00000000000..38b5d131a22
--- /dev/null
+++ b/chromium/services/audio/public/cpp/audio_system_factory.cc
@@ -0,0 +1,18 @@
+// Copyright 2018 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/audio/public/cpp/audio_system_factory.h"
+
+#include "services/audio/public/cpp/audio_system_to_service_adapter.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace audio {
+
+std::unique_ptr<media::AudioSystem> CreateAudioSystem(
+ std::unique_ptr<service_manager::Connector> connector) {
+ return std::make_unique<audio::AudioSystemToServiceAdapter>(
+ std::move(connector));
+}
+
+} // namespace audio
diff --git a/chromium/services/audio/public/cpp/audio_system_factory.h b/chromium/services/audio/public/cpp/audio_system_factory.h
new file mode 100644
index 00000000000..cb9beb10b04
--- /dev/null
+++ b/chromium/services/audio/public/cpp/audio_system_factory.h
@@ -0,0 +1,27 @@
+// Copyright 2018 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 SERVICES_AUDIO_PUBLIC_CPP_AUDIO_SYSTEM_FACTORY_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_AUDIO_SYSTEM_FACTORY_H_
+
+#include <memory>
+
+namespace media {
+class AudioSystem;
+}
+
+namespace service_manager {
+class Connector;
+}
+
+namespace audio {
+
+// Creates an instance of AudioSystem which will be bound to the thread it's
+// used on for the first time.
+std::unique_ptr<media::AudioSystem> CreateAudioSystem(
+ std::unique_ptr<service_manager::Connector> connector);
+
+} // namespace audio
+
+#endif // SERVICES_AUDIO_PUBLIC_CPP_AUDIO_SYSTEM_FACTORY_H_
diff --git a/chromium/services/audio/public/cpp/audio_system_to_service_adapter.cc b/chromium/services/audio/public/cpp/audio_system_to_service_adapter.cc
index 279463f8ffa..b835ce9522e 100644
--- a/chromium/services/audio/public/cpp/audio_system_to_service_adapter.cc
+++ b/chromium/services/audio/public/cpp/audio_system_to_service_adapter.cc
@@ -5,8 +5,9 @@
#include "services/audio/public/cpp/audio_system_to_service_adapter.h"
#include "base/bind.h"
+#include "base/logging.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
-#include "services/audio/public/interfaces/constants.mojom.h"
+#include "services/audio/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace audio {
@@ -18,12 +19,13 @@ AudioSystemToServiceAdapter::AudioSystemToServiceAdapter(
DETACH_FROM_THREAD(thread_checker_);
}
-AudioSystemToServiceAdapter::~AudioSystemToServiceAdapter() {}
+AudioSystemToServiceAdapter::~AudioSystemToServiceAdapter() {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+}
void AudioSystemToServiceAdapter::GetInputStreamParameters(
const std::string& device_id,
OnAudioParamsCallback on_params_callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
GetSystemInfo()->GetInputStreamParameters(
device_id, mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(on_params_callback), base::nullopt));
@@ -32,7 +34,6 @@ void AudioSystemToServiceAdapter::GetInputStreamParameters(
void AudioSystemToServiceAdapter::GetOutputStreamParameters(
const std::string& device_id,
OnAudioParamsCallback on_params_callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
GetSystemInfo()->GetOutputStreamParameters(
device_id, mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(on_params_callback), base::nullopt));
@@ -40,14 +41,12 @@ void AudioSystemToServiceAdapter::GetOutputStreamParameters(
void AudioSystemToServiceAdapter::HasInputDevices(
OnBoolCallback on_has_devices_callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
GetSystemInfo()->HasInputDevices(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(on_has_devices_callback), false));
}
void AudioSystemToServiceAdapter::HasOutputDevices(
OnBoolCallback on_has_devices_callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
GetSystemInfo()->HasOutputDevices(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(on_has_devices_callback), false));
}
@@ -55,7 +54,6 @@ void AudioSystemToServiceAdapter::HasOutputDevices(
void AudioSystemToServiceAdapter::GetDeviceDescriptions(
bool for_input,
OnDeviceDescriptionsCallback on_descriptions_callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
auto reply_callback = mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(on_descriptions_callback), media::AudioDeviceDescriptions());
if (for_input)
@@ -67,7 +65,6 @@ void AudioSystemToServiceAdapter::GetDeviceDescriptions(
void AudioSystemToServiceAdapter::GetAssociatedOutputDeviceID(
const std::string& input_device_id,
OnDeviceIdCallback on_device_id_callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
GetSystemInfo()->GetAssociatedOutputDeviceID(
input_device_id, mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(on_device_id_callback), base::nullopt));
@@ -76,7 +73,6 @@ void AudioSystemToServiceAdapter::GetAssociatedOutputDeviceID(
void AudioSystemToServiceAdapter::GetInputDeviceInfo(
const std::string& input_device_id,
OnInputDeviceInfoCallback on_input_device_info_callback) {
- DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
GetSystemInfo()->GetInputDeviceInfo(
input_device_id, mojo::WrapCallbackWithDefaultInvokeIfNotRun(
std::move(on_input_device_info_callback),
@@ -86,17 +82,21 @@ void AudioSystemToServiceAdapter::GetInputDeviceInfo(
mojom::SystemInfo* AudioSystemToServiceAdapter::GetSystemInfo() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!system_info_) {
+ DVLOG(4) << "AudioSystemToServiceAdapter::GetSystemInfo: SystemInfo bind "
+ "request";
connector_->BindInterface(mojom::kServiceName,
mojo::MakeRequest(&system_info_));
+ system_info_.set_connection_error_handler(
+ base::BindOnce(&AudioSystemToServiceAdapter::OnConnectionError,
+ base::Unretained(this)));
+ DCHECK(system_info_);
}
- DCHECK(system_info_);
- system_info_.set_connection_error_handler(base::BindOnce(
- &AudioSystemToServiceAdapter::OnConnectionError, base::Unretained(this)));
return system_info_.get();
}
void AudioSystemToServiceAdapter::OnConnectionError() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DVLOG(4) << "AudioSystemToServiceAdapter::OnConnectionError";
system_info_.reset();
}
diff --git a/chromium/services/audio/public/cpp/audio_system_to_service_adapter.h b/chromium/services/audio/public/cpp/audio_system_to_service_adapter.h
index 41e9b1063c0..c09aec7e59b 100644
--- a/chromium/services/audio/public/cpp/audio_system_to_service_adapter.h
+++ b/chromium/services/audio/public/cpp/audio_system_to_service_adapter.h
@@ -9,7 +9,7 @@
#include "base/threading/thread_checker.h"
#include "media/audio/audio_system.h"
-#include "services/audio/public/interfaces/system_info.mojom.h"
+#include "services/audio/public/mojom/system_info.mojom.h"
namespace service_manager {
class Connector;
diff --git a/chromium/services/audio/public/cpp/debug_recording_session.cc b/chromium/services/audio/public/cpp/debug_recording_session.cc
new file mode 100644
index 00000000000..12091abd7a9
--- /dev/null
+++ b/chromium/services/audio/public/cpp/debug_recording_session.cc
@@ -0,0 +1,63 @@
+// Copyright 2018 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/audio/public/cpp/debug_recording_session.h"
+
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "media/audio/audio_debug_recording_manager.h"
+#include "media/audio/audio_manager.h"
+#include "services/audio/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace audio {
+
+namespace {
+const base::FilePath::CharType kWavExtension[] = FILE_PATH_LITERAL("wav");
+}
+
+DebugRecordingSession::DebugRecordingFileProvider::DebugRecordingFileProvider(
+ mojom::DebugRecordingFileProviderRequest request,
+ const base::FilePath& file_name_base)
+ : binding_(this, std::move(request)), file_name_base_(file_name_base) {}
+
+DebugRecordingSession::DebugRecordingFileProvider::
+ ~DebugRecordingFileProvider() = default;
+
+void DebugRecordingSession::DebugRecordingFileProvider::CreateWavFile(
+ const base::FilePath& file_name_suffix,
+ CreateWavFileCallback reply_callback) {
+ base::PostTaskWithTraitsAndReplyWithResult(
+ FROM_HERE,
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
+ base::BindOnce(
+ [](const base::FilePath& file_name) {
+ return base::File(file_name, base::File::FLAG_CREATE_ALWAYS |
+ base::File::FLAG_WRITE);
+ },
+ file_name_base_.AddExtension(file_name_suffix.value())
+ .AddExtension(kWavExtension)),
+ std::move(reply_callback));
+}
+
+DebugRecordingSession::DebugRecordingSession(
+ const base::FilePath& file_name_base,
+ std::unique_ptr<service_manager::Connector> connector) {
+ DCHECK(connector);
+
+ mojom::DebugRecordingFileProviderPtr file_provider;
+ file_provider_ = std::make_unique<DebugRecordingFileProvider>(
+ mojo::MakeRequest(&file_provider), file_name_base);
+
+ connector->BindInterface(audio::mojom::kServiceName,
+ mojo::MakeRequest(&debug_recording_));
+ if (debug_recording_.is_bound())
+ debug_recording_->Enable(std::move(file_provider));
+}
+
+DebugRecordingSession::~DebugRecordingSession() {}
+
+} // namespace audio
diff --git a/chromium/services/audio/public/cpp/debug_recording_session.h b/chromium/services/audio/public/cpp/debug_recording_session.h
new file mode 100644
index 00000000000..addb231b5e4
--- /dev/null
+++ b/chromium/services/audio/public/cpp/debug_recording_session.h
@@ -0,0 +1,63 @@
+// Copyright 2018 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 SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_H_
+
+#include <memory>
+
+#include "media/audio/audio_debug_recording_session.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/audio/public/mojom/debug_recording.mojom.h"
+
+namespace service_manager {
+class Connector;
+}
+
+namespace base {
+class FilePath;
+}
+
+namespace audio {
+
+class DebugRecordingFileProvider;
+
+// Client class for using mojom::DebugRecording interface. This class owns
+// mojom::DebugRecordingFileProvider implementation, therefore owners of this
+// class' instances need permission to create files in |file_name_base| path
+// passed in constructor in order to start debug recording. If file creation
+// fails, debug recording will silently not start.
+class DebugRecordingSession : public media::AudioDebugRecordingSession {
+ public:
+ class DebugRecordingFileProvider : public mojom::DebugRecordingFileProvider {
+ public:
+ DebugRecordingFileProvider(mojom::DebugRecordingFileProviderRequest request,
+ const base::FilePath& file_name_base);
+ ~DebugRecordingFileProvider() override;
+
+ // Creates file with name "|file_name_base_|.|file_suffix|.wav".
+ void CreateWavFile(const base::FilePath& file_suffix,
+ CreateWavFileCallback reply_callback) override;
+
+ private:
+ mojo::Binding<mojom::DebugRecordingFileProvider> binding_;
+ base::FilePath file_name_base_;
+
+ DISALLOW_COPY_AND_ASSIGN(DebugRecordingFileProvider);
+ };
+
+ DebugRecordingSession(const base::FilePath& file_name_base,
+ std::unique_ptr<service_manager::Connector> connector);
+ ~DebugRecordingSession() override;
+
+ private:
+ std::unique_ptr<DebugRecordingFileProvider> file_provider_;
+ mojom::DebugRecordingPtr debug_recording_;
+
+ DISALLOW_COPY_AND_ASSIGN(DebugRecordingSession);
+};
+
+} // namespace audio
+
+#endif // SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_H_
diff --git a/chromium/services/audio/public/cpp/debug_recording_session_factory.cc b/chromium/services/audio/public/cpp/debug_recording_session_factory.cc
new file mode 100644
index 00000000000..eab484b87c4
--- /dev/null
+++ b/chromium/services/audio/public/cpp/debug_recording_session_factory.cc
@@ -0,0 +1,25 @@
+// Copyright 2018 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/audio/public/cpp/debug_recording_session_factory.h"
+
+#include <utility>
+
+#include "base/files/file_path.h"
+#include "media/audio/audio_debug_recording_session_impl.h"
+#include "services/service_manager/public/cpp/connector.h"
+
+namespace audio {
+
+std::unique_ptr<media::AudioDebugRecordingSession>
+CreateAudioDebugRecordingSession(
+ const base::FilePath& debug_recording_file_path,
+ std::unique_ptr<service_manager::Connector> connector) {
+ DCHECK(connector);
+
+ return std::make_unique<media::AudioDebugRecordingSessionImpl>(
+ debug_recording_file_path);
+}
+
+} // namespace audio
diff --git a/chromium/services/audio/public/cpp/debug_recording_session_factory.h b/chromium/services/audio/public/cpp/debug_recording_session_factory.h
new file mode 100644
index 00000000000..fae9da88e19
--- /dev/null
+++ b/chromium/services/audio/public/cpp/debug_recording_session_factory.h
@@ -0,0 +1,31 @@
+// Copyright 2018 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 SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_FACTORY_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_FACTORY_H_
+
+#include <memory>
+
+namespace base {
+class FilePath;
+}
+
+namespace media {
+class AudioDebugRecordingSession;
+}
+
+namespace service_manager {
+class Connector;
+}
+
+namespace audio {
+
+std::unique_ptr<media::AudioDebugRecordingSession>
+CreateAudioDebugRecordingSession(
+ const base::FilePath& debug_recording_file_path,
+ std::unique_ptr<service_manager::Connector> connector);
+
+} // namespace audio
+
+#endif // SERVICES_AUDIO_PUBLIC_CPP_DEBUG_RECORDING_SESSION_FACTORY_H_
diff --git a/chromium/services/audio/public/cpp/fake_system_info.cc b/chromium/services/audio/public/cpp/fake_system_info.cc
new file mode 100644
index 00000000000..ad139900064
--- /dev/null
+++ b/chromium/services/audio/public/cpp/fake_system_info.cc
@@ -0,0 +1,74 @@
+// Copyright 2018 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/audio/public/cpp/fake_system_info.h"
+
+#include "services/audio/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/cpp/bind_source_info.h"
+#include "services/service_manager/public/cpp/service_context.h"
+
+namespace audio {
+
+FakeSystemInfo::FakeSystemInfo() {}
+
+FakeSystemInfo::~FakeSystemInfo() {}
+
+// static
+void FakeSystemInfo::OverrideGlobalBinderForAudioService(
+ FakeSystemInfo* fake_system_info) {
+ service_manager::ServiceContext::SetGlobalBinderForTesting(
+ mojom::kServiceName, mojom::SystemInfo::Name_,
+ base::BindRepeating(&FakeSystemInfo::Bind,
+ base::Unretained(fake_system_info)));
+}
+
+void FakeSystemInfo::GetInputStreamParameters(
+ const std::string& device_id,
+ GetInputStreamParametersCallback callback) {
+ std::move(callback).Run(base::nullopt);
+}
+
+void FakeSystemInfo::GetOutputStreamParameters(
+ const std::string& device_id,
+ GetOutputStreamParametersCallback callback) {
+ std::move(callback).Run(base::nullopt);
+}
+
+void FakeSystemInfo::HasInputDevices(HasInputDevicesCallback callback) {
+ std::move(callback).Run(false);
+}
+
+void FakeSystemInfo::HasOutputDevices(HasOutputDevicesCallback callback) {
+ std::move(callback).Run(false);
+}
+
+void FakeSystemInfo::GetInputDeviceDescriptions(
+ GetInputDeviceDescriptionsCallback callback) {
+ std::move(callback).Run(media::AudioDeviceDescriptions());
+}
+
+void FakeSystemInfo::GetOutputDeviceDescriptions(
+ GetOutputDeviceDescriptionsCallback callback) {
+ std::move(callback).Run(media::AudioDeviceDescriptions());
+}
+
+void FakeSystemInfo::GetAssociatedOutputDeviceID(
+ const std::string& input_device_id,
+ GetAssociatedOutputDeviceIDCallback callback) {
+ std::move(callback).Run(base::nullopt);
+}
+
+void FakeSystemInfo::GetInputDeviceInfo(const std::string& input_device_id,
+ GetInputDeviceInfoCallback callback) {
+ std::move(callback).Run(base::nullopt, base::nullopt);
+}
+
+void FakeSystemInfo::Bind(const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle handle,
+ const service_manager::BindSourceInfo& source_info) {
+ DCHECK(interface_name == mojom::SystemInfo::Name_);
+ bindings_.AddBinding(this, mojom::SystemInfoRequest(std::move(handle)));
+}
+
+} // namespace audio
diff --git a/chromium/services/audio/public/cpp/fake_system_info.h b/chromium/services/audio/public/cpp/fake_system_info.h
new file mode 100644
index 00000000000..ef75a127ea0
--- /dev/null
+++ b/chromium/services/audio/public/cpp/fake_system_info.h
@@ -0,0 +1,64 @@
+// Copyright 2018 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 SERVICES_AUDIO_PUBLIC_CPP_FAKE_SYSTEM_INFO_H_
+#define SERVICES_AUDIO_PUBLIC_CPP_FAKE_SYSTEM_INFO_H_
+
+#include <string>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+#include "services/audio/public/mojom/system_info.mojom.h"
+
+namespace service_manager {
+struct BindSourceInfo;
+}
+
+namespace audio {
+
+// An instance of this class can be used to override the global binding for
+// audio::SystemInfo. By default it behaves as if the system has no audio
+// devices. Inherit from it to override the behavior.
+class FakeSystemInfo : public mojom::SystemInfo {
+ public:
+ FakeSystemInfo();
+ ~FakeSystemInfo() override;
+
+ // See ServiceContext::ClearGlobalBindersForTesting() to clear it if needed.
+ static void OverrideGlobalBinderForAudioService(
+ FakeSystemInfo* fake_system_info);
+
+ protected:
+ // audio::mojom::SystemInfo implementation.
+ void GetInputStreamParameters(
+ const std::string& device_id,
+ GetInputStreamParametersCallback callback) override;
+ void GetOutputStreamParameters(
+ const std::string& device_id,
+ GetOutputStreamParametersCallback callback) override;
+ void HasInputDevices(HasInputDevicesCallback callback) override;
+ void HasOutputDevices(HasOutputDevicesCallback callback) override;
+ void GetInputDeviceDescriptions(
+ GetInputDeviceDescriptionsCallback callback) override;
+ void GetOutputDeviceDescriptions(
+ GetOutputDeviceDescriptionsCallback callback) override;
+ void GetAssociatedOutputDeviceID(
+ const std::string& input_device_id,
+ GetAssociatedOutputDeviceIDCallback callback) override;
+ void GetInputDeviceInfo(const std::string& input_device_id,
+ GetInputDeviceInfoCallback callback) override;
+
+ private:
+ void Bind(const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle handle,
+ const service_manager::BindSourceInfo& source_info);
+
+ mojo::BindingSet<mojom::SystemInfo> bindings_;
+ DISALLOW_COPY_AND_ASSIGN(FakeSystemInfo);
+};
+
+} // namespace audio
+
+#endif // SERVICES_AUDIO_PUBLIC_CPP_FAKE_SYSTEM_INFO_H_
diff --git a/chromium/services/audio/public/interfaces/BUILD.gn b/chromium/services/audio/public/mojom/BUILD.gn
index 28206e6ce73..079f3243c7e 100644
--- a/chromium/services/audio/public/interfaces/BUILD.gn
+++ b/chromium/services/audio/public/mojom/BUILD.gn
@@ -4,9 +4,10 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"audio_device_description.mojom",
+ "debug_recording.mojom",
"system_info.mojom",
]
diff --git a/chromium/services/device/public/interfaces/OWNERS b/chromium/services/audio/public/mojom/OWNERS
index 2c44a463856..ae29a36aac8 100644
--- a/chromium/services/device/public/interfaces/OWNERS
+++ b/chromium/services/audio/public/mojom/OWNERS
@@ -1,6 +1,6 @@
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/audio/public/interfaces/audio_device_description.mojom b/chromium/services/audio/public/mojom/audio_device_description.mojom
index 51d264dbc9b..51d264dbc9b 100644
--- a/chromium/services/audio/public/interfaces/audio_device_description.mojom
+++ b/chromium/services/audio/public/mojom/audio_device_description.mojom
diff --git a/chromium/services/audio/public/interfaces/constants.mojom b/chromium/services/audio/public/mojom/constants.mojom
index 0d4b0cc5fdb..0d4b0cc5fdb 100644
--- a/chromium/services/audio/public/interfaces/constants.mojom
+++ b/chromium/services/audio/public/mojom/constants.mojom
diff --git a/chromium/services/audio/public/mojom/debug_recording.mojom b/chromium/services/audio/public/mojom/debug_recording.mojom
new file mode 100644
index 00000000000..9bb73eaa8ab
--- /dev/null
+++ b/chromium/services/audio/public/mojom/debug_recording.mojom
@@ -0,0 +1,29 @@
+// Copyright 2018 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.
+
+module audio.mojom;
+
+import "mojo/common/file.mojom";
+import "mojo/common/file_path.mojom";
+
+// Creates audio debug recording files. Requires a base file path at binding.
+// All files are created in the path defined in implementation, to which
+// ".|suffix|" and ".wav" extension are appended. E.g.: from base file path
+// "/path/base_name" and suffix "output.1", "/path/base_name.output.1.wav" will
+// be created. This interface is called by audio service from implementation of
+// DebugRecording interface defined below.
+interface DebugRecordingFileProvider {
+ // Returns invalid file in case of failure.
+ CreateWavFile(mojo.common.mojom.FilePath suffix)
+ => (mojo.common.mojom.File? file);
+};
+
+// Controls audio debug recording. To enable, bind interface and call Enable
+// with a bound DebugRecordingFileProvider interface pointer. To disable, close
+// debug recording message pipe. Note: only the instance that enabled debug
+// recording can disable it, i.e. closing debug recording message pipe without
+// priorly enabling debug recording will not change debug recording state.
+interface DebugRecording {
+ Enable(DebugRecordingFileProvider file_provider);
+};
diff --git a/chromium/services/audio/public/interfaces/system_info.mojom b/chromium/services/audio/public/mojom/system_info.mojom
index b926709d129..54bedfe5cd2 100644
--- a/chromium/services/audio/public/interfaces/system_info.mojom
+++ b/chromium/services/audio/public/mojom/system_info.mojom
@@ -5,7 +5,7 @@
module audio.mojom;
import "media/mojo/interfaces/audio_parameters.mojom";
-import "services/audio/public/interfaces/audio_device_description.mojom";
+import "services/audio/public/mojom/audio_device_description.mojom";
// Provides information about audio system.
interface SystemInfo {
diff --git a/chromium/services/audio/service.cc b/chromium/services/audio/service.cc
index 4320940918e..99fccde9615 100644
--- a/chromium/services/audio/service.cc
+++ b/chromium/services/audio/service.cc
@@ -4,10 +4,14 @@
#include "services/audio/service.h"
+#include <utility>
+
+#include "base/logging.h"
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "media/audio/audio_manager.h"
+#include "services/audio/debug_recording.h"
#include "services/audio/system_info.h"
#include "services/service_manager/public/cpp/service_context.h"
@@ -24,8 +28,11 @@ Service::~Service() {
void Service::OnStart() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DVLOG(4) << "audio::Service::OnStart";
registry_.AddInterface<mojom::SystemInfo>(base::BindRepeating(
&Service::BindSystemInfoRequest, base::Unretained(this)));
+ registry_.AddInterface<mojom::DebugRecording>(base::BindRepeating(
+ &Service::BindDebugRecordingRequest, base::Unretained(this)));
}
void Service::OnBindInterface(
@@ -33,11 +40,15 @@ void Service::OnBindInterface(
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ DVLOG(4) << "audio::Service::OnBindInterface";
registry_.BindInterface(interface_name, std::move(interface_pipe));
}
bool Service::OnServiceManagerConnectionLost() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ // Reset |debug_recording_| to disable debug recording before AudioManager
+ // shutdown.
+ debug_recording_.reset();
audio_manager_accessor_->Shutdown();
return true;
}
@@ -45,10 +56,22 @@ bool Service::OnServiceManagerConnectionLost() {
void Service::BindSystemInfoRequest(mojom::SystemInfoRequest request) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
if (!system_info_) {
+ DVLOG(4)
+ << "audio::Service::BindSystemInfoRequest: lazy SystemInfo creation";
system_info_ = std::make_unique<SystemInfo>(
audio_manager_accessor_->GetAudioManager());
}
system_info_->Bind(std::move(request));
}
+void Service::BindDebugRecordingRequest(mojom::DebugRecordingRequest request) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ // Accept only one bind request at a time. Old request is overwritten.
+ // |debug_recording_| must be reset first to disable debug recording, and then
+ // create a new DebugRecording instance to enable debug recording.
+ debug_recording_.reset();
+ debug_recording_ = std::make_unique<DebugRecording>(
+ std::move(request), audio_manager_accessor_->GetAudioManager());
+}
+
} // namespace audio
diff --git a/chromium/services/audio/service.h b/chromium/services/audio/service.h
index 8270ca7addd..c6741c0f200 100644
--- a/chromium/services/audio/service.h
+++ b/chromium/services/audio/service.h
@@ -6,11 +6,13 @@
#define SERVICES_AUDIO_SERVICE_H_
#include <memory>
+#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
-#include "services/audio/public/interfaces/system_info.mojom.h"
+#include "services/audio/public/mojom/debug_recording.mojom.h"
+#include "services/audio/public/mojom/system_info.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
@@ -19,6 +21,7 @@ class AudioManager;
} // namespace media
namespace audio {
+class DebugRecording;
class SystemInfo;
class Service : public service_manager::Service {
@@ -27,7 +30,7 @@ class Service : public service_manager::Service {
// its created on, and that thread must be AudioManager main thread.
class AudioManagerAccessor {
public:
- virtual ~AudioManagerAccessor(){};
+ virtual ~AudioManagerAccessor() {}
// Must be called before destruction.
virtual void Shutdown() = 0;
@@ -49,9 +52,11 @@ class Service : public service_manager::Service {
private:
void BindSystemInfoRequest(mojom::SystemInfoRequest request);
+ void BindDebugRecordingRequest(mojom::DebugRecordingRequest request);
std::unique_ptr<AudioManagerAccessor> audio_manager_accessor_;
std::unique_ptr<SystemInfo> system_info_;
+ std::unique_ptr<DebugRecording> debug_recording_;
service_manager::BinderRegistry registry_;
diff --git a/chromium/services/audio/service_factory.cc b/chromium/services/audio/service_factory.cc
new file mode 100644
index 00000000000..40532eabf36
--- /dev/null
+++ b/chromium/services/audio/service_factory.cc
@@ -0,0 +1,19 @@
+// Copyright 2018 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/audio/service_factory.h"
+
+#include "services/audio/in_process_audio_manager_accessor.h"
+#include "services/audio/service.h"
+#include "services/service_manager/public/cpp/service.h"
+
+namespace audio {
+
+std::unique_ptr<service_manager::Service> CreateEmbeddedService(
+ media::AudioManager* audio_manager) {
+ return std::make_unique<Service>(
+ std::make_unique<InProcessAudioManagerAccessor>(audio_manager));
+}
+
+} // namespace audio
diff --git a/chromium/services/audio/service_factory.h b/chromium/services/audio/service_factory.h
new file mode 100644
index 00000000000..a7cf39e057c
--- /dev/null
+++ b/chromium/services/audio/service_factory.h
@@ -0,0 +1,28 @@
+// Copyright 2018 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 SERVICES_AUDIO_SERVICE_FACTORY_H_
+#define SERVICES_AUDIO_SERVICE_FACTORY_H_
+
+#include <memory>
+
+namespace service_manager {
+class Service;
+}
+
+namespace media {
+class AudioManager;
+} // namespace media
+
+namespace audio {
+
+// Create an instance of Audio service which will live in the current process
+// on top of AudioManager instance belonging to that process. Must be called on
+// the device thread of AudioManager.
+std::unique_ptr<service_manager::Service> CreateEmbeddedService(
+ media::AudioManager* audio_manager);
+
+} // namespace audio
+
+#endif // SERVICES_AUDIO_SERVICE_FACTORY_H_
diff --git a/chromium/services/audio/system_info.h b/chromium/services/audio/system_info.h
index 9523ba9cb95..57ebac178bb 100644
--- a/chromium/services/audio/system_info.h
+++ b/chromium/services/audio/system_info.h
@@ -12,7 +12,7 @@
#include "base/sequence_checker.h"
#include "media/audio/audio_system_helper.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/audio/public/interfaces/system_info.mojom.h"
+#include "services/audio/public/mojom/system_info.mojom.h"
namespace media {
class AudioManager;
diff --git a/chromium/services/catalog/BUILD.gn b/chromium/services/catalog/BUILD.gn
index dc33437be5f..594b4fbfc40 100644
--- a/chromium/services/catalog/BUILD.gn
+++ b/chromium/services/catalog/BUILD.gn
@@ -40,7 +40,7 @@ source_set("lib") {
"//base",
"//components/filesystem:lib",
"//services/catalog/public/cpp",
- "//services/catalog/public/interfaces",
+ "//services/catalog/public/mojom",
"//services/service_manager/public/cpp",
]
diff --git a/chromium/services/catalog/catalog.h b/chromium/services/catalog/catalog.h
index b5f9f72a686..8ea31595d35 100644
--- a/chromium/services/catalog/catalog.h
+++ b/chromium/services/catalog/catalog.h
@@ -16,9 +16,9 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/catalog/entry_cache.h"
-#include "services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/catalog/public/mojom/catalog.mojom.h"
#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
namespace base {
class FilePath;
diff --git a/chromium/services/catalog/entry.cc b/chromium/services/catalog/entry.cc
index 6f642177a2b..b954208a9c5 100644
--- a/chromium/services/catalog/entry.cc
+++ b/chromium/services/catalog/entry.cc
@@ -10,7 +10,7 @@
#include "base/values.h"
#include "services/catalog/public/cpp/manifest_parsing_util.h"
#include "services/catalog/store.h"
-#include "services/service_manager/public/interfaces/interface_provider_spec.mojom.h"
+#include "services/service_manager/public/mojom/interface_provider_spec.mojom.h"
namespace catalog {
namespace {
diff --git a/chromium/services/catalog/entry.h b/chromium/services/catalog/entry.h
index 2320f25cb46..bb0ec92e552 100644
--- a/chromium/services/catalog/entry.h
+++ b/chromium/services/catalog/entry.h
@@ -11,7 +11,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
-#include "services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/catalog/public/mojom/catalog.mojom.h"
#include "services/service_manager/public/cpp/interface_provider_spec.h"
namespace base {
diff --git a/chromium/services/catalog/entry_unittest.cc b/chromium/services/catalog/entry_unittest.cc
index 3406c4ebe3b..9c509fc3e81 100644
--- a/chromium/services/catalog/entry_unittest.cc
+++ b/chromium/services/catalog/entry_unittest.cc
@@ -11,7 +11,7 @@
#include "base/values.h"
#include "build/build_config.h"
#include "services/service_manager/public/cpp/interface_provider_spec.h"
-#include "services/service_manager/public/interfaces/interface_provider_spec.mojom.h"
+#include "services/service_manager/public/mojom/interface_provider_spec.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace catalog {
diff --git a/chromium/services/catalog/instance.h b/chromium/services/catalog/instance.h
index 255f3797102..1fa612d8460 100644
--- a/chromium/services/catalog/instance.h
+++ b/chromium/services/catalog/instance.h
@@ -10,7 +10,7 @@
#include "base/values.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/catalog/entry.h"
-#include "services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/catalog/public/mojom/catalog.mojom.h"
#include "services/catalog/store.h"
namespace catalog {
diff --git a/chromium/services/catalog/public/cpp/resource_loader.cc b/chromium/services/catalog/public/cpp/resource_loader.cc
index c18a709e22c..90afc1e55fc 100644
--- a/chromium/services/catalog/public/cpp/resource_loader.cc
+++ b/chromium/services/catalog/public/cpp/resource_loader.cc
@@ -12,7 +12,7 @@
#include "components/filesystem/public/interfaces/directory.mojom.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
+#include "services/service_manager/public/mojom/interface_provider.mojom.h"
namespace catalog {
diff --git a/chromium/services/catalog/public/interfaces/BUILD.gn b/chromium/services/catalog/public/mojom/BUILD.gn
index b8ba8cceb6d..53a0d00c031 100644
--- a/chromium/services/catalog/public/interfaces/BUILD.gn
+++ b/chromium/services/catalog/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"catalog.mojom",
]
diff --git a/chromium/services/catalog/public/interfaces/OWNERS b/chromium/services/catalog/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/catalog/public/interfaces/OWNERS
+++ b/chromium/services/catalog/public/mojom/OWNERS
diff --git a/chromium/services/catalog/public/interfaces/catalog.mojom b/chromium/services/catalog/public/mojom/catalog.mojom
index 278cb632d90..278cb632d90 100644
--- a/chromium/services/catalog/public/interfaces/catalog.mojom
+++ b/chromium/services/catalog/public/mojom/catalog.mojom
diff --git a/chromium/services/catalog/public/interfaces/constants.mojom b/chromium/services/catalog/public/mojom/constants.mojom
index 51294a87cfa..51294a87cfa 100644
--- a/chromium/services/catalog/public/interfaces/constants.mojom
+++ b/chromium/services/catalog/public/mojom/constants.mojom
diff --git a/chromium/services/data_decoder/BUILD.gn b/chromium/services/data_decoder/BUILD.gn
index be8c21eef5b..5bf5f50222b 100644
--- a/chromium/services/data_decoder/BUILD.gn
+++ b/chromium/services/data_decoder/BUILD.gn
@@ -29,7 +29,7 @@ source_set("lib") {
]
public_deps = [
- "//services/data_decoder/public/interfaces",
+ "//services/data_decoder/public/mojom",
"//services/service_manager/public/cpp",
]
}
diff --git a/chromium/services/data_decoder/data_decoder_service.cc b/chromium/services/data_decoder/data_decoder_service.cc
index 0fdd5023d47..36452d6cf9e 100644
--- a/chromium/services/data_decoder/data_decoder_service.cc
+++ b/chromium/services/data_decoder/data_decoder_service.cc
@@ -11,7 +11,7 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/data_decoder/image_decoder_impl.h"
#include "services/data_decoder/json_parser_impl.h"
-#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
+#include "services/data_decoder/public/mojom/image_decoder.mojom.h"
#include "services/data_decoder/xml_parser.h"
#include "services/service_manager/public/cpp/service_context.h"
@@ -36,7 +36,7 @@ void OnJsonParserRequest(service_manager::ServiceContextRefFactory* ref_factory,
void OnXmlParserRequest(service_manager::ServiceContextRefFactory* ref_factory,
mojom::XmlParserRequest request) {
- mojo::MakeStrongBinding(base::MakeUnique<XmlParser>(ref_factory->CreateRef()),
+ mojo::MakeStrongBinding(std::make_unique<XmlParser>(ref_factory->CreateRef()),
std::move(request));
}
@@ -52,8 +52,9 @@ std::unique_ptr<service_manager::Service> DataDecoderService::Create() {
}
void DataDecoderService::OnStart() {
- ref_factory_.reset(new service_manager::ServiceContextRefFactory(base::Bind(
- &DataDecoderService::MaybeRequestQuitDelayed, base::Unretained(this))));
+ ref_factory_.reset(new service_manager::ServiceContextRefFactory(
+ base::BindRepeating(&DataDecoderService::MaybeRequestQuitDelayed,
+ weak_factory_.GetWeakPtr())));
registry_.AddInterface(
base::Bind(&OnImageDecoderRequest, ref_factory_.get()));
registry_.AddInterface(base::Bind(&OnJsonParserRequest, ref_factory_.get()));
@@ -78,7 +79,7 @@ void DataDecoderService::MaybeRequestQuitDelayed() {
void DataDecoderService::MaybeRequestQuit() {
DCHECK(ref_factory_);
if (ref_factory_->HasNoRefs())
- context()->RequestQuit();
+ context()->CreateQuitClosure().Run();
}
} // namespace data_decoder
diff --git a/chromium/services/data_decoder/image_decoder_impl.h b/chromium/services/data_decoder/image_decoder_impl.h
index 07907b4e2ba..576977b9080 100644
--- a/chromium/services/data_decoder/image_decoder_impl.h
+++ b/chromium/services/data_decoder/image_decoder_impl.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include "base/macros.h"
-#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
+#include "services/data_decoder/public/mojom/image_decoder.mojom.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
#include "ui/gfx/geometry/size.h"
diff --git a/chromium/services/data_decoder/image_decoder_impl_unittest.cc b/chromium/services/data_decoder/image_decoder_impl_unittest.cc
index 3a59c88fa56..8650a8bf303 100644
--- a/chromium/services/data_decoder/image_decoder_impl_unittest.cc
+++ b/chromium/services/data_decoder/image_decoder_impl_unittest.cc
@@ -28,6 +28,16 @@ namespace {
const int64_t kTestMaxImageSize = 128 * 1024;
+#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
+#if defined(USE_V8_CONTEXT_SNAPSHOT)
+constexpr gin::V8Initializer::V8SnapshotFileType kSnapshotType =
+ gin::V8Initializer::V8SnapshotFileType::kWithAdditionalContext;
+#else
+constexpr gin::V8Initializer::V8SnapshotFileType kSnapshotType =
+ gin::V8Initializer::V8SnapshotFileType::kDefault;
+#endif
+#endif
+
bool CreateJPEGImage(int width,
int height,
SkColor color,
@@ -72,11 +82,8 @@ class BlinkInitializer : public blink::Platform {
: main_thread_(
blink::scheduler::WebThreadBase::InitializeUtilityThread()) {
#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
- gin::V8Initializer::LoadV8Snapshot();
+ gin::V8Initializer::LoadV8Snapshot(kSnapshotType);
gin::V8Initializer::LoadV8Natives();
-#if defined(USE_V8_CONTEXT_SNAPSHOT)
- gin::V8Initializer::LoadV8ContextSnapshot();
-#endif // USE_V8_CONTEXT_SNAPSHOT
#endif // V8_USE_EXTERNAL_STARTUP_DATA
service_manager::BinderRegistry empty_registry;
diff --git a/chromium/services/data_decoder/json_parser_impl.h b/chromium/services/data_decoder/json_parser_impl.h
index 9656d04b22e..e965e6ea326 100644
--- a/chromium/services/data_decoder/json_parser_impl.h
+++ b/chromium/services/data_decoder/json_parser_impl.h
@@ -8,7 +8,7 @@
#include <string>
#include "base/macros.h"
-#include "services/data_decoder/public/interfaces/json_parser.mojom.h"
+#include "services/data_decoder/public/mojom/json_parser.mojom.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
namespace data_decoder {
diff --git a/chromium/services/data_decoder/public/cpp/BUILD.gn b/chromium/services/data_decoder/public/cpp/BUILD.gn
index 7ddbc0b9b50..64043ce19c6 100644
--- a/chromium/services/data_decoder/public/cpp/BUILD.gn
+++ b/chromium/services/data_decoder/public/cpp/BUILD.gn
@@ -20,7 +20,7 @@ source_set("cpp") {
]
public_deps = [
- "//services/data_decoder/public/interfaces",
+ "//services/data_decoder/public/mojom",
"//services/service_manager/public/cpp",
]
diff --git a/chromium/services/data_decoder/public/cpp/decode_image.cc b/chromium/services/data_decoder/public/cpp/decode_image.cc
index 60a6bff7b96..9674ef0b49e 100644
--- a/chromium/services/data_decoder/public/cpp/decode_image.cc
+++ b/chromium/services/data_decoder/public/cpp/decode_image.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/bind_helpers.h"
-#include "services/data_decoder/public/interfaces/constants.mojom.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chromium/services/data_decoder/public/cpp/decode_image.h b/chromium/services/data_decoder/public/cpp/decode_image.h
index 1b015abaab9..886e44b5155 100644
--- a/chromium/services/data_decoder/public/cpp/decode_image.h
+++ b/chromium/services/data_decoder/public/cpp/decode_image.h
@@ -9,7 +9,7 @@
#include <vector>
-#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
+#include "services/data_decoder/public/mojom/image_decoder.mojom.h"
namespace gfx {
class Size;
diff --git a/chromium/services/data_decoder/public/cpp/safe_json_parser_impl.cc b/chromium/services/data_decoder/public/cpp/safe_json_parser_impl.cc
index 67a34267114..f37bbbb3e56 100644
--- a/chromium/services/data_decoder/public/cpp/safe_json_parser_impl.cc
+++ b/chromium/services/data_decoder/public/cpp/safe_json_parser_impl.cc
@@ -10,9 +10,9 @@
#include "base/threading/sequenced_task_runner_handle.h"
#include "base/unguessable_token.h"
#include "base/values.h"
-#include "services/data_decoder/public/interfaces/constants.mojom.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/mojom/constants.mojom.h"
namespace data_decoder {
diff --git a/chromium/services/data_decoder/public/cpp/safe_json_parser_impl.h b/chromium/services/data_decoder/public/cpp/safe_json_parser_impl.h
index a17a91ae6c5..e2c4f6664f2 100644
--- a/chromium/services/data_decoder/public/cpp/safe_json_parser_impl.h
+++ b/chromium/services/data_decoder/public/cpp/safe_json_parser_impl.h
@@ -13,7 +13,7 @@
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "services/data_decoder/public/cpp/safe_json_parser.h"
-#include "services/data_decoder/public/interfaces/json_parser.mojom.h"
+#include "services/data_decoder/public/mojom/json_parser.mojom.h"
namespace base {
class Value;
diff --git a/chromium/services/data_decoder/public/cpp/safe_xml_parser.cc b/chromium/services/data_decoder/public/cpp/safe_xml_parser.cc
index 54d7585be72..3a43cb72b76 100644
--- a/chromium/services/data_decoder/public/cpp/safe_xml_parser.cc
+++ b/chromium/services/data_decoder/public/cpp/safe_xml_parser.cc
@@ -9,10 +9,10 @@
#include "base/threading/thread_checker.h"
#include "base/unguessable_token.h"
#include "base/values.h"
-#include "services/data_decoder/public/interfaces/constants.mojom.h"
-#include "services/data_decoder/public/interfaces/xml_parser.mojom.h"
+#include "services/data_decoder/public/mojom/constants.mojom.h"
+#include "services/data_decoder/public/mojom/xml_parser.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/mojom/constants.mojom.h"
namespace data_decoder {
diff --git a/chromium/services/data_decoder/public/interfaces/BUILD.gn b/chromium/services/data_decoder/public/mojom/BUILD.gn
index 7dac2c1bc3d..25fb5fe109d 100644
--- a/chromium/services/data_decoder/public/interfaces/BUILD.gn
+++ b/chromium/services/data_decoder/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"image_decoder.mojom",
"json_parser.mojom",
diff --git a/chromium/services/data_decoder/public/interfaces/OWNERS b/chromium/services/data_decoder/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/data_decoder/public/interfaces/OWNERS
+++ b/chromium/services/data_decoder/public/mojom/OWNERS
diff --git a/chromium/services/data_decoder/public/interfaces/constants.mojom b/chromium/services/data_decoder/public/mojom/constants.mojom
index 60a96f275bd..60a96f275bd 100644
--- a/chromium/services/data_decoder/public/interfaces/constants.mojom
+++ b/chromium/services/data_decoder/public/mojom/constants.mojom
diff --git a/chromium/services/data_decoder/public/interfaces/image_decoder.mojom b/chromium/services/data_decoder/public/mojom/image_decoder.mojom
index 4fa72b96a0c..4fa72b96a0c 100644
--- a/chromium/services/data_decoder/public/interfaces/image_decoder.mojom
+++ b/chromium/services/data_decoder/public/mojom/image_decoder.mojom
diff --git a/chromium/services/data_decoder/public/interfaces/json_parser.mojom b/chromium/services/data_decoder/public/mojom/json_parser.mojom
index 502a16bf976..502a16bf976 100644
--- a/chromium/services/data_decoder/public/interfaces/json_parser.mojom
+++ b/chromium/services/data_decoder/public/mojom/json_parser.mojom
diff --git a/chromium/services/data_decoder/public/interfaces/xml_parser.mojom b/chromium/services/data_decoder/public/mojom/xml_parser.mojom
index edb1de90ddb..edb1de90ddb 100644
--- a/chromium/services/data_decoder/public/interfaces/xml_parser.mojom
+++ b/chromium/services/data_decoder/public/mojom/xml_parser.mojom
diff --git a/chromium/services/data_decoder/xml_parser.h b/chromium/services/data_decoder/xml_parser.h
index 44a51ed1866..2ef4df4e45e 100644
--- a/chromium/services/data_decoder/xml_parser.h
+++ b/chromium/services/data_decoder/xml_parser.h
@@ -9,7 +9,7 @@
#include <string>
#include "base/macros.h"
-#include "services/data_decoder/public/interfaces/xml_parser.mojom.h"
+#include "services/data_decoder/public/mojom/xml_parser.mojom.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
namespace data_decoder {
diff --git a/chromium/services/device/BUILD.gn b/chromium/services/device/BUILD.gn
index c9dee83e500..20301dbd005 100644
--- a/chromium/services/device/BUILD.gn
+++ b/chromium/services/device/BUILD.gn
@@ -28,15 +28,12 @@ source_set("lib") {
deps = [
"//base",
"//device/geolocation",
- "//device/geolocation/public/interfaces",
- "//device/sensors",
- "//device/sensors/public/interfaces",
"//services/device/fingerprint",
"//services/device/generic_sensor",
"//services/device/geolocation",
"//services/device/power_monitor",
"//services/device/public/cpp:device_features",
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
"//services/device/screen_orientation",
"//services/device/time_zone_monitor",
"//services/device/wake_lock",
@@ -82,6 +79,7 @@ source_set("tests") {
"generic_sensor/platform_sensor_fusion_unittest.cc",
"generic_sensor/platform_sensor_provider_unittest_android.cc",
"generic_sensor/relative_orientation_euler_angles_fusion_algorithm_using_accelerometer_unittest.cc",
+ "geolocation/geolocation_service_unittest.cc",
"geolocation/public_ip_address_geolocator_unittest.cc",
"geolocation/public_ip_address_location_notifier_unittest.cc",
"power_monitor/power_monitor_message_broadcaster_unittest.cc",
@@ -95,8 +93,8 @@ source_set("tests") {
"//base",
"//base/test:test_support",
"//device/base/synchronization",
+ "//device/geolocation",
"//device/geolocation/public/cpp",
- "//device/geolocation/public/interfaces",
"//mojo/edk/embedder:headers",
"//mojo/public/cpp/bindings",
"//net",
@@ -106,6 +104,7 @@ source_set("tests") {
"//services/device/power_monitor",
"//services/device/public/cpp:device_features",
"//services/device/public/cpp/power_monitor",
+ "//services/device/public/mojom",
"//services/device/wake_lock",
"//testing/gmock",
"//testing/gtest",
@@ -218,7 +217,7 @@ source_set("test_support") {
"//mojo/public/cpp/bindings",
"//net",
"//net:test_support",
- "//services/device/public/interfaces:constants",
+ "//services/device/public/mojom:constants",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
]
@@ -244,23 +243,26 @@ if (is_android) {
"//content/public/android:*",
"//services:*",
]
- java_files = [ "android/java/src/org/chromium/services/device/InterfaceRegistrar.java" ]
+ java_files = [
+ "android/java/src/org/chromium/services/device/InterfaceRegistrar.java",
+ ]
deps = [
"//base:base_java",
+ "//device/geolocation:geolocation_java",
"//mojo/android:system_java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
"//services/device/battery/android:battery_monitor_java",
"//services/device/generic_sensor:java",
"//services/device/nfc/android:java",
- "//services/device/public/interfaces:interfaces_java",
"//services/device/public/java:nfc_java",
+ "//services/device/public/mojom:mojom_java",
"//services/device/screen_orientation:java",
"//services/device/time_zone_monitor:java",
"//services/device/vibration/android:vibration_manager_java",
"//services/device/wake_lock/power_save_blocker:java",
- "//services/service_manager/public/interfaces:interfaces_java",
"//services/service_manager/public/java:service_manager_java",
+ "//services/service_manager/public/mojom:mojom_java",
]
}
}
diff --git a/chromium/services/device/battery/BUILD.gn b/chromium/services/device/battery/BUILD.gn
index 4f8a2a980f3..815adaa5bbb 100644
--- a/chromium/services/device/battery/BUILD.gn
+++ b/chromium/services/device/battery/BUILD.gn
@@ -30,7 +30,7 @@ if (!is_android) {
]
public_deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
deps = [
diff --git a/chromium/services/device/battery/android/BUILD.gn b/chromium/services/device/battery/android/BUILD.gn
index 86aed8ea884..4647cfb110d 100644
--- a/chromium/services/device/battery/android/BUILD.gn
+++ b/chromium/services/device/battery/android/BUILD.gn
@@ -17,7 +17,7 @@ android_library("battery_monitor_java") {
"//base:base_java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
- "//services/device/public/interfaces:interfaces_java",
+ "//services/device/public/mojom:mojom_java",
"//services/service_manager/public/java:service_manager_java",
"//third_party/jsr-305:jsr_305_javalib",
]
diff --git a/chromium/services/device/battery/battery_monitor_impl.h b/chromium/services/device/battery/battery_monitor_impl.h
index 511e7396e96..dd365465bd7 100644
--- a/chromium/services/device/battery/battery_monitor_impl.h
+++ b/chromium/services/device/battery/battery_monitor_impl.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/device/battery/battery_status_service.h"
-#include "services/device/public/interfaces/battery_monitor.mojom.h"
+#include "services/device/public/mojom/battery_monitor.mojom.h"
namespace device {
diff --git a/chromium/services/device/battery/battery_monitor_impl_unittest.cc b/chromium/services/device/battery/battery_monitor_impl_unittest.cc
index c7a6c73cafb..4b89cc376ab 100644
--- a/chromium/services/device/battery/battery_monitor_impl_unittest.cc
+++ b/chromium/services/device/battery/battery_monitor_impl_unittest.cc
@@ -13,8 +13,8 @@
#include "services/device/battery/battery_status_manager.h"
#include "services/device/battery/battery_status_service.h"
#include "services/device/device_service_test_base.h"
-#include "services/device/public/interfaces/battery_monitor.mojom.h"
-#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/device/public/mojom/battery_monitor.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
// These tests run against the implementation of the BatteryMonitor interface
// inside Device Service, with a dummy BatteryManager set as a source of the
diff --git a/chromium/services/device/battery/battery_status_manager_linux.cc b/chromium/services/device/battery/battery_status_manager_linux.cc
index a75552d826d..157a2c60d0f 100644
--- a/chromium/services/device/battery/battery_status_manager_linux.cc
+++ b/chromium/services/device/battery/battery_status_manager_linux.cc
@@ -95,7 +95,7 @@ UPowerObject::UPowerObject(
UPowerObject::~UPowerObject() {
properties_.reset(); // before the proxy is deleted.
dbus_->RemoveObjectProxy(kUPowerServiceName, proxy_->object_path(),
- base::Bind(&base::DoNothing));
+ base::DoNothing());
}
std::vector<dbus::ObjectPath> UPowerObject::EnumerateDevices() {
@@ -261,7 +261,7 @@ BatteryObject::BatteryObject(
BatteryObject::~BatteryObject() {
properties_.reset(); // before the proxy is deleted.
dbus_->RemoveObjectProxy(kUPowerServiceName, proxy_->object_path(),
- base::Bind(&base::DoNothing));
+ base::DoNothing());
}
bool BatteryObject::IsValid() const {
@@ -307,10 +307,6 @@ mojom::BatteryStatus ComputeWebBatteryStatus(BatteryProperties* properties) {
return status;
}
-void OnSignalConnectedDoNothing(const std::string& interface_name,
- const std::string& signal_name,
- bool success) {}
-
} // namespace
// Class that represents a dedicated thread which communicates with DBus to
@@ -349,12 +345,12 @@ class BatteryStatusManagerLinux::BatteryStatusNotificationThread
kUPowerServiceName, kUPowerSignalDeviceAdded,
base::Bind(&BatteryStatusNotificationThread::DeviceAdded,
base::Unretained(this)),
- base::Bind(&OnSignalConnectedDoNothing));
+ base::DoNothing());
upower_->proxy()->ConnectToSignal(
kUPowerServiceName, kUPowerSignalDeviceRemoved,
base::Bind(&BatteryStatusNotificationThread::DeviceRemoved,
base::Unretained(this)),
- base::Bind(&OnSignalConnectedDoNothing));
+ base::DoNothing());
FindBatteryDevice();
}
@@ -464,7 +460,7 @@ class BatteryStatusManagerLinux::BatteryStatusNotificationThread
kUPowerDeviceInterfaceName, kUPowerDeviceSignalChanged,
base::Bind(&BatteryStatusNotificationThread::BatteryChanged,
base::Unretained(this)),
- base::Bind(&OnSignalConnectedDoNothing));
+ base::DoNothing());
}
}
diff --git a/chromium/services/device/battery/battery_status_manager_linux.h b/chromium/services/device/battery/battery_status_manager_linux.h
index d1b6c8dbbad..ca1d9b0acd5 100644
--- a/chromium/services/device/battery/battery_status_manager_linux.h
+++ b/chromium/services/device/battery/battery_status_manager_linux.h
@@ -5,7 +5,7 @@
#define SERVICES_DEVICE_BATTERY_BATTERY_STATUS_MANAGER_LINUX_H_
#include "services/device/battery/battery_status_manager.h"
-#include "services/device/public/interfaces/battery_status.mojom.h"
+#include "services/device/public/mojom/battery_status.mojom.h"
namespace dbus {
class Bus;
diff --git a/chromium/services/device/battery/battery_status_manager_win.h b/chromium/services/device/battery/battery_status_manager_win.h
index ca34ad3a049..fdb12b303ad 100644
--- a/chromium/services/device/battery/battery_status_manager_win.h
+++ b/chromium/services/device/battery/battery_status_manager_win.h
@@ -6,7 +6,7 @@
#define SERVICES_DEVICE_BATTERY_BATTERY_STATUS_MANAGER_WIN_H_
#include <windows.h>
-#include "services/device/public/interfaces/battery_status.mojom.h"
+#include "services/device/public/mojom/battery_status.mojom.h"
namespace device {
diff --git a/chromium/services/device/battery/battery_status_service.h b/chromium/services/device/battery/battery_status_service.h
index 1712b384793..bb6171bc830 100644
--- a/chromium/services/device/battery/battery_status_service.h
+++ b/chromium/services/device/battery/battery_status_service.h
@@ -10,7 +10,7 @@
#include "base/callback_list.h"
#include "base/macros.h"
#include "base/memory/singleton.h"
-#include "services/device/public/interfaces/battery_status.mojom.h"
+#include "services/device/public/mojom/battery_status.mojom.h"
namespace base {
class SingleThreadTaskRunner;
diff --git a/chromium/services/device/device_service.cc b/chromium/services/device/device_service.cc
index 78104d86c9b..edadd8a9853 100644
--- a/chromium/services/device/device_service.cc
+++ b/chromium/services/device/device_service.cc
@@ -14,14 +14,13 @@
#include "build/build_config.h"
#include "device/geolocation/geolocation_config.h"
#include "device/geolocation/geolocation_context.h"
-#include "device/geolocation/geolocation_provider_impl.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "services/device/fingerprint/fingerprint.h"
#include "services/device/generic_sensor/sensor_provider_impl.h"
#include "services/device/geolocation/public_ip_address_geolocator.h"
#include "services/device/geolocation/public_ip_address_location_notifier.h"
#include "services/device/power_monitor/power_monitor_message_broadcaster.h"
-#include "services/device/public/interfaces/battery_monitor.mojom.h"
+#include "services/device/public/mojom/battery_monitor.mojom.h"
#include "services/device/serial/serial_device_enumerator_impl.h"
#include "services/device/serial/serial_io_handler_impl.h"
#include "services/device/time_zone_monitor/time_zone_monitor.h"
@@ -55,7 +54,8 @@ std::unique_ptr<service_manager::Service> CreateDeviceService(
const WakeLockContextCallback& wake_lock_context_callback,
const CustomLocationProviderCallback& custom_location_provider_callback,
const base::android::JavaRef<jobject>& java_nfc_delegate) {
- GeolocationProviderImpl::SetCustomLocationProviderCallback(
+ GeolocationProviderImpl::SetGeolocationGlobals(
+ geolocation_request_context_producer, geolocation_api_key,
custom_location_provider_callback);
return std::make_unique<DeviceService>(
std::move(file_task_runner), std::move(io_task_runner),
@@ -70,7 +70,8 @@ std::unique_ptr<service_manager::Service> CreateDeviceService(
geolocation_request_context_producer,
const std::string& geolocation_api_key,
const CustomLocationProviderCallback& custom_location_provider_callback) {
- GeolocationProviderImpl::SetCustomLocationProviderCallback(
+ GeolocationProviderImpl::SetGeolocationGlobals(
+ geolocation_request_context_producer, geolocation_api_key,
custom_location_provider_callback);
return std::make_unique<DeviceService>(
std::move(file_task_runner), std::move(io_task_runner),
diff --git a/chromium/services/device/device_service.h b/chromium/services/device/device_service.h
index 74c49be69c2..46304ddd832 100644
--- a/chromium/services/device/device_service.h
+++ b/chromium/services/device/device_service.h
@@ -9,22 +9,22 @@
#include "build/build_config.h"
#include "device/geolocation/geolocation_provider.h"
#include "device/geolocation/geolocation_provider_impl.h"
-#include "device/geolocation/public/interfaces/geolocation.mojom.h"
-#include "device/screen_orientation/public/interfaces/screen_orientation.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/device/geolocation/public_ip_address_geolocation_provider.h"
-#include "services/device/public/interfaces/battery_monitor.mojom.h"
-#include "services/device/public/interfaces/fingerprint.mojom.h"
-#include "services/device/public/interfaces/geolocation_config.mojom.h"
-#include "services/device/public/interfaces/geolocation_context.mojom.h"
-#include "services/device/public/interfaces/geolocation_control.mojom.h"
-#include "services/device/public/interfaces/nfc_provider.mojom.h"
-#include "services/device/public/interfaces/power_monitor.mojom.h"
-#include "services/device/public/interfaces/sensor_provider.mojom.h"
-#include "services/device/public/interfaces/serial.mojom.h"
-#include "services/device/public/interfaces/time_zone_monitor.mojom.h"
-#include "services/device/public/interfaces/vibration_manager.mojom.h"
-#include "services/device/public/interfaces/wake_lock_provider.mojom.h"
+#include "services/device/public/mojom/battery_monitor.mojom.h"
+#include "services/device/public/mojom/fingerprint.mojom.h"
+#include "services/device/public/mojom/geolocation.mojom.h"
+#include "services/device/public/mojom/geolocation_config.mojom.h"
+#include "services/device/public/mojom/geolocation_context.mojom.h"
+#include "services/device/public/mojom/geolocation_control.mojom.h"
+#include "services/device/public/mojom/nfc_provider.mojom.h"
+#include "services/device/public/mojom/power_monitor.mojom.h"
+#include "services/device/public/mojom/screen_orientation.mojom.h"
+#include "services/device/public/mojom/sensor_provider.mojom.h"
+#include "services/device/public/mojom/serial.mojom.h"
+#include "services/device/public/mojom/time_zone_monitor.mojom.h"
+#include "services/device/public/mojom/vibration_manager.mojom.h"
+#include "services/device/public/mojom/wake_lock_provider.mojom.h"
#include "services/device/wake_lock/wake_lock_context.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_provider.h"
@@ -33,11 +33,11 @@
#if defined(OS_ANDROID)
#include "base/android/scoped_java_ref.h"
#else
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
#endif
#if defined(OS_LINUX) && defined(USE_UDEV)
-#include "services/device/public/interfaces/input_service.mojom.h"
+#include "services/device/public/mojom/input_service.mojom.h"
#endif
namespace base {
diff --git a/chromium/services/device/device_service_test_base.cc b/chromium/services/device/device_service_test_base.cc
index cfe2e3e2e5b..023b7ca1b36 100644
--- a/chromium/services/device/device_service_test_base.cc
+++ b/chromium/services/device/device_service_test_base.cc
@@ -12,17 +12,16 @@
#include "mojo/public/cpp/bindings/binding_set.h"
#include "net/url_request/url_request_test_util.h"
#include "services/device/device_service.h"
-#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
-#include "services/service_manager/public/interfaces/service_factory.mojom.h"
+#include "services/service_manager/public/mojom/service_factory.mojom.h"
namespace device {
namespace {
const char kTestServiceName[] = "device_unittests";
-const char kTestGeolocationApiKey[] = "";
// Simple request context producer that immediately produces a
// TestURLRequestContextGetter.
diff --git a/chromium/services/device/device_service_test_base.h b/chromium/services/device/device_service_test_base.h
index a3c73af44c5..279385381d4 100644
--- a/chromium/services/device/device_service_test_base.h
+++ b/chromium/services/device/device_service_test_base.h
@@ -11,6 +11,8 @@
namespace device {
+const char kTestGeolocationApiKey[] = "FakeApiKeyForTest";
+
// Base class responsible to setup Device Service for test.
class DeviceServiceTestBase : public service_manager::test::ServiceTest {
public:
diff --git a/chromium/services/device/fingerprint/BUILD.gn b/chromium/services/device/fingerprint/BUILD.gn
index c5f5cace7da..da55b12b6be 100644
--- a/chromium/services/device/fingerprint/BUILD.gn
+++ b/chromium/services/device/fingerprint/BUILD.gn
@@ -34,6 +34,6 @@ component("fingerprint") {
}
public_deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
}
diff --git a/chromium/services/device/fingerprint/fingerprint.h b/chromium/services/device/fingerprint/fingerprint.h
index c5600ec899b..83676e85b0f 100644
--- a/chromium/services/device/fingerprint/fingerprint.h
+++ b/chromium/services/device/fingerprint/fingerprint.h
@@ -6,7 +6,7 @@
#define SERVICES_DEVICE_FINGERPRINT_FINGERPRINT_H_
#include "services/device/fingerprint/fingerprint_export.h"
-#include "services/device/public/interfaces/fingerprint.mojom.h"
+#include "services/device/public/mojom/fingerprint.mojom.h"
namespace device {
diff --git a/chromium/services/device/fingerprint/fingerprint_chromeos.h b/chromium/services/device/fingerprint/fingerprint_chromeos.h
index 365e0b57703..46e690fcdc3 100644
--- a/chromium/services/device/fingerprint/fingerprint_chromeos.h
+++ b/chromium/services/device/fingerprint/fingerprint_chromeos.h
@@ -11,7 +11,7 @@
#include "chromeos/dbus/biod/biod_client.h"
#include "dbus/object_path.h"
#include "services/device/fingerprint/fingerprint_export.h"
-#include "services/device/public/interfaces/fingerprint.mojom.h"
+#include "services/device/public/mojom/fingerprint.mojom.h"
namespace device {
diff --git a/chromium/services/device/fingerprint/fingerprint_default.cc b/chromium/services/device/fingerprint/fingerprint_default.cc
index 263b2be7195..8c0ae7ea21b 100644
--- a/chromium/services/device/fingerprint/fingerprint_default.cc
+++ b/chromium/services/device/fingerprint/fingerprint_default.cc
@@ -3,7 +3,7 @@
// found in the LICENSE file.
#include "services/device/fingerprint/fingerprint.h"
-#include "services/device/public/interfaces/fingerprint.mojom.h"
+#include "services/device/public/mojom/fingerprint.mojom.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/BUILD.gn b/chromium/services/device/generic_sensor/BUILD.gn
index 4215ee5b8cf..4b81ba0188f 100644
--- a/chromium/services/device/generic_sensor/BUILD.gn
+++ b/chromium/services/device/generic_sensor/BUILD.gn
@@ -134,7 +134,7 @@ if (is_android) {
java_files = device_sensors_jni_sources
deps = [
"//base:base_java",
- "//services/device/public/interfaces:generic_sensor_java",
+ "//services/device/public/mojom:generic_sensor_java",
]
}
}
diff --git a/chromium/services/device/generic_sensor/README.md b/chromium/services/device/generic_sensor/README.md
index fe6e5605aa3..bdf8a075136 100644
--- a/chromium/services/device/generic_sensor/README.md
+++ b/chromium/services/device/generic_sensor/README.md
@@ -3,7 +3,7 @@
`services/device/generic_sensor` contains the platform-specific parts of the Sensor APIs
implementation.
-Sensors Mojo interfaces are defined in the `services/device/public/interfaces` subdirectory.
+Sensors Mojo interfaces are defined in the `services/device/public/mojom` subdirectory.
## Web-exposed Interfaces
diff --git a/chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.cc b/chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.cc
index 166f9951490..0d53e3bc906 100644
--- a/chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.cc
+++ b/chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.cc
@@ -51,7 +51,7 @@ mojom::ReportingMode FakePlatformSensor::GetReportingMode() {
}
double FakePlatformSensor::GetMaximumSupportedFrequency() {
- return 50.0;
+ return maximum_supported_frequency_;
}
double FakePlatformSensor::GetMinimumSupportedFrequency() {
diff --git a/chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.h b/chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.h
index 79cf9cd1fc1..eeaac4f02f3 100644
--- a/chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.h
+++ b/chromium/services/device/generic_sensor/fake_platform_sensor_and_provider.h
@@ -22,6 +22,10 @@ class FakePlatformSensor : public PlatformSensor {
MOCK_METHOD1(StartSensor,
bool(const PlatformSensorConfiguration& configuration));
+ void set_maximum_supported_frequency(double maximum_supported_frequency) {
+ maximum_supported_frequency_ = maximum_supported_frequency;
+ }
+
protected:
void StopSensor() override {}
@@ -35,6 +39,8 @@ class FakePlatformSensor : public PlatformSensor {
double GetMaximumSupportedFrequency() override;
double GetMinimumSupportedFrequency() override;
+ double maximum_supported_frequency_ = 50.0;
+
~FakePlatformSensor() override;
DISALLOW_COPY_AND_ASSIGN(FakePlatformSensor);
diff --git a/chromium/services/device/generic_sensor/generic_sensor_service_unittest.cc b/chromium/services/device/generic_sensor/generic_sensor_service_unittest.cc
index cd965f40402..a2f0d2d0be9 100644
--- a/chromium/services/device/generic_sensor/generic_sensor_service_unittest.cc
+++ b/chromium/services/device/generic_sensor/generic_sensor_service_unittest.cc
@@ -22,7 +22,7 @@
#include "services/device/public/cpp/device_features.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading.h"
#include "services/device/public/cpp/generic_sensor/sensor_traits.h"
-#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
using ::testing::_;
using ::testing::Invoke;
@@ -61,8 +61,10 @@ class TestSensorClient : public mojom::SensorClient {
// Sensor mojo interfaces callbacks:
void OnSensorCreated(base::OnceClosure quit_closure,
+ mojom::SensorCreationResult result,
mojom::SensorInitParamsPtr params) {
ASSERT_TRUE(params);
+ EXPECT_EQ(mojom::SensorCreationResult::SUCCESS, result);
EXPECT_TRUE(params->memory.is_valid());
const double expected_default_frequency =
std::min(30.0, GetSensorMaxAllowedFrequency(type_));
@@ -250,10 +252,9 @@ TEST_F(GenericSensorServiceTest, ValidAddConfigurationTest) {
PlatformSensorConfiguration configuration(50.0);
client->sensor()->AddConfiguration(
configuration,
- base::BindOnce(&TestSensorClient::OnAddConfiguration,
- base::Unretained(client.get()),
- base::BindOnce(&CheckSuccess,
- base::BindOnce(&base::DoNothing), true)));
+ base::BindOnce(
+ &TestSensorClient::OnAddConfiguration, base::Unretained(client.get()),
+ base::BindOnce(&CheckSuccess, base::DoNothing::Once<>(), true)));
{
// Expect the SensorReadingChanged() will be called after AddConfiguration.
@@ -395,10 +396,9 @@ TEST_F(GenericSensorServiceTest, AddAndRemoveConfigurationTest) {
PlatformSensorConfiguration configuration_30(30.0);
client->sensor()->AddConfiguration(
configuration_30,
- base::BindOnce(&TestSensorClient::OnAddConfiguration,
- base::Unretained(client.get()),
- base::BindOnce(&CheckSuccess,
- base::BindOnce(&base::DoNothing), true)));
+ base::BindOnce(
+ &TestSensorClient::OnAddConfiguration, base::Unretained(client.get()),
+ base::BindOnce(&CheckSuccess, base::DoNothing::Once<>(), true)));
{
base::RunLoop run_loop;
client->SetCheckValueCallback(base::BindOnce(&CheckValue, 30.0));
@@ -413,10 +413,10 @@ TEST_F(GenericSensorServiceTest, AddAndRemoveConfigurationTest) {
PlatformSensorConfiguration configuration_20(20.0);
client->sensor()->AddConfiguration(
configuration_20,
- base::BindOnce(&TestSensorClient::OnAddConfiguration,
- base::Unretained(client.get()),
- base::BindOnce(&CheckSuccess,
- base::BindOnce(&base::DoNothing), true)));
+ base::BindOnce(
+ &TestSensorClient::OnAddConfiguration,
+ base::Unretained(client.get()),
+ base::BindOnce(&CheckSuccess, base::DoNothing::Once<>(), true)));
client->SetCheckValueCallback(base::BindOnce(&CheckValue, 30.0));
client->SetQuitClosure(run_loop.QuitClosure());
run_loop.Run();
@@ -462,10 +462,9 @@ TEST_F(GenericSensorServiceTest, SuspendTest) {
PlatformSensorConfiguration configuration_1(30.0);
client->sensor()->AddConfiguration(
configuration_1,
- base::BindOnce(&TestSensorClient::OnAddConfiguration,
- base::Unretained(client.get()),
- base::BindOnce(&CheckSuccess,
- base::BindOnce(&base::DoNothing), true)));
+ base::BindOnce(
+ &TestSensorClient::OnAddConfiguration, base::Unretained(client.get()),
+ base::BindOnce(&CheckSuccess, base::DoNothing::Once<>(), true)));
PlatformSensorConfiguration configuration_2(31.0);
client->sensor()->AddConfiguration(
configuration_2,
@@ -495,10 +494,10 @@ TEST_F(GenericSensorServiceTest, SuspendThenResumeTest) {
PlatformSensorConfiguration configuration_1(30.0);
client->sensor()->AddConfiguration(
configuration_1,
- base::BindOnce(&TestSensorClient::OnAddConfiguration,
- base::Unretained(client.get()),
- base::BindOnce(&CheckSuccess,
- base::BindOnce(&base::DoNothing), true)));
+ base::BindOnce(
+ &TestSensorClient::OnAddConfiguration,
+ base::Unretained(client.get()),
+ base::BindOnce(&CheckSuccess, base::DoNothing::Once<>(), true)));
client->SetCheckValueCallback(base::BindOnce(&CheckValue, 30.0));
client->SetQuitClosure(run_loop.QuitClosure());
run_loop.Run();
@@ -514,10 +513,10 @@ TEST_F(GenericSensorServiceTest, SuspendThenResumeTest) {
PlatformSensorConfiguration configuration_2(50.0);
client->sensor()->AddConfiguration(
configuration_2,
- base::BindOnce(&TestSensorClient::OnAddConfiguration,
- base::Unretained(client.get()),
- base::BindOnce(&CheckSuccess,
- base::BindOnce(&base::DoNothing), true)));
+ base::BindOnce(
+ &TestSensorClient::OnAddConfiguration,
+ base::Unretained(client.get()),
+ base::BindOnce(&CheckSuccess, base::DoNothing::Once<>(), true)));
client->SetCheckValueCallback(base::BindOnce(&CheckValue, 50.0));
client->SetQuitClosure(run_loop.QuitClosure());
run_loop.Run();
diff --git a/chromium/services/device/generic_sensor/linux/sensor_data_linux.h b/chromium/services/device/generic_sensor/linux/sensor_data_linux.h
index f3bd1a6ee42..2be71af4fc0 100644
--- a/chromium/services/device/generic_sensor/linux/sensor_data_linux.h
+++ b/chromium/services/device/generic_sensor/linux/sensor_data_linux.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_DEVICE_GENERIC_SENSOR_LINUX_SENSOR_DATA_LINUX_H_
#define SERVICES_DEVICE_GENERIC_SENSOR_LINUX_SENSOR_DATA_LINUX_H_
-#include "services/device/public/interfaces/sensor.mojom.h"
+#include "services/device/public/mojom/sensor.mojom.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/linux/sensor_device_manager.h b/chromium/services/device/generic_sensor/linux/sensor_device_manager.h
index 9ac4d396a3f..84e50b50703 100644
--- a/chromium/services/device/generic_sensor/linux/sensor_device_manager.h
+++ b/chromium/services/device/generic_sensor/linux/sensor_device_manager.h
@@ -8,7 +8,7 @@
#include "base/scoped_observer.h"
#include "base/single_thread_task_runner.h"
#include "device/base/device_monitor_linux.h"
-#include "services/device/public/interfaces/sensor.mojom.h"
+#include "services/device/public/mojom/sensor.mojom.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/platform_sensor.h b/chromium/services/device/generic_sensor/platform_sensor.h
index 76aac492cd0..07647b3b9a2 100644
--- a/chromium/services/device/generic_sensor/platform_sensor.h
+++ b/chromium/services/device/generic_sensor/platform_sensor.h
@@ -16,7 +16,7 @@
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/system/buffer.h"
#include "services/device/public/cpp/generic_sensor/sensor_reading.h"
-#include "services/device/public/interfaces/sensor.mojom.h"
+#include "services/device/public/mojom/sensor.mojom.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc b/chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
index e0c5d016dfb..345b964bb8d 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_and_provider_unittest_win.cc
@@ -16,7 +16,7 @@
#include "services/device/generic_sensor/fake_platform_sensor_and_provider.h"
#include "services/device/generic_sensor/generic_sensor_consts.h"
#include "services/device/generic_sensor/platform_sensor_provider_win.h"
-#include "services/device/public/interfaces/sensor_provider.mojom.h"
+#include "services/device/public/mojom/sensor_provider.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/angle_conversions.h"
diff --git a/chromium/services/device/generic_sensor/platform_sensor_fusion.cc b/chromium/services/device/generic_sensor/platform_sensor_fusion.cc
index d7168a2b224..168120347f9 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_fusion.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_fusion.cc
@@ -4,6 +4,8 @@
#include "services/device/generic_sensor/platform_sensor_fusion.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "base/memory/scoped_refptr.h"
#include "services/device/generic_sensor/platform_sensor_fusion_algorithm.h"
@@ -144,7 +146,10 @@ bool PlatformSensorFusion::StartSensor(
// Remove all the previously added source configs.
StopSensor();
for (const auto& pair : source_sensors_) {
- if (!pair.second->StartListening(this, configuration)) {
+ if (!pair.second->StartListening(
+ this, PlatformSensorConfiguration(
+ std::min(configuration.frequency(),
+ pair.second->GetMaximumSupportedFrequency())))) {
StopSensor();
return false;
}
@@ -164,12 +169,23 @@ void PlatformSensorFusion::StopSensor() {
bool PlatformSensorFusion::CheckSensorConfiguration(
const PlatformSensorConfiguration& configuration) {
for (const auto& pair : source_sensors_) {
- if (!pair.second->CheckSensorConfiguration(configuration))
+ if (!pair.second->CheckSensorConfiguration(PlatformSensorConfiguration(
+ std::min(configuration.frequency(),
+ pair.second->GetMaximumSupportedFrequency()))))
return false;
}
return true;
}
+double PlatformSensorFusion::GetMaximumSupportedFrequency() {
+ double maximum_frequency = 0.0;
+ for (const auto& pair : source_sensors_) {
+ maximum_frequency = std::max(maximum_frequency,
+ pair.second->GetMaximumSupportedFrequency());
+ }
+ return maximum_frequency;
+}
+
void PlatformSensorFusion::OnSensorReadingChanged(mojom::SensorType type) {
SensorReading reading;
reading.raw.timestamp =
diff --git a/chromium/services/device/generic_sensor/platform_sensor_fusion.h b/chromium/services/device/generic_sensor/platform_sensor_fusion.h
index 0ce3d9fb60f..d25a5abde5d 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_fusion.h
+++ b/chromium/services/device/generic_sensor/platform_sensor_fusion.h
@@ -48,6 +48,7 @@ class PlatformSensorFusion : public PlatformSensor,
PlatformSensorConfiguration GetDefaultConfiguration() override;
bool CheckSensorConfiguration(
const PlatformSensorConfiguration& configuration) override;
+ double GetMaximumSupportedFrequency() override;
// PlatformSensor::Client:
void OnSensorReadingChanged(mojom::SensorType type) override;
diff --git a/chromium/services/device/generic_sensor/platform_sensor_fusion_unittest.cc b/chromium/services/device/generic_sensor/platform_sensor_fusion_unittest.cc
index 91106d5734d..e7ac303437a 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_fusion_unittest.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_fusion_unittest.cc
@@ -328,4 +328,33 @@ TEST_F(PlatformSensorFusionTest,
EXPECT_FALSE(fusion_sensor_);
}
+TEST_F(PlatformSensorFusionTest,
+ FusionSensorMaximumSupportedFrequencyIsTheMaximumOfItsSourceSensors) {
+ EXPECT_FALSE(provider_->GetSensor(SensorType::ACCELEROMETER));
+ CreateAccelerometer();
+ scoped_refptr<PlatformSensor> accelerometer =
+ provider_->GetSensor(SensorType::ACCELEROMETER);
+ EXPECT_TRUE(accelerometer);
+ static_cast<FakePlatformSensor*>(accelerometer.get())
+ ->set_maximum_supported_frequency(30.0);
+
+ EXPECT_FALSE(provider_->GetSensor(SensorType::MAGNETOMETER));
+ CreateMagnetometer();
+ scoped_refptr<PlatformSensor> magnetometer =
+ provider_->GetSensor(SensorType::MAGNETOMETER);
+ EXPECT_TRUE(magnetometer);
+ static_cast<FakePlatformSensor*>(magnetometer.get())
+ ->set_maximum_supported_frequency(20.0);
+
+ CreateAbsoluteOrientationEulerAnglesFusionSensor();
+ EXPECT_TRUE(fusion_sensor_);
+ EXPECT_EQ(SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES,
+ fusion_sensor_->GetType());
+ EXPECT_EQ(30.0, fusion_sensor_->GetMaximumSupportedFrequency());
+ auto client = std::make_unique<testing::NiceMock<MockPlatformSensorClient>>(
+ fusion_sensor_);
+ EXPECT_TRUE(fusion_sensor_->StartListening(
+ client.get(), PlatformSensorConfiguration(30.0)));
+}
+
} // namespace device
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_base.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_base.cc
index 887d84ee79b..011e6e70810 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_base.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_base.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/stl_util.h"
-#include "services/device/public/interfaces/sensor_provider.mojom.h"
+#include "services/device/public/mojom/sensor_provider.mojom.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/platform_sensor_provider_win.cc b/chromium/services/device/generic_sensor/platform_sensor_provider_win.cc
index 15602986141..e6cade1dd7e 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_provider_win.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_provider_win.cc
@@ -4,8 +4,11 @@
#include "services/device/generic_sensor/platform_sensor_provider_win.h"
+#include <comdef.h>
#include <objbase.h>
+#include <iomanip>
+
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "base/task_runner_util.h"
@@ -33,8 +36,19 @@ class PlatformSensorProviderWin::SensorThread final : public base::Thread {
void Init() override {
if (sensor_manager_)
return;
- ::CoCreateInstance(CLSID_SensorManager, nullptr, CLSCTX_ALL,
- IID_PPV_ARGS(&sensor_manager_));
+ HRESULT hr = ::CoCreateInstance(CLSID_SensorManager, nullptr, CLSCTX_ALL,
+ IID_PPV_ARGS(&sensor_manager_));
+ if (FAILED(hr)) {
+ // Only log this error the first time.
+ static bool logged_failure = false;
+ if (!logged_failure) {
+ LOG(ERROR) << "Unable to create instance of SensorManager: "
+ << _com_error(hr).ErrorMessage() << " (0x" << std::hex
+ << std::uppercase << std::setfill('0') << std::setw(8) << hr
+ << ")";
+ logged_failure = true;
+ }
+ }
}
void CleanUp() override { sensor_manager_.Reset(); }
diff --git a/chromium/services/device/generic_sensor/platform_sensor_reader_win.cc b/chromium/services/device/generic_sensor/platform_sensor_reader_win.cc
index a9cfefc2280..93c9e059434 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_reader_win.cc
+++ b/chromium/services/device/generic_sensor/platform_sensor_reader_win.cc
@@ -5,8 +5,11 @@
#include "services/device/generic_sensor/platform_sensor_reader_win.h"
#include <Sensors.h>
+#include <comdef.h>
#include <objbase.h>
+#include <iomanip>
+
#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
@@ -454,21 +457,30 @@ void PlatformSensorReaderWin::ListenSensorEvent() {
bool PlatformSensorReaderWin::SetReportingInterval(
const PlatformSensorConfiguration& configuration) {
Microsoft::WRL::ComPtr<IPortableDeviceValues> props;
- if (SUCCEEDED(::CoCreateInstance(CLSID_PortableDeviceValues, nullptr,
- CLSCTX_ALL, IID_PPV_ARGS(&props)))) {
- unsigned interval =
- (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
-
- HRESULT hr = props->SetUnsignedIntegerValue(
- SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL, interval);
-
- if (SUCCEEDED(hr)) {
- Microsoft::WRL::ComPtr<IPortableDeviceValues> return_props;
- hr = sensor_->SetProperties(props.Get(), return_props.GetAddressOf());
- return SUCCEEDED(hr);
+ HRESULT hr = ::CoCreateInstance(CLSID_PortableDeviceValues, nullptr,
+ CLSCTX_ALL, IID_PPV_ARGS(&props));
+ if (FAILED(hr)) {
+ static bool logged_failure = false;
+ if (!logged_failure) {
+ LOG(ERROR) << "Unable to create instance of PortableDeviceValues: "
+ << _com_error(hr).ErrorMessage() << " (0x" << std::hex
+ << std::uppercase << std::setfill('0') << std::setw(8) << hr
+ << ")";
+ logged_failure = true;
}
+ return false;
}
- return false;
+
+ unsigned interval =
+ (1 / configuration.frequency()) * base::Time::kMillisecondsPerSecond;
+ hr = props->SetUnsignedIntegerValue(SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL,
+ interval);
+ if (FAILED(hr))
+ return false;
+
+ Microsoft::WRL::ComPtr<IPortableDeviceValues> return_props;
+ hr = sensor_->SetProperties(props.Get(), return_props.GetAddressOf());
+ return SUCCEEDED(hr);
}
HRESULT PlatformSensorReaderWin::SensorReadingChanged(
diff --git a/chromium/services/device/generic_sensor/platform_sensor_reader_win.h b/chromium/services/device/generic_sensor/platform_sensor_reader_win.h
index 1672a4e5edb..8b31ae2f4a0 100644
--- a/chromium/services/device/generic_sensor/platform_sensor_reader_win.h
+++ b/chromium/services/device/generic_sensor/platform_sensor_reader_win.h
@@ -8,7 +8,7 @@
#include <SensorsApi.h>
#include <wrl/client.h>
-#include "services/device/public/interfaces/sensor.mojom.h"
+#include "services/device/public/mojom/sensor.mojom.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/sensor_impl.h b/chromium/services/device/generic_sensor/sensor_impl.h
index 5c65a085336..e0002665667 100644
--- a/chromium/services/device/generic_sensor/sensor_impl.h
+++ b/chromium/services/device/generic_sensor/sensor_impl.h
@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "services/device/generic_sensor/platform_sensor.h"
-#include "services/device/public/interfaces/sensor.mojom.h"
+#include "services/device/public/mojom/sensor.mojom.h"
namespace device {
diff --git a/chromium/services/device/generic_sensor/sensor_provider_impl.cc b/chromium/services/device/generic_sensor/sensor_provider_impl.cc
index afb72075dea..4bfebc860c1 100644
--- a/chromium/services/device/generic_sensor/sensor_provider_impl.cc
+++ b/chromium/services/device/generic_sensor/sensor_provider_impl.cc
@@ -59,12 +59,14 @@ void SensorProviderImpl::GetSensor(mojom::SensorType type,
GetSensorCallback callback) {
if (!base::FeatureList::IsEnabled(features::kGenericSensorExtraClasses) &&
IsExtraSensorClass(type)) {
- std::move(callback).Run(nullptr);
+ std::move(callback).Run(mojom::SensorCreationResult::ERROR_NOT_AVAILABLE,
+ nullptr);
return;
}
auto cloned_handle = provider_->CloneSharedBufferHandle();
if (!cloned_handle.is_valid()) {
- std::move(callback).Run(nullptr);
+ std::move(callback).Run(mojom::SensorCreationResult::ERROR_NOT_AVAILABLE,
+ nullptr);
return;
}
@@ -87,7 +89,8 @@ void SensorProviderImpl::SensorCreated(
GetSensorCallback callback,
scoped_refptr<PlatformSensor> sensor) {
if (!sensor) {
- std::move(callback).Run(nullptr);
+ std::move(callback).Run(mojom::SensorCreationResult::ERROR_NOT_AVAILABLE,
+ nullptr);
return;
}
@@ -133,7 +136,8 @@ void SensorProviderImpl::SensorCreated(
DCHECK_GT(init_params->minimum_frequency, 0.0);
DCHECK_GE(init_params->maximum_frequency, init_params->minimum_frequency);
- std::move(callback).Run(std::move(init_params));
+ std::move(callback).Run(mojom::SensorCreationResult::SUCCESS,
+ std::move(init_params));
}
} // namespace device
diff --git a/chromium/services/device/generic_sensor/sensor_provider_impl.h b/chromium/services/device/generic_sensor/sensor_provider_impl.h
index 14ff07dd2ea..9ee9b998a4e 100644
--- a/chromium/services/device/generic_sensor/sensor_provider_impl.h
+++ b/chromium/services/device/generic_sensor/sensor_provider_impl.h
@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "base/single_thread_task_runner.h"
-#include "services/device/public/interfaces/sensor_provider.mojom.h"
+#include "services/device/public/mojom/sensor_provider.mojom.h"
namespace device {
diff --git a/chromium/services/device/geolocation/BUILD.gn b/chromium/services/device/geolocation/BUILD.gn
index 648d52a22ec..93d01d9bad1 100644
--- a/chromium/services/device/geolocation/BUILD.gn
+++ b/chromium/services/device/geolocation/BUILD.gn
@@ -21,6 +21,6 @@ source_set("geolocation") {
"//device/geolocation",
"//mojo/public/cpp/bindings",
"//net",
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
}
diff --git a/chromium/services/device/geolocation/DEPS b/chromium/services/device/geolocation/DEPS
index 8fa9d48d882..a352a55706a 100644
--- a/chromium/services/device/geolocation/DEPS
+++ b/chromium/services/device/geolocation/DEPS
@@ -1,3 +1,4 @@
include_rules = [
+ "+chromeos",
"+net",
]
diff --git a/chromium/services/device/geolocation/geolocation_service_unittest.cc b/chromium/services/device/geolocation/geolocation_service_unittest.cc
new file mode 100644
index 00000000000..5611a9492c7
--- /dev/null
+++ b/chromium/services/device/geolocation/geolocation_service_unittest.cc
@@ -0,0 +1,159 @@
+// Copyright 2018 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 "base/run_loop.h"
+#include "build/build_config.h"
+#if defined(OS_CHROMEOS)
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "chromeos/network/geolocation_handler.h"
+#endif
+#include "device/geolocation/geolocation_provider_impl.h"
+#include "device/geolocation/network_location_request.h"
+#include "mojo/public/cpp/bindings/interface_ptr.h"
+#include "net/url_request/test_url_fetcher_factory.h"
+#include "services/device/device_service_test_base.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/device/public/mojom/geolocation.mojom.h"
+#include "services/device/public/mojom/geolocation_config.mojom.h"
+#include "services/device/public/mojom/geolocation_context.mojom.h"
+#include "services/device/public/mojom/geolocation_control.mojom.h"
+
+namespace device {
+
+namespace {
+
+void CheckBoolReturnValue(base::OnceClosure quit_closure,
+ bool expect,
+ bool result) {
+ EXPECT_EQ(expect, result);
+ std::move(quit_closure).Run();
+}
+
+// Observer that waits until a TestURLFetcher with the specified fetcher_id
+// starts, after which it is made available through .fetcher().
+class TestURLFetcherObserver : public net::TestURLFetcher::DelegateForTests {
+ public:
+ explicit TestURLFetcherObserver(int expected_fetcher_id)
+ : expected_fetcher_id_(expected_fetcher_id) {
+ factory_.SetDelegateForTests(this);
+ }
+ virtual ~TestURLFetcherObserver() {}
+
+ void Wait() { loop_.Run(); }
+
+ net::TestURLFetcher* fetcher() { return fetcher_; }
+
+ // net::TestURLFetcher::DelegateForTests:
+ void OnRequestStart(int fetcher_id) override {
+ if (fetcher_id == expected_fetcher_id_) {
+ fetcher_ = factory_.GetFetcherByID(fetcher_id);
+ fetcher_->SetDelegateForTests(nullptr);
+ factory_.SetDelegateForTests(nullptr);
+ loop_.Quit();
+ }
+ }
+ void OnChunkUpload(int fetcher_id) override {}
+ void OnRequestEnd(int fetcher_id) override {}
+
+ private:
+ const int expected_fetcher_id_;
+ net::TestURLFetcher* fetcher_ = nullptr;
+ net::TestURLFetcherFactory factory_;
+ base::RunLoop loop_;
+};
+
+class GeolocationServiceUnitTest : public DeviceServiceTestBase {
+ public:
+ GeolocationServiceUnitTest() = default;
+ ~GeolocationServiceUnitTest() override = default;
+
+ protected:
+ void SetUp() override {
+ DeviceServiceTestBase::SetUp();
+
+#if defined(OS_CHROMEOS)
+ chromeos::DBusThreadManager::Initialize();
+ chromeos::NetworkHandler::Initialize();
+#endif
+
+ connector()->BindInterface(mojom::kServiceName, &geolocation_control_);
+ geolocation_control_->UserDidOptIntoLocationServices();
+
+ connector()->BindInterface(mojom::kServiceName, &geolocation_context_);
+ geolocation_context_->BindGeolocation(MakeRequest(&geolocation_));
+ }
+
+ void TearDown() override {
+ DeviceServiceTestBase::TearDown();
+
+#if defined(OS_CHROMEOS)
+ chromeos::NetworkHandler::Shutdown();
+ chromeos::DBusThreadManager::Shutdown();
+#endif
+
+ // Let the GeolocationImpl destruct earlier than GeolocationProviderImpl to
+ // make sure the base::CallbackList<> member in GeolocationProviderImpl is
+ // empty.
+ geolocation_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void BindGeolocationConfig() {
+ connector()->BindInterface(mojom::kServiceName, &geolocation_config_);
+ }
+
+ mojom::GeolocationControlPtr geolocation_control_;
+ mojom::GeolocationContextPtr geolocation_context_;
+ mojom::GeolocationPtr geolocation_;
+ mojom::GeolocationConfigPtr geolocation_config_;
+
+ DISALLOW_COPY_AND_ASSIGN(GeolocationServiceUnitTest);
+};
+
+#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
+// ChromeOS fails to perform network geolocation when zero wifi networks are
+// detected in a scan: https://crbug.com/767300.
+#else
+TEST_F(GeolocationServiceUnitTest, UrlWithApiKey) {
+ // Unique ID (derived from Gerrit CL number):
+ device::NetworkLocationRequest::url_fetcher_id_for_tests = 675023;
+
+ // Intercept the URLFetcher from network geolocation request.
+ TestURLFetcherObserver observer(
+ device::NetworkLocationRequest::url_fetcher_id_for_tests);
+
+ geolocation_->SetHighAccuracy(true);
+ observer.Wait();
+ DCHECK(observer.fetcher());
+
+ // Verify full URL including a fake Google API key.
+ std::string expected_url =
+ "https://www.googleapis.com/geolocation/v1/"
+ "geolocate?key=";
+ expected_url.append(kTestGeolocationApiKey);
+ EXPECT_EQ(expected_url, observer.fetcher()->GetOriginalURL());
+}
+#endif
+
+TEST_F(GeolocationServiceUnitTest, GeolocationConfig) {
+ BindGeolocationConfig();
+ {
+ base::RunLoop run_loop;
+ geolocation_config_->IsHighAccuracyLocationBeingCaptured(
+ base::BindOnce(&CheckBoolReturnValue, run_loop.QuitClosure(), false));
+ run_loop.Run();
+ }
+
+ geolocation_->SetHighAccuracy(true);
+ {
+ base::RunLoop run_loop;
+ geolocation_config_->IsHighAccuracyLocationBeingCaptured(
+ base::BindOnce(&CheckBoolReturnValue, run_loop.QuitClosure(), true));
+ run_loop.Run();
+ }
+}
+
+} // namespace
+
+} // namespace device
diff --git a/chromium/services/device/geolocation/public_ip_address_geolocation_provider.h b/chromium/services/device/geolocation/public_ip_address_geolocation_provider.h
index a0a0e9263ef..8888c95a8ba 100644
--- a/chromium/services/device/geolocation/public_ip_address_geolocation_provider.h
+++ b/chromium/services/device/geolocation/public_ip_address_geolocation_provider.h
@@ -8,13 +8,13 @@
#include <string>
#include "base/macros.h"
-#include "device/geolocation/public/interfaces/geolocation.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/device/geolocation/public_ip_address_geolocator.h"
#include "services/device/geolocation/public_ip_address_location_notifier.h"
-#include "services/device/public/interfaces/public_ip_address_geolocation_provider.mojom.h"
+#include "services/device/public/mojom/geolocation.mojom.h"
+#include "services/device/public/mojom/public_ip_address_geolocation_provider.mojom.h"
namespace device {
diff --git a/chromium/services/device/geolocation/public_ip_address_geolocator.h b/chromium/services/device/geolocation/public_ip_address_geolocator.h
index a52701200a3..ab74b888645 100644
--- a/chromium/services/device/geolocation/public_ip_address_geolocator.h
+++ b/chromium/services/device/geolocation/public_ip_address_geolocator.h
@@ -10,10 +10,10 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/time/time.h"
-#include "device/geolocation/public/interfaces/geolocation.mojom.h"
-#include "device/geolocation/public/interfaces/geoposition.mojom.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/device/geolocation/public_ip_address_location_notifier.h"
+#include "services/device/public/mojom/geolocation.mojom.h"
+#include "services/device/public/mojom/geoposition.mojom.h"
namespace device {
diff --git a/chromium/services/device/geolocation/public_ip_address_location_notifier.h b/chromium/services/device/geolocation/public_ip_address_location_notifier.h
index 0f4e84b0dfc..2742bb0e1b9 100644
--- a/chromium/services/device/geolocation/public_ip_address_location_notifier.h
+++ b/chromium/services/device/geolocation/public_ip_address_location_notifier.h
@@ -15,9 +15,9 @@
#include "base/time/time.h"
#include "device/geolocation/geolocation_provider.h"
#include "device/geolocation/network_location_request.h"
-#include "device/geolocation/public/interfaces/geoposition.mojom.h"
#include "net/base/network_change_notifier.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/device/public/mojom/geoposition.mojom.h"
namespace device {
diff --git a/chromium/services/device/geolocation/public_ip_address_location_notifier_unittest.cc b/chromium/services/device/geolocation/public_ip_address_location_notifier_unittest.cc
index 7744e0ad679..3322b1061ea 100644
--- a/chromium/services/device/geolocation/public_ip_address_location_notifier_unittest.cc
+++ b/chromium/services/device/geolocation/public_ip_address_location_notifier_unittest.cc
@@ -9,10 +9,10 @@
#include "base/strings/stringprintf.h"
#include "base/test/test_mock_time_task_runner.h"
#include "device/geolocation/public/cpp/geoposition.h"
-#include "device/geolocation/public/interfaces/geoposition.mojom.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
#include "net/url_request/test_url_fetcher_factory.h"
#include "net/url_request/url_request_test_util.h"
+#include "services/device/public/mojom/geoposition.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/device/hid/BUILD.gn b/chromium/services/device/hid/BUILD.gn
index 3ed04a27261..2725e6e84c1 100644
--- a/chromium/services/device/hid/BUILD.gn
+++ b/chromium/services/device/hid/BUILD.gn
@@ -38,7 +38,7 @@ source_set("hid") {
"//components/device_event_log",
"//device/base",
"//services/device/public/cpp/hid",
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
if (is_linux && use_udev) {
@@ -85,7 +85,7 @@ fuzzer_test("hid_report_descriptor_fuzzer") {
]
deps = [
"//services/device/public/cpp/hid",
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
seed_corpus = "fuzz_corpus"
libfuzzer_options = [ "max_len=2048" ]
diff --git a/chromium/services/device/hid/hid_connection.cc b/chromium/services/device/hid/hid_connection.cc
index 9ab2d6ee1df..8872bfb2605 100644
--- a/chromium/services/device/hid/hid_connection.cc
+++ b/chromium/services/device/hid/hid_connection.cc
@@ -10,7 +10,7 @@
#include "base/stl_util.h"
#include "components/device_event_log/device_event_log.h"
#include "services/device/public/cpp/hid/hid_usage_and_page.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/hid/hid_connection_impl.h b/chromium/services/device/hid/hid_connection_impl.h
index e037fc9d5fe..6ca4612e3dd 100644
--- a/chromium/services/device/hid/hid_connection_impl.h
+++ b/chromium/services/device/hid/hid_connection_impl.h
@@ -7,7 +7,7 @@
#include "base/memory/ref_counted.h"
#include "services/device/hid/hid_connection.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/hid/hid_connection_unittest.cc b/chromium/services/device/hid/hid_connection_unittest.cc
index 9e4ad2913fd..e319b3af577 100644
--- a/chromium/services/device/hid/hid_connection_unittest.cc
+++ b/chromium/services/device/hid/hid_connection_unittest.cc
@@ -21,7 +21,7 @@
#include "device/test/usb_test_gadget.h"
#include "device/usb/usb_device.h"
#include "services/device/hid/hid_service.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
diff --git a/chromium/services/device/hid/hid_device_info.h b/chromium/services/device/hid/hid_device_info.h
index f8304f617d1..5071b312605 100644
--- a/chromium/services/device/hid/hid_device_info.h
+++ b/chromium/services/device/hid/hid_device_info.h
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "build/build_config.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/hid/hid_manager_impl.h b/chromium/services/device/hid/hid_manager_impl.h
index b69f225c1e6..1ca9c0f787e 100644
--- a/chromium/services/device/hid/hid_manager_impl.h
+++ b/chromium/services/device/hid/hid_manager_impl.h
@@ -13,7 +13,7 @@
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/device/hid/hid_device_info.h"
#include "services/device/hid/hid_service.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/hid/hid_manager_unittest.cc b/chromium/services/device/hid/hid_manager_unittest.cc
index 6a600fd0744..95ac49e833f 100644
--- a/chromium/services/device/hid/hid_manager_unittest.cc
+++ b/chromium/services/device/hid/hid_manager_unittest.cc
@@ -12,8 +12,8 @@
#include "services/device/hid/hid_manager_impl.h"
#include "services/device/hid/mock_hid_connection.h"
#include "services/device/hid/mock_hid_service.h"
-#include "services/device/public/interfaces/constants.mojom.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/hid/hid_report_descriptor_fuzzer.cc b/chromium/services/device/hid/hid_report_descriptor_fuzzer.cc
index 5faad4bf234..2a8e0088779 100644
--- a/chromium/services/device/hid/hid_report_descriptor_fuzzer.cc
+++ b/chromium/services/device/hid/hid_report_descriptor_fuzzer.cc
@@ -6,7 +6,7 @@
#include <stdint.h>
#include "services/device/public/cpp/hid/hid_report_descriptor.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
device::HidReportDescriptor desc(std::vector<uint8_t>(data, data + size));
diff --git a/chromium/services/device/hid/hid_service.h b/chromium/services/device/hid/hid_service.h
index 55d435bf46d..6215f6663a8 100644
--- a/chromium/services/device/hid/hid_service.h
+++ b/chromium/services/device/hid/hid_service.h
@@ -20,7 +20,7 @@
#include "base/task_scheduler/task_traits.h"
#include "base/threading/thread_checker.h"
#include "services/device/hid/hid_device_info.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/hid/hid_service_unittest.cc b/chromium/services/device/hid/hid_service_unittest.cc
index ea222291a5e..37bf89a50b2 100644
--- a/chromium/services/device/hid/hid_service_unittest.cc
+++ b/chromium/services/device/hid/hid_service_unittest.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
diff --git a/chromium/services/device/hid/hid_service_win.cc b/chromium/services/device/hid/hid_service_win.cc
index 90ca8f80e83..7d7b3fe40bf 100644
--- a/chromium/services/device/hid/hid_service_win.cc
+++ b/chromium/services/device/hid/hid_service_win.cc
@@ -277,7 +277,7 @@ void HidServiceWin::OnDeviceRemoved(const GUID& class_guid,
// Execute a no-op closure on the file task runner to synchronize with any
// devices that are still being enumerated.
blocking_task_runner_->PostTaskAndReply(
- FROM_HERE, base::BindOnce(&base::DoNothing),
+ FROM_HERE, base::DoNothing(),
base::BindOnce(&HidServiceWin::RemoveDevice, weak_factory_.GetWeakPtr(),
device_path));
}
diff --git a/chromium/services/device/hid/input_service_linux.h b/chromium/services/device/hid/input_service_linux.h
index 5aa6b9fef44..9f20de46858 100644
--- a/chromium/services/device/hid/input_service_linux.h
+++ b/chromium/services/device/hid/input_service_linux.h
@@ -15,7 +15,7 @@
#include "base/threading/thread_checker.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/device/public/interfaces/input_service.mojom.h"
+#include "services/device/public/mojom/input_service.mojom.h"
namespace device {
diff --git a/chromium/services/device/hid/input_service_linux_unittest.cc b/chromium/services/device/hid/input_service_linux_unittest.cc
index 24641cd5169..a084f4b057d 100644
--- a/chromium/services/device/hid/input_service_linux_unittest.cc
+++ b/chromium/services/device/hid/input_service_linux_unittest.cc
@@ -10,7 +10,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "services/device/hid/input_service_linux.h"
-#include "services/device/public/interfaces/input_service.mojom.h"
+#include "services/device/public/mojom/input_service.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
diff --git a/chromium/services/device/manifest.json b/chromium/services/device/manifest.json
index 6b343e81dcc..e586d3b1c07 100644
--- a/chromium/services/device/manifest.json
+++ b/chromium/services/device/manifest.json
@@ -12,7 +12,7 @@
"device:geolocation_control": [ "device::mojom::GeolocationControl" ],
"device:hid": [ "device::mojom::HidManager" ],
"device:input_service": [ "device::mojom::InputDeviceManager" ],
- "device:ip_geolocator": [ "device::mojom::PublicIpAddressGeolocationProvider" ],
+ "device:ip_geolocator": [ "device::mojom::PublicIpAddressGeolocationProvider" ],
"device:nfc": [ "device::mojom::NFCProvider" ],
"device:power_monitor": [ "device::mojom::PowerMonitor" ],
"device:screen_orientation": [ "device::mojom::ScreenOrientationListener" ],
diff --git a/chromium/services/device/nfc/android/BUILD.gn b/chromium/services/device/nfc/android/BUILD.gn
index 4cc149b5616..87fafca398f 100644
--- a/chromium/services/device/nfc/android/BUILD.gn
+++ b/chromium/services/device/nfc/android/BUILD.gn
@@ -23,9 +23,9 @@ android_library("java") {
"//base:base_java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
- "//services/device/public/interfaces:interfaces_java",
"//services/device/public/java:nfc_java",
- "//services/service_manager/public/interfaces:interfaces_java",
+ "//services/device/public/mojom:mojom_java",
"//services/service_manager/public/java:service_manager_java",
+ "//services/service_manager/public/mojom:mojom_java",
]
}
diff --git a/chromium/services/device/power_monitor/BUILD.gn b/chromium/services/device/power_monitor/BUILD.gn
index 5515623d2e0..b21f6455461 100644
--- a/chromium/services/device/power_monitor/BUILD.gn
+++ b/chromium/services/device/power_monitor/BUILD.gn
@@ -18,6 +18,6 @@ source_set("power_monitor") {
]
public_deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
}
diff --git a/chromium/services/device/power_monitor/power_monitor_message_broadcaster.h b/chromium/services/device/power_monitor/power_monitor_message_broadcaster.h
index 0b42dfe1b3c..617e005b515 100644
--- a/chromium/services/device/power_monitor/power_monitor_message_broadcaster.h
+++ b/chromium/services/device/power_monitor/power_monitor_message_broadcaster.h
@@ -9,7 +9,7 @@
#include "base/power_monitor/power_observer.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/device/public/interfaces/power_monitor.mojom.h"
+#include "services/device/public/mojom/power_monitor.mojom.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/generic_sensor/BUILD.gn b/chromium/services/device/public/cpp/generic_sensor/BUILD.gn
index 037a630f50f..3c503b143c8 100644
--- a/chromium/services/device/public/cpp/generic_sensor/BUILD.gn
+++ b/chromium/services/device/public/cpp/generic_sensor/BUILD.gn
@@ -15,7 +15,7 @@ source_set("generic_sensor") {
]
public_deps = [
- "//services/device/public/interfaces:generic_sensor",
+ "//services/device/public/mojom:generic_sensor",
]
deps = [
diff --git a/chromium/services/device/public/cpp/generic_sensor/OWNERS b/chromium/services/device/public/cpp/generic_sensor/OWNERS
index bb6511619b7..d5fefd82012 100644
--- a/chromium/services/device/public/cpp/generic_sensor/OWNERS
+++ b/chromium/services/device/public/cpp/generic_sensor/OWNERS
@@ -1,2 +1,2 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/device/public/cpp/generic_sensor/sensor_struct_traits.cc b/chromium/services/device/public/cpp/generic_sensor/sensor_mojom_traits.cc
index 39a233e06e8..bfed47fb0a1 100644
--- a/chromium/services/device/public/cpp/generic_sensor/sensor_struct_traits.cc
+++ b/chromium/services/device/public/cpp/generic_sensor/sensor_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/device/public/cpp/generic_sensor/sensor_struct_traits.h"
+#include "services/device/public/cpp/generic_sensor/sensor_mojom_traits.h"
namespace mojo {
diff --git a/chromium/services/device/public/cpp/generic_sensor/sensor_struct_traits.h b/chromium/services/device/public/cpp/generic_sensor/sensor_mojom_traits.h
index e15f8ee03be..2c2caf3adb0 100644
--- a/chromium/services/device/public/cpp/generic_sensor/sensor_struct_traits.h
+++ b/chromium/services/device/public/cpp/generic_sensor/sensor_mojom_traits.h
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_STRUCT_TRAITS_H_
-#define SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_STRUCT_TRAITS_H_
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_MOJOM_TRAITS_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_MOJOM_TRAITS_H_
#include "services/device/public/cpp/generic_sensor/platform_sensor_configuration.h"
-#include "services/device/public/interfaces/sensor.mojom.h"
+#include "services/device/public/mojom/sensor.mojom.h"
namespace mojo {
@@ -23,4 +23,4 @@ struct StructTraits<device::mojom::SensorConfigurationDataView,
} // namespace mojo
-#endif // SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_STRUCT_TRAITS_H_
+#endif // SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_MOJOM_TRAITS_H_
diff --git a/chromium/services/device/public/cpp/generic_sensor/sensor_reading.h b/chromium/services/device/public/cpp/generic_sensor/sensor_reading.h
index 261e6d46472..eb6cfe7eaa9 100644
--- a/chromium/services/device/public/cpp/generic_sensor/sensor_reading.h
+++ b/chromium/services/device/public/cpp/generic_sensor/sensor_reading.h
@@ -6,7 +6,7 @@
#define SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_READING_H_
#include "device/base/synchronization/one_writer_seqlock.h"
-#include "services/device/public/interfaces/sensor.mojom.h"
+#include "services/device/public/mojom/sensor.mojom.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/generic_sensor/sensor_traits.h b/chromium/services/device/public/cpp/generic_sensor/sensor_traits.h
index 8e63b228780..8a76ee902fa 100644
--- a/chromium/services/device/public/cpp/generic_sensor/sensor_traits.h
+++ b/chromium/services/device/public/cpp/generic_sensor/sensor_traits.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_TRAITS_H_
#define SERVICES_DEVICE_PUBLIC_CPP_GENERIC_SENSOR_SENSOR_TRAITS_H_
-#include "services/device/public/interfaces/sensor.mojom.h"
+#include "services/device/public/mojom/sensor.mojom.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/hid/BUILD.gn b/chromium/services/device/public/cpp/hid/BUILD.gn
index 515416bf08f..6ec1c2cc0e1 100644
--- a/chromium/services/device/public/cpp/hid/BUILD.gn
+++ b/chromium/services/device/public/cpp/hid/BUILD.gn
@@ -23,7 +23,7 @@ source_set("hid") {
]
deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
"//services/service_manager/public/cpp",
]
}
diff --git a/chromium/services/device/public/cpp/hid/fake_input_service_linux.h b/chromium/services/device/public/cpp/hid/fake_input_service_linux.h
index 9c31d8e5226..f1904883ede 100644
--- a/chromium/services/device/public/cpp/hid/fake_input_service_linux.h
+++ b/chromium/services/device/public/cpp/hid/fake_input_service_linux.h
@@ -10,7 +10,7 @@
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/device/public/interfaces/input_service.mojom.h"
+#include "services/device/public/mojom/input_service.mojom.h"
#include "services/service_manager/public/cpp/service_context.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/hid/hid_device_filter.h b/chromium/services/device/public/cpp/hid/hid_device_filter.h
index e8527ebe1b3..431d8a47c2a 100644
--- a/chromium/services/device/public/cpp/hid/hid_device_filter.h
+++ b/chromium/services/device/public/cpp/hid/hid_device_filter.h
@@ -9,7 +9,7 @@
#include <vector>
#include "base/memory/ref_counted.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/hid/hid_device_filter_unittest.cc b/chromium/services/device/public/cpp/hid/hid_device_filter_unittest.cc
index ad6c4e31db1..70688acd2da 100644
--- a/chromium/services/device/public/cpp/hid/hid_device_filter_unittest.cc
+++ b/chromium/services/device/public/cpp/hid/hid_device_filter_unittest.cc
@@ -8,7 +8,7 @@
#include "services/device/hid/hid_device_info.h"
#include "services/device/hid/test_report_descriptors.h"
#include "services/device/public/cpp/hid/hid_device_filter.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/hid/hid_report_descriptor.h b/chromium/services/device/public/cpp/hid/hid_report_descriptor.h
index cbb8660c9c1..337ea6ac16c 100644
--- a/chromium/services/device/public/cpp/hid/hid_report_descriptor.h
+++ b/chromium/services/device/public/cpp/hid/hid_report_descriptor.h
@@ -12,7 +12,7 @@
#include <vector>
#include "services/device/public/cpp/hid/hid_report_descriptor_item.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc b/chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
index 86525635262..c365eb66318 100644
--- a/chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
+++ b/chromium/services/device/public/cpp/hid/hid_report_descriptor_unittest.cc
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "services/device/hid/test_report_descriptors.h"
#include "services/device/public/cpp/hid/hid_report_descriptor.h"
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/device/public/cpp/hid/hid_usage_and_page.h b/chromium/services/device/public/cpp/hid/hid_usage_and_page.h
index dd5e3221f7e..4c82d8856bc 100644
--- a/chromium/services/device/public/cpp/hid/hid_usage_and_page.h
+++ b/chromium/services/device/public/cpp/hid/hid_usage_and_page.h
@@ -5,7 +5,7 @@
#ifndef DEVICE_HID_PUBLIC_CPP_HID_USAGE_AND_PAGE_H_
#define DEVICE_HID_PUBLIC_CPP_HID_USAGE_AND_PAGE_H_
-#include "services/device/public/interfaces/hid.mojom.h"
+#include "services/device/public/mojom/hid.mojom.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/power_monitor/BUILD.gn b/chromium/services/device/public/cpp/power_monitor/BUILD.gn
index 4613af60395..27ca57cbd0d 100644
--- a/chromium/services/device/public/cpp/power_monitor/BUILD.gn
+++ b/chromium/services/device/public/cpp/power_monitor/BUILD.gn
@@ -17,6 +17,6 @@ source_set("power_monitor") {
]
public_deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
}
diff --git a/chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc b/chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc
index 1ae5332349a..6216ec6fc5c 100644
--- a/chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc
+++ b/chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "base/sequenced_task_runner.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace device {
diff --git a/chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h b/chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h
index c76d3bd651a..73feb649477 100644
--- a/chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h
+++ b/chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h
@@ -12,7 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/power_monitor/power_monitor_source.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/device/public/interfaces/power_monitor.mojom.h"
+#include "services/device/public/mojom/power_monitor.mojom.h"
namespace base {
class SequencedTaskRunner;
diff --git a/chromium/services/device/public/cpp/test/BUILD.gn b/chromium/services/device/public/cpp/test/BUILD.gn
index eb89d5037ab..3a8db4a14ff 100644
--- a/chromium/services/device/public/cpp/test/BUILD.gn
+++ b/chromium/services/device/public/cpp/test/BUILD.gn
@@ -10,7 +10,7 @@ source_set("test_support") {
public_deps = [
"//base",
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
"//services/service_manager/public/cpp",
]
diff --git a/chromium/services/device/public/interfaces/sensor.typemap b/chromium/services/device/public/interfaces/sensor.typemap
deleted file mode 100644
index d230c996486..00000000000
--- a/chromium/services/device/public/interfaces/sensor.typemap
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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.
-
-mojom = "//services/device/public/interfaces/sensor.mojom"
-public_headers = [ "//services/device/public/cpp/generic_sensor/platform_sensor_configuration.h" ]
-traits_headers =
- [ "//services/device/public/cpp/generic_sensor/sensor_struct_traits.h" ]
-sources = [
- "//services/device/public/cpp/generic_sensor/sensor_struct_traits.cc",
-]
-type_mappings =
- [ "device.mojom.SensorConfiguration=device::PlatformSensorConfiguration" ]
diff --git a/chromium/services/device/public/interfaces/BUILD.gn b/chromium/services/device/public/mojom/BUILD.gn
index 55c288a66db..0691ad55a3a 100644
--- a/chromium/services/device/public/interfaces/BUILD.gn
+++ b/chromium/services/device/public/mojom/BUILD.gn
@@ -4,20 +4,24 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"battery_monitor.mojom",
"battery_status.mojom",
"fingerprint.mojom",
+ "geolocation.mojom",
"geolocation_config.mojom",
"geolocation_context.mojom",
"geolocation_control.mojom",
+ "geoposition.mojom",
"hid.mojom",
"input_service.mojom",
"nfc.mojom",
"nfc_provider.mojom",
"power_monitor.mojom",
"public_ip_address_geolocation_provider.mojom",
+ "screen_orientation.mojom",
+ "screen_orientation_lock_types.mojom",
"serial.mojom",
"time_zone_monitor.mojom",
"vibration_manager.mojom",
@@ -28,11 +32,10 @@ mojom("interfaces") {
public_deps = [
":constants",
- "//device/geolocation/public/interfaces",
- "//services/network/public/interfaces",
+ "//services/network/public/mojom",
]
- # The blink variant of the Device Service interfaces are depended on by the
+ # The blink variant of the Device Service mojom are depended on by the
# blink platform target. All blink variant mojoms use WTF types, which are
# part of the blink platform component. In order to avoid a dependency cycle,
# these targets must be part of that component.
@@ -41,6 +44,7 @@ mojom("interfaces") {
export_header_blink = "third_party/WebKit/public/platform/WebCommon.h"
visibility_blink = [
+ "//third_party/WebKit/Source/bindings/modules/v8:generate_mojo_bindings",
"//third_party/WebKit/Source/platform:blink_platform_public_deps",
"//third_party/WebKit/public:mojo_bindings_blink",
]
diff --git a/chromium/services/audio/public/interfaces/OWNERS b/chromium/services/device/public/mojom/OWNERS
index 2c44a463856..ae29a36aac8 100644
--- a/chromium/services/audio/public/interfaces/OWNERS
+++ b/chromium/services/device/public/mojom/OWNERS
@@ -1,6 +1,6 @@
per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/device/public/interfaces/README(WakeLock).md b/chromium/services/device/public/mojom/README(WakeLock).md
index 0d7c3955193..0d7c3955193 100644
--- a/chromium/services/device/public/interfaces/README(WakeLock).md
+++ b/chromium/services/device/public/mojom/README(WakeLock).md
diff --git a/chromium/services/device/public/interfaces/battery_monitor.mojom b/chromium/services/device/public/mojom/battery_monitor.mojom
index d3ebf42e804..2bfb2af6c29 100644
--- a/chromium/services/device/public/interfaces/battery_monitor.mojom
+++ b/chromium/services/device/public/mojom/battery_monitor.mojom
@@ -4,7 +4,7 @@
module device.mojom;
-import "services/device/public/interfaces/battery_status.mojom";
+import "services/device/public/mojom/battery_status.mojom";
interface BatteryMonitor {
// Battery status is reported once it changes or immediately if this is the
diff --git a/chromium/services/device/public/interfaces/battery_status.mojom b/chromium/services/device/public/mojom/battery_status.mojom
index 83c0026cc44..83c0026cc44 100644
--- a/chromium/services/device/public/interfaces/battery_status.mojom
+++ b/chromium/services/device/public/mojom/battery_status.mojom
diff --git a/chromium/services/device/public/interfaces/constants.mojom b/chromium/services/device/public/mojom/constants.mojom
index de400fc8b87..de400fc8b87 100644
--- a/chromium/services/device/public/interfaces/constants.mojom
+++ b/chromium/services/device/public/mojom/constants.mojom
diff --git a/chromium/services/device/public/interfaces/fingerprint.mojom b/chromium/services/device/public/mojom/fingerprint.mojom
index 92515ce23e5..92515ce23e5 100644
--- a/chromium/services/device/public/interfaces/fingerprint.mojom
+++ b/chromium/services/device/public/mojom/fingerprint.mojom
diff --git a/chromium/services/device/public/mojom/geolocation.mojom b/chromium/services/device/public/mojom/geolocation.mojom
new file mode 100644
index 00000000000..f079d3431b5
--- /dev/null
+++ b/chromium/services/device/public/mojom/geolocation.mojom
@@ -0,0 +1,30 @@
+// 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.
+
+module device.mojom;
+
+import "services/device/public/mojom/geoposition.mojom";
+
+// Geolocation provides updates on the device's location. By default, it
+// provides updates with low accuracy, but |SetHighAccuracy()| may be called
+// to change this.
+interface Geolocation {
+ // Select between high and low accuracy, if supported by the implementation.
+ // Ignored if unsupported.
+ SetHighAccuracy(bool high_accuracy);
+
+ // Use this method to get notified of future position updates, by calling
+ // QueryNextPosition once, and then calling it again when/if it returns.
+ //
+ // When first called:
+ // Returns the latest known Geoposition.
+ // When subsequently called:
+ // Issues a request for a single position update, which the implementation
+ // may fulfill at its discretion (e.g. when the next geoposition change is
+ // detected).
+ //
+ // Overlapping calls to this method are prohibited and will be treated as a
+ // connection error. Position updates may be throttled by the service.
+ QueryNextPosition() => (Geoposition geoposition);
+};
diff --git a/chromium/services/device/public/interfaces/geolocation_config.mojom b/chromium/services/device/public/mojom/geolocation_config.mojom
index 340a567b275..340a567b275 100644
--- a/chromium/services/device/public/interfaces/geolocation_config.mojom
+++ b/chromium/services/device/public/mojom/geolocation_config.mojom
diff --git a/chromium/services/device/public/interfaces/geolocation_context.mojom b/chromium/services/device/public/mojom/geolocation_context.mojom
index e223cfe65c4..00ca070a062 100644
--- a/chromium/services/device/public/interfaces/geolocation_context.mojom
+++ b/chromium/services/device/public/mojom/geolocation_context.mojom
@@ -4,8 +4,8 @@
module device.mojom;
-import "device/geolocation/public/interfaces/geolocation.mojom";
-import "device/geolocation/public/interfaces/geoposition.mojom";
+import "services/device/public/mojom/geolocation.mojom";
+import "services/device/public/mojom/geoposition.mojom";
// GeolocationContext provides methods to bind Geolocation instance and to
// set/clear overrides of geoposition that will apply to all Geolocation
diff --git a/chromium/services/device/public/interfaces/geolocation_control.mojom b/chromium/services/device/public/mojom/geolocation_control.mojom
index 0b209fb74b3..0b209fb74b3 100644
--- a/chromium/services/device/public/interfaces/geolocation_control.mojom
+++ b/chromium/services/device/public/mojom/geolocation_control.mojom
diff --git a/chromium/services/device/public/mojom/geoposition.mojom b/chromium/services/device/public/mojom/geoposition.mojom
new file mode 100644
index 00000000000..a64e9b77c6d
--- /dev/null
+++ b/chromium/services/device/public/mojom/geoposition.mojom
@@ -0,0 +1,60 @@
+// 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.
+
+module device.mojom;
+
+import "mojo/common/time.mojom";
+
+// Sentinel values to mark invalid data. (WebKit carries companion is_valid
+// bools for this purpose; we may eventually follow that approach, but
+// sentinels worked OK in the Gears code this is based on.)
+const double kBadLatitudeLongitude = 200;
+// Lowest point on land is at approximately -400 meters.
+const double kBadAltitude = -10000;
+const double kBadAccuracy = -1; // Accuracy must be non-negative.
+const double kBadHeading = -1; // Heading must be non-negative.
+const double kBadSpeed = -1;
+
+// A Geoposition represents a position fix. It was originally derived from:
+// http://gears.googlecode.com/svn/trunk/gears/geolocation/geolocation.h
+struct Geoposition {
+ // These values follow the W3C geolocation specification and can be returned
+ // to JavaScript without the need for a conversion.
+ enum ErrorCode {
+ NONE = 0, // Chrome addition.
+ PERMISSION_DENIED = 1,
+ POSITION_UNAVAILABLE = 2,
+ TIMEOUT = 3,
+ LAST = TIMEOUT
+ };
+
+ // Whether this geoposition is valid.
+ bool valid;
+
+ // These properties correspond to those of the JavaScript Position object
+ // although their types may differ.
+ // Latitude in decimal degrees north (WGS84 coordinate frame).
+ double latitude = kBadLatitudeLongitude;
+ // Longitude in decimal degrees west (WGS84 coordinate frame).
+ double longitude = kBadLatitudeLongitude;
+ // Altitude in meters (above WGS84 datum).
+ double altitude = kBadAltitude;
+ // Accuracy of horizontal position in meters.
+ double accuracy = kBadAccuracy;
+ // Accuracy of altitude in meters.
+ double altitude_accuracy = kBadAccuracy;
+ // Heading in decimal degrees clockwise from true north.
+ double heading = kBadHeading;
+ // Horizontal component of device velocity in meters per second.
+ double speed = kBadSpeed;
+ // Time of position measurement in seconds since the Windows FILETIME epoch
+ // (1601-01-01 00:00:00 UTC). This is taken from the host computer's system
+ // clock (i.e. from Time::Now(), not the source device's clock).
+ mojo.common.mojom.Time timestamp;
+
+ // Error code, see enum above.
+ ErrorCode error_code = NONE;
+ // Human-readable error message.
+ string error_message;
+};
diff --git a/chromium/services/device/public/interfaces/hid.mojom b/chromium/services/device/public/mojom/hid.mojom
index 1de8f6f2b91..1de8f6f2b91 100644
--- a/chromium/services/device/public/interfaces/hid.mojom
+++ b/chromium/services/device/public/mojom/hid.mojom
diff --git a/chromium/services/device/public/interfaces/input_service.mojom b/chromium/services/device/public/mojom/input_service.mojom
index 727a3f13184..727a3f13184 100644
--- a/chromium/services/device/public/interfaces/input_service.mojom
+++ b/chromium/services/device/public/mojom/input_service.mojom
diff --git a/chromium/services/device/public/interfaces/nfc.mojom b/chromium/services/device/public/mojom/nfc.mojom
index 02df7b545d2..02df7b545d2 100644
--- a/chromium/services/device/public/interfaces/nfc.mojom
+++ b/chromium/services/device/public/mojom/nfc.mojom
diff --git a/chromium/services/device/public/interfaces/nfc_provider.mojom b/chromium/services/device/public/mojom/nfc_provider.mojom
index e5ec384ff84..8486f734ffe 100644
--- a/chromium/services/device/public/interfaces/nfc_provider.mojom
+++ b/chromium/services/device/public/mojom/nfc_provider.mojom
@@ -4,7 +4,7 @@
module device.mojom;
-import "services/device/public/interfaces/nfc.mojom";
+import "services/device/public/mojom/nfc.mojom";
interface NFCProvider {
// Gets an NFC that is associated with |host_id|. |host_id|
diff --git a/chromium/services/device/public/interfaces/power_monitor.mojom b/chromium/services/device/public/mojom/power_monitor.mojom
index a6d8701fb07..a6d8701fb07 100644
--- a/chromium/services/device/public/interfaces/power_monitor.mojom
+++ b/chromium/services/device/public/mojom/power_monitor.mojom
diff --git a/chromium/services/device/public/interfaces/public_ip_address_geolocation_provider.mojom b/chromium/services/device/public/mojom/public_ip_address_geolocation_provider.mojom
index 214912e2fe4..145e2e4fc6f 100644
--- a/chromium/services/device/public/interfaces/public_ip_address_geolocation_provider.mojom
+++ b/chromium/services/device/public/mojom/public_ip_address_geolocation_provider.mojom
@@ -4,8 +4,8 @@
module device.mojom;
-import "device/geolocation/public/interfaces/geolocation.mojom";
-import "services/network/public/interfaces/mutable_partial_network_traffic_annotation_tag.mojom";
+import "services/network/public/mojom/mutable_partial_network_traffic_annotation_tag.mojom";
+import "services/device/public/mojom/geolocation.mojom";
// Provides a coarse-grained device.mojom.Geolocation which, subject to
// case-by-case privacy review, may be able to operate without explicit user
diff --git a/chromium/services/device/public/mojom/screen_orientation.mojom b/chromium/services/device/public/mojom/screen_orientation.mojom
new file mode 100644
index 00000000000..505461695b9
--- /dev/null
+++ b/chromium/services/device/public/mojom/screen_orientation.mojom
@@ -0,0 +1,35 @@
+// 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.
+
+module device.mojom;
+
+import "services/device/public/mojom/screen_orientation_lock_types.mojom";
+
+interface ScreenOrientation {
+ LockOrientation(ScreenOrientationLockType orientation) =>
+ (ScreenOrientationLockResult result);
+ UnlockOrientation();
+};
+
+// ScreenOrientationListener is expected to be used when the platform requires
+// heavy work in order to accurately know the screen orientation.
+// For example, on Android, this is required for Jelly Bean, where there is no
+// API to be notified of a screen orientation change of 180 degrees.
+interface ScreenOrientationListener {
+ // The renderer process is now using the Screen Orientation API and informs
+ // the browser process that it should start accurately listening to the screen
+ // orientation if it wasn't already.
+ Start();
+
+ // The renderer process is no longer using the Screen Orientation API and
+ // informs the browser process that it can stop accurately listening to the
+ // screen orientation if no other process cares about it.
+ Stop();
+
+ // Queries whether accelerometer auto rotation of screen orientation is
+ // enabled, or the user has locked the screen orientation at the OS level.
+ // This can be called at any time, whether or not the listener is started.
+ // It's currently only implemented on Android.
+ IsAutoRotateEnabledByUser() => (bool enabled);
+};
diff --git a/chromium/services/device/public/mojom/screen_orientation_lock_types.mojom b/chromium/services/device/public/mojom/screen_orientation_lock_types.mojom
new file mode 100644
index 00000000000..d3c3463a5b0
--- /dev/null
+++ b/chromium/services/device/public/mojom/screen_orientation_lock_types.mojom
@@ -0,0 +1,31 @@
+// 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.
+
+module device.mojom;
+
+enum ScreenOrientationLockResult {
+ // The lock was successfully applied.
+ SCREEN_ORIENTATION_LOCK_RESULT_SUCCESS,
+
+ // Failed because locking isn't available on the platform.
+ SCREEN_ORIENTATION_LOCK_RESULT_ERROR_NOT_AVAILABLE,
+
+ // Failed because fullscreen is required to lock.
+ SCREEN_ORIENTATION_LOCK_RESULT_ERROR_FULLSCREEN_REQUIRED,
+
+ // Failed because another lock/unlock got called before that one ended.
+ SCREEN_ORIENTATION_LOCK_RESULT_ERROR_CANCELED,
+};
+
+enum ScreenOrientationLockType {
+ DEFAULT = 0, // Equivalent to unlock.
+ PORTRAIT_PRIMARY,
+ PORTRAIT_SECONDARY,
+ LANDSCAPE_PRIMARY,
+ LANDSCAPE_SECONDARY,
+ ANY,
+ LANDSCAPE,
+ PORTRAIT,
+ NATURAL,
+};
diff --git a/chromium/services/device/public/interfaces/sensor.mojom b/chromium/services/device/public/mojom/sensor.mojom
index 19e9fe8eed7..19e9fe8eed7 100644
--- a/chromium/services/device/public/interfaces/sensor.mojom
+++ b/chromium/services/device/public/mojom/sensor.mojom
diff --git a/chromium/services/device/public/mojom/sensor.typemap b/chromium/services/device/public/mojom/sensor.typemap
new file mode 100644
index 00000000000..2d65c5e44f1
--- /dev/null
+++ b/chromium/services/device/public/mojom/sensor.typemap
@@ -0,0 +1,15 @@
+# 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.
+
+mojom = "//services/device/public/mojom/sensor.mojom"
+public_headers = [
+ "//services/device/public/cpp/generic_sensor/platform_sensor_configuration.h",
+]
+traits_headers =
+ [ "//services/device/public/cpp/generic_sensor/sensor_mojom_traits.h" ]
+sources = [
+ "//services/device/public/cpp/generic_sensor/sensor_mojom_traits.cc",
+]
+type_mappings =
+ [ "device.mojom.SensorConfiguration=device::PlatformSensorConfiguration" ]
diff --git a/chromium/services/device/public/interfaces/sensor_provider.mojom b/chromium/services/device/public/mojom/sensor_provider.mojom
index 261d17a8b1b..da07a8464ab 100644
--- a/chromium/services/device/public/interfaces/sensor_provider.mojom
+++ b/chromium/services/device/public/mojom/sensor_provider.mojom
@@ -39,12 +39,21 @@ struct SensorInitParams {
const uint64 kReadBufferSizeForTests = 48;
};
+enum SensorCreationResult {
+ SUCCESS,
+ ERROR_NOT_AVAILABLE, // Sensor is not available on the platform.
+ ERROR_NOT_ALLOWED, // The required permissions are not granted.
+};
+
interface SensorProvider {
// Gets the sensor interface by the given type.
//
// |type| type of the sensor.
//
- // |init_params| on success will contain the SensorInitParams describing the
- // sensor, contains null on failure.
- GetSensor(SensorType type) => (SensorInitParams? init_params);
+ // |result| on success contains SUCCESS, otherwise contains the
+ // SensorCreationResult describing the failure reason.
+ // |init_params| on success will contain the SensorInitParams describing
+ // the sensor, contains null on failure.
+ GetSensor(SensorType type) => (SensorCreationResult result,
+ SensorInitParams? init_params);
};
diff --git a/chromium/services/device/public/interfaces/serial.mojom b/chromium/services/device/public/mojom/serial.mojom
index 31a1709440a..31a1709440a 100644
--- a/chromium/services/device/public/interfaces/serial.mojom
+++ b/chromium/services/device/public/mojom/serial.mojom
diff --git a/chromium/services/device/public/interfaces/time_zone_monitor.mojom b/chromium/services/device/public/mojom/time_zone_monitor.mojom
index 207b0a086a5..207b0a086a5 100644
--- a/chromium/services/device/public/interfaces/time_zone_monitor.mojom
+++ b/chromium/services/device/public/mojom/time_zone_monitor.mojom
diff --git a/chromium/services/device/public/interfaces/typemaps.gni b/chromium/services/device/public/mojom/typemaps.gni
index 3a292ce21dc..d5073902415 100644
--- a/chromium/services/device/public/interfaces/typemaps.gni
+++ b/chromium/services/device/public/mojom/typemaps.gni
@@ -2,4 +2,4 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-typemaps = [ "//services/device/public/interfaces/sensor.typemap" ]
+typemaps = [ "//services/device/public/mojom/sensor.typemap" ]
diff --git a/chromium/services/device/public/interfaces/vibration_manager.mojom b/chromium/services/device/public/mojom/vibration_manager.mojom
index a933301134c..a933301134c 100644
--- a/chromium/services/device/public/interfaces/vibration_manager.mojom
+++ b/chromium/services/device/public/mojom/vibration_manager.mojom
diff --git a/chromium/services/device/public/interfaces/wake_lock.mojom b/chromium/services/device/public/mojom/wake_lock.mojom
index 41a5add43d1..41a5add43d1 100644
--- a/chromium/services/device/public/interfaces/wake_lock.mojom
+++ b/chromium/services/device/public/mojom/wake_lock.mojom
diff --git a/chromium/services/device/public/interfaces/wake_lock_context.mojom b/chromium/services/device/public/mojom/wake_lock_context.mojom
index f5167b34020..358b89a976f 100644
--- a/chromium/services/device/public/interfaces/wake_lock_context.mojom
+++ b/chromium/services/device/public/mojom/wake_lock_context.mojom
@@ -4,7 +4,7 @@
module device.mojom;
-import "services/device/public/interfaces/wake_lock.mojom";
+import "services/device/public/mojom/wake_lock.mojom";
// Context in which WakeLock instances operate.
interface WakeLockContext {
diff --git a/chromium/services/device/public/interfaces/wake_lock_provider.mojom b/chromium/services/device/public/mojom/wake_lock_provider.mojom
index 5a3e4859704..722aa4efdd5 100644
--- a/chromium/services/device/public/interfaces/wake_lock_provider.mojom
+++ b/chromium/services/device/public/mojom/wake_lock_provider.mojom
@@ -4,8 +4,8 @@
module device.mojom;
-import "services/device/public/interfaces/wake_lock_context.mojom";
-import "services/device/public/interfaces/wake_lock.mojom";
+import "services/device/public/mojom/wake_lock_context.mojom";
+import "services/device/public/mojom/wake_lock.mojom";
interface WakeLockProvider {
diff --git a/chromium/services/device/screen_orientation/BUILD.gn b/chromium/services/device/screen_orientation/BUILD.gn
index 6aa31af0198..410ee3989bf 100644
--- a/chromium/services/device/screen_orientation/BUILD.gn
+++ b/chromium/services/device/screen_orientation/BUILD.gn
@@ -22,7 +22,7 @@ source_set("screen_orientation") {
]
public_deps = [
- "//device/screen_orientation/public/interfaces",
+ "//services/device/public/mojom",
]
if (is_android) {
diff --git a/chromium/services/device/screen_orientation/OWNERS b/chromium/services/device/screen_orientation/OWNERS
index 33ac3a28754..60c92e4b8bc 100644
--- a/chromium/services/device/screen_orientation/OWNERS
+++ b/chromium/services/device/screen_orientation/OWNERS
@@ -1,2 +1,4 @@
-file://device/screen_orientation/OWNERS
+blundell@chromium.org
+mlamouri@chromium.org
+# COMPONENT: Blink>ScreenOrientation
diff --git a/chromium/services/device/screen_orientation/screen_orientation_listener_android.h b/chromium/services/device/screen_orientation/screen_orientation_listener_android.h
index 307b9f6443f..e86012df1fe 100644
--- a/chromium/services/device/screen_orientation/screen_orientation_listener_android.h
+++ b/chromium/services/device/screen_orientation/screen_orientation_listener_android.h
@@ -6,7 +6,7 @@
#define SERVICES_DEVICE_SCREEN_ORIENTATION_SCREEN_ORIENTATION_LISTENER_ANDROID_H_
#include "base/macros.h"
-#include "device/screen_orientation/public/interfaces/screen_orientation.mojom.h"
+#include "services/device/public/mojom/screen_orientation.mojom.h"
namespace device {
diff --git a/chromium/services/device/serial/BUILD.gn b/chromium/services/device/serial/BUILD.gn
index d70d6e5a1d0..84985df9e6e 100644
--- a/chromium/services/device/serial/BUILD.gn
+++ b/chromium/services/device/serial/BUILD.gn
@@ -19,7 +19,7 @@ if (is_win || (is_linux && use_udev) || is_mac) {
]
public_deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
deps = [
diff --git a/chromium/services/device/serial/serial_device_enumerator_impl.h b/chromium/services/device/serial/serial_device_enumerator_impl.h
index 9863b15192e..bb9f694f3b9 100644
--- a/chromium/services/device/serial/serial_device_enumerator_impl.h
+++ b/chromium/services/device/serial/serial_device_enumerator_impl.h
@@ -9,7 +9,7 @@
#include "base/macros.h"
#include "device/serial/serial_device_enumerator.h"
-#include "services/device/public/interfaces/serial.mojom.h"
+#include "services/device/public/mojom/serial.mojom.h"
namespace device {
diff --git a/chromium/services/device/serial/serial_device_enumerator_impl_unittest.cc b/chromium/services/device/serial/serial_device_enumerator_impl_unittest.cc
index c45f2a47bb6..b4bbacfe5fa 100644
--- a/chromium/services/device/serial/serial_device_enumerator_impl_unittest.cc
+++ b/chromium/services/device/serial/serial_device_enumerator_impl_unittest.cc
@@ -7,8 +7,8 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "services/device/device_service_test_base.h"
-#include "services/device/public/interfaces/constants.mojom.h"
-#include "services/device/public/interfaces/serial.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/device/public/mojom/serial.mojom.h"
namespace device {
diff --git a/chromium/services/device/serial/serial_io_handler_impl.h b/chromium/services/device/serial/serial_io_handler_impl.h
index 7029ad9bcbc..c8b7aca2921 100644
--- a/chromium/services/device/serial/serial_io_handler_impl.h
+++ b/chromium/services/device/serial/serial_io_handler_impl.h
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "device/serial/serial_io_handler.h"
-#include "services/device/public/interfaces/serial.mojom.h"
+#include "services/device/public/mojom/serial.mojom.h"
namespace base {
class SingleThreadTaskRunner;
diff --git a/chromium/services/device/serial/serial_io_handler_impl_unittest.cc b/chromium/services/device/serial/serial_io_handler_impl_unittest.cc
index 70c42392c01..d492526bd85 100644
--- a/chromium/services/device/serial/serial_io_handler_impl_unittest.cc
+++ b/chromium/services/device/serial/serial_io_handler_impl_unittest.cc
@@ -7,8 +7,8 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "services/device/device_service_test_base.h"
-#include "services/device/public/interfaces/constants.mojom.h"
-#include "services/device/public/interfaces/serial.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/device/public/mojom/serial.mojom.h"
namespace device {
diff --git a/chromium/services/device/time_zone_monitor/BUILD.gn b/chromium/services/device/time_zone_monitor/BUILD.gn
index f10d7db2289..565c9199683 100644
--- a/chromium/services/device/time_zone_monitor/BUILD.gn
+++ b/chromium/services/device/time_zone_monitor/BUILD.gn
@@ -29,7 +29,7 @@ source_set("time_zone_monitor") {
]
public_deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
if (is_android) {
diff --git a/chromium/services/device/time_zone_monitor/time_zone_monitor.h b/chromium/services/device/time_zone_monitor/time_zone_monitor.h
index 730aa5d0d6a..aecf705697d 100644
--- a/chromium/services/device/time_zone_monitor/time_zone_monitor.h
+++ b/chromium/services/device/time_zone_monitor/time_zone_monitor.h
@@ -11,7 +11,7 @@
#include "base/threading/thread_checker.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/device/public/interfaces/time_zone_monitor.mojom.h"
+#include "services/device/public/mojom/time_zone_monitor.mojom.h"
template <class T>
class scoped_refptr;
diff --git a/chromium/services/device/unittest_manifest.json b/chromium/services/device/unittest_manifest.json
index 94c35d954a6..6ead6a6a471 100644
--- a/chromium/services/device/unittest_manifest.json
+++ b/chromium/services/device/unittest_manifest.json
@@ -12,6 +12,9 @@
"device": [
"device:battery_monitor",
"device:generic_sensor",
+ "device:geolocation_config",
+ "device:geolocation_control",
+ "device:geolocation",
"device:hid",
"device:power_monitor",
"device:serial",
diff --git a/chromium/services/device/vibration/BUILD.gn b/chromium/services/device/vibration/BUILD.gn
index 737c90ea856..1e69eeda344 100644
--- a/chromium/services/device/vibration/BUILD.gn
+++ b/chromium/services/device/vibration/BUILD.gn
@@ -19,7 +19,7 @@ if (!is_android) {
]
public_deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
deps = [
diff --git a/chromium/services/device/vibration/android/BUILD.gn b/chromium/services/device/vibration/android/BUILD.gn
index caa084f6f7d..9a692c3d9f9 100644
--- a/chromium/services/device/vibration/android/BUILD.gn
+++ b/chromium/services/device/vibration/android/BUILD.gn
@@ -22,7 +22,7 @@ android_library("vibration_manager_java") {
"//base:base_java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
- "//services/device/public/interfaces:interfaces_java",
+ "//services/device/public/mojom:mojom_java",
"//services/service_manager/public/java:service_manager_java",
]
}
diff --git a/chromium/services/device/vibration/vibration_manager_impl.h b/chromium/services/device/vibration/vibration_manager_impl.h
index 175ffa90635..75627249863 100644
--- a/chromium/services/device/vibration/vibration_manager_impl.h
+++ b/chromium/services/device/vibration/vibration_manager_impl.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_DEVICE_VIBRATION_VIBRATION_MANAGER_IMPL_H_
#define SERVICES_DEVICE_VIBRATION_VIBRATION_MANAGER_IMPL_H_
-#include "services/device/public/interfaces/vibration_manager.mojom.h"
+#include "services/device/public/mojom/vibration_manager.mojom.h"
namespace device {
diff --git a/chromium/services/device/vibration/vibration_manager_impl_unittest.cc b/chromium/services/device/vibration/vibration_manager_impl_unittest.cc
index 78039dcc737..fe3a3c89930 100644
--- a/chromium/services/device/vibration/vibration_manager_impl_unittest.cc
+++ b/chromium/services/device/vibration/vibration_manager_impl_unittest.cc
@@ -4,8 +4,8 @@
#include "base/run_loop.h"
#include "services/device/device_service_test_base.h"
-#include "services/device/public/interfaces/constants.mojom.h"
-#include "services/device/public/interfaces/vibration_manager.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/device/public/mojom/vibration_manager.mojom.h"
#if defined(OS_ANDROID)
#include "base/android/jni_android.h"
diff --git a/chromium/services/device/wake_lock/BUILD.gn b/chromium/services/device/wake_lock/BUILD.gn
index 9a18c1e4f5e..a045e2a76cd 100644
--- a/chromium/services/device/wake_lock/BUILD.gn
+++ b/chromium/services/device/wake_lock/BUILD.gn
@@ -19,7 +19,7 @@ source_set("wake_lock") {
public_deps = [
"//base",
"//mojo/public/cpp/bindings",
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
"//ui/gfx",
]
diff --git a/chromium/services/device/wake_lock/power_save_blocker/BUILD.gn b/chromium/services/device/wake_lock/power_save_blocker/BUILD.gn
index 759510318cb..dfce90f6b79 100644
--- a/chromium/services/device/wake_lock/power_save_blocker/BUILD.gn
+++ b/chromium/services/device/wake_lock/power_save_blocker/BUILD.gn
@@ -31,7 +31,7 @@ source_set("power_save_blocker") {
]
public_deps = [
- "//services/device/public/interfaces",
+ "//services/device/public/mojom",
]
deps = [
diff --git a/chromium/services/device/wake_lock/power_save_blocker/power_save_blocker.h b/chromium/services/device/wake_lock/power_save_blocker/power_save_blocker.h
index 87a8b16d86e..64650087eb7 100644
--- a/chromium/services/device/wake_lock/power_save_blocker/power_save_blocker.h
+++ b/chromium/services/device/wake_lock/power_save_blocker/power_save_blocker.h
@@ -12,7 +12,7 @@
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
-#include "services/device/public/interfaces/wake_lock.mojom.h"
+#include "services/device/public/mojom/wake_lock.mojom.h"
#if defined(OS_ANDROID)
#include "ui/android/view_android.h"
diff --git a/chromium/services/device/wake_lock/power_save_blocker/power_save_blocker_x11.cc b/chromium/services/device/wake_lock/power_save_blocker/power_save_blocker_x11.cc
index d4f2565888f..b23d1ff8bb0 100644
--- a/chromium/services/device/wake_lock/power_save_blocker/power_save_blocker_x11.cc
+++ b/chromium/services/device/wake_lock/power_save_blocker/power_save_blocker_x11.cc
@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include <X11/Xlib.h>
-#include <X11/extensions/dpms.h>
#include <X11/extensions/scrnsaver.h>
#include <stdint.h>
@@ -120,19 +119,12 @@ class PowerSaveBlocker::Delegate
// Must be called on the UI thread.
void XSSSuspendSet(bool suspend);
- // If DPMS (the power saving system in X11) is not enabled, then we don't want
- // to try to disable power saving, since on some desktop environments that may
- // enable DPMS with very poor default settings (e.g. turning off the display
- // after only 1 second). Must be called on the UI thread.
- bool DPMSEnabled();
-
// If no other method is available (i.e. not running under a Desktop
// Environment) check whether the X11 Screen Saver Extension can be used
// to disable the screen saver. Must be called on the UI thread.
bool XSSAvailable();
// Returns an appropriate D-Bus API to use based on the desktop environment.
- // Must be called on the UI thread, as it may call DPMSEnabled() above.
DBusAPI SelectAPI();
const mojom::WakeLockType type_;
@@ -427,18 +419,6 @@ void PowerSaveBlocker::Delegate::XSSSuspendSet(bool suspend) {
XScreenSaverSuspend(display, suspend);
}
-bool PowerSaveBlocker::Delegate::DPMSEnabled() {
- DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
- XDisplay* display = gfx::GetXDisplay();
- BOOL enabled = false;
- int dummy;
- if (DPMSQueryExtension(display, &dummy, &dummy) && DPMSCapable(display)) {
- CARD16 state;
- DPMSInfo(display, &state, &enabled);
- }
- return enabled;
-}
-
bool PowerSaveBlocker::Delegate::XSSAvailable() {
DCHECK(ui_task_runner_->RunsTasksInCurrentSequence());
// X Screen Saver isn't accessible in headless mode.
@@ -463,21 +443,20 @@ DBusAPI PowerSaveBlocker::Delegate::SelectAPI() {
// Power saving APIs are not accessible in headless mode.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kHeadless))
return NO_API;
+
+ // TODO(thomasanderson): Query the GNOME and Freedesktop APIs for availability
+ // directly rather than guessing based on the desktop environment.
std::unique_ptr<base::Environment> env(base::Environment::Create());
switch (base::nix::GetDesktopEnvironment(env.get())) {
case base::nix::DESKTOP_ENVIRONMENT_CINNAMON:
case base::nix::DESKTOP_ENVIRONMENT_GNOME:
case base::nix::DESKTOP_ENVIRONMENT_PANTHEON:
case base::nix::DESKTOP_ENVIRONMENT_UNITY:
- if (DPMSEnabled())
- return GNOME_API;
- break;
+ return GNOME_API;
case base::nix::DESKTOP_ENVIRONMENT_XFCE:
case base::nix::DESKTOP_ENVIRONMENT_KDE4:
case base::nix::DESKTOP_ENVIRONMENT_KDE5:
- if (DPMSEnabled())
- return FREEDESKTOP_API;
- break;
+ return FREEDESKTOP_API;
case base::nix::DESKTOP_ENVIRONMENT_KDE3:
case base::nix::DESKTOP_ENVIRONMENT_OTHER:
// Not supported.
diff --git a/chromium/services/device/wake_lock/wake_lock.h b/chromium/services/device/wake_lock/wake_lock.h
index 9b7d898830a..b134e62876d 100644
--- a/chromium/services/device/wake_lock/wake_lock.h
+++ b/chromium/services/device/wake_lock/wake_lock.h
@@ -12,8 +12,8 @@
#include "base/single_thread_task_runner.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/device/public/interfaces/wake_lock.mojom.h"
-#include "services/device/public/interfaces/wake_lock_context.mojom.h"
+#include "services/device/public/mojom/wake_lock.mojom.h"
+#include "services/device/public/mojom/wake_lock_context.mojom.h"
#include "services/device/wake_lock/power_save_blocker/power_save_blocker.h"
#include "services/device/wake_lock/wake_lock_context.h"
#include "ui/gfx/native_widget_types.h"
diff --git a/chromium/services/device/wake_lock/wake_lock_context.h b/chromium/services/device/wake_lock/wake_lock_context.h
index 14e1befecb6..9a1d5f50bb2 100644
--- a/chromium/services/device/wake_lock/wake_lock_context.h
+++ b/chromium/services/device/wake_lock/wake_lock_context.h
@@ -11,7 +11,7 @@
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
-#include "services/device/public/interfaces/wake_lock_context.mojom.h"
+#include "services/device/public/mojom/wake_lock_context.mojom.h"
#include "ui/gfx/native_widget_types.h"
namespace device {
diff --git a/chromium/services/device/wake_lock/wake_lock_for_testing.h b/chromium/services/device/wake_lock/wake_lock_for_testing.h
index 6a6dd16ecc5..ef3b6620bcf 100644
--- a/chromium/services/device/wake_lock/wake_lock_for_testing.h
+++ b/chromium/services/device/wake_lock/wake_lock_for_testing.h
@@ -11,8 +11,8 @@
#include "base/memory/ref_counted.h"
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/device/public/interfaces/wake_lock.mojom.h"
-#include "services/device/public/interfaces/wake_lock_context.mojom.h"
+#include "services/device/public/mojom/wake_lock.mojom.h"
+#include "services/device/public/mojom/wake_lock_context.mojom.h"
#include "services/device/wake_lock/wake_lock.h"
#include "ui/gfx/native_widget_types.h"
diff --git a/chromium/services/device/wake_lock/wake_lock_provider.h b/chromium/services/device/wake_lock/wake_lock_provider.h
index 2bf187599b7..0197ba77d1f 100644
--- a/chromium/services/device/wake_lock/wake_lock_provider.h
+++ b/chromium/services/device/wake_lock/wake_lock_provider.h
@@ -8,8 +8,8 @@
#include "base/sequenced_task_runner.h"
#include "base/single_thread_task_runner.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/device/public/interfaces/wake_lock_context.mojom.h"
-#include "services/device/public/interfaces/wake_lock_provider.mojom.h"
+#include "services/device/public/mojom/wake_lock_context.mojom.h"
+#include "services/device/public/mojom/wake_lock_provider.mojom.h"
#include "services/device/wake_lock/wake_lock_context.h"
#include "ui/gfx/native_widget_types.h"
diff --git a/chromium/services/device/wake_lock/wake_lock_unittest.cc b/chromium/services/device/wake_lock/wake_lock_unittest.cc
index 888e99d731d..a32beb35bb0 100644
--- a/chromium/services/device/wake_lock/wake_lock_unittest.cc
+++ b/chromium/services/device/wake_lock/wake_lock_unittest.cc
@@ -5,10 +5,10 @@
#include "base/run_loop.h"
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "services/device/device_service_test_base.h"
-#include "services/device/public/interfaces/constants.mojom.h"
-#include "services/device/public/interfaces/wake_lock.mojom.h"
-#include "services/device/public/interfaces/wake_lock_context.mojom.h"
-#include "services/device/public/interfaces/wake_lock_provider.mojom.h"
+#include "services/device/public/mojom/constants.mojom.h"
+#include "services/device/public/mojom/wake_lock.mojom.h"
+#include "services/device/public/mojom/wake_lock_context.mojom.h"
+#include "services/device/public/mojom/wake_lock_provider.mojom.h"
#include "services/device/wake_lock/wake_lock_provider.h"
namespace device {
diff --git a/chromium/services/file/BUILD.gn b/chromium/services/file/BUILD.gn
index 45fc925e471..0e402e0dfdd 100644
--- a/chromium/services/file/BUILD.gn
+++ b/chromium/services/file/BUILD.gn
@@ -23,9 +23,9 @@ source_set("lib") {
"//components/leveldb/public/interfaces",
"//mojo/common",
"//mojo/common:common_base",
- "//services/file/public/interfaces",
+ "//services/file/public/mojom",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//url",
]
}
diff --git a/chromium/services/file/file_service.h b/chromium/services/file/file_service.h
index c3164250d58..977007c0321 100644
--- a/chromium/services/file/file_service.h
+++ b/chromium/services/file/file_service.h
@@ -11,7 +11,7 @@
#include "components/filesystem/lock_table.h"
#include "components/leveldb/public/interfaces/leveldb.mojom.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/file/public/interfaces/file_system.mojom.h"
+#include "services/file/public/mojom/file_system.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
diff --git a/chromium/services/file/file_system.h b/chromium/services/file/file_system.h
index 576ca574252..45dbda27c29 100644
--- a/chromium/services/file/file_system.h
+++ b/chromium/services/file/file_system.h
@@ -7,7 +7,7 @@
#include "base/files/file_path.h"
#include "components/filesystem/public/interfaces/directory.mojom.h"
-#include "services/file/public/interfaces/file_system.mojom.h"
+#include "services/file/public/mojom/file_system.mojom.h"
namespace filesystem {
class LockTable;
diff --git a/chromium/services/file/public/interfaces/BUILD.gn b/chromium/services/file/public/mojom/BUILD.gn
index 4139acd0ea6..b2fd12a7aca 100644
--- a/chromium/services/file/public/interfaces/BUILD.gn
+++ b/chromium/services/file/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"file_system.mojom",
]
diff --git a/chromium/services/file/public/interfaces/OWNERS b/chromium/services/file/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/file/public/interfaces/OWNERS
+++ b/chromium/services/file/public/mojom/OWNERS
diff --git a/chromium/services/file/public/interfaces/constants.mojom b/chromium/services/file/public/mojom/constants.mojom
index a37e97e3a59..a37e97e3a59 100644
--- a/chromium/services/file/public/interfaces/constants.mojom
+++ b/chromium/services/file/public/mojom/constants.mojom
diff --git a/chromium/services/file/public/interfaces/file_system.mojom b/chromium/services/file/public/mojom/file_system.mojom
index c3a422d4daf..c3a422d4daf 100644
--- a/chromium/services/file/public/interfaces/file_system.mojom
+++ b/chromium/services/file/public/mojom/file_system.mojom
diff --git a/chromium/services/identity/BUILD.gn b/chromium/services/identity/BUILD.gn
index 52a4c1f4291..b118e942d12 100644
--- a/chromium/services/identity/BUILD.gn
+++ b/chromium/services/identity/BUILD.gn
@@ -19,9 +19,9 @@ source_set("lib") {
"//components/signin/core/browser",
"//components/signin/core/browser:account_info",
"//services/identity/public/cpp:cpp_types",
- "//services/identity/public/interfaces",
+ "//services/identity/public/mojom",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
@@ -42,7 +42,7 @@ source_set("tests") {
"//components/sync_preferences:test_support",
"//mojo/public/cpp/bindings:bindings",
"//services/identity/public/cpp",
- "//services/identity/public/interfaces",
+ "//services/identity/public/mojom",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
"//testing/gmock",
diff --git a/chromium/services/identity/DEPS b/chromium/services/identity/DEPS
index f194cc9c1c1..3d7192ae03a 100644
--- a/chromium/services/identity/DEPS
+++ b/chromium/services/identity/DEPS
@@ -5,6 +5,7 @@ include_rules = [
"+components/signin/core/browser/fake_signin_manager.h",
"+components/signin/core/browser/profile_oauth2_token_service.h",
"+components/signin/core/browser/signin_manager_base.h",
+ "+components/signin/core/browser/signin_manager.h",
"+components/signin/core/browser/test_signin_client.h",
"+components/signin/public",
"+components/sync_preferences/testing_pref_service_syncable.h",
diff --git a/chromium/services/identity/identity_manager_impl.cc b/chromium/services/identity/identity_manager_impl.cc
index 9b14d88c579..64633c1cb44 100644
--- a/chromium/services/identity/identity_manager_impl.cc
+++ b/chromium/services/identity/identity_manager_impl.cc
@@ -9,7 +9,7 @@
#include "base/time/time.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "google_apis/gaia/google_service_auth_error.h"
-#include "services/identity/public/interfaces/account.mojom.h"
+#include "services/identity/public/mojom/account.mojom.h"
namespace identity {
diff --git a/chromium/services/identity/identity_manager_impl.h b/chromium/services/identity/identity_manager_impl.h
index 22316a7b512..05f4839aceb 100644
--- a/chromium/services/identity/identity_manager_impl.h
+++ b/chromium/services/identity/identity_manager_impl.h
@@ -12,7 +12,7 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/identity/public/cpp/account_state.h"
#include "services/identity/public/cpp/scope_set.h"
-#include "services/identity/public/interfaces/identity_manager.mojom.h"
+#include "services/identity/public/mojom/identity_manager.mojom.h"
class AccountTrackerService;
diff --git a/chromium/services/identity/identity_manager_impl_unittest.cc b/chromium/services/identity/identity_manager_impl_unittest.cc
index d75fefd879e..4ac9add4a21 100644
--- a/chromium/services/identity/identity_manager_impl_unittest.cc
+++ b/chromium/services/identity/identity_manager_impl_unittest.cc
@@ -15,12 +15,12 @@
#include "services/identity/identity_service.h"
#include "services/identity/public/cpp/account_state.h"
#include "services/identity/public/cpp/scope_set.h"
-#include "services/identity/public/interfaces/constants.mojom.h"
-#include "services/identity/public/interfaces/identity_manager.mojom.h"
+#include "services/identity/public/mojom/constants.mojom.h"
+#include "services/identity/public/mojom/identity_manager.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/service_manager/public/cpp/service_test.h"
-#include "services/service_manager/public/interfaces/service_factory.mojom.h"
+#include "services/service_manager/public/mojom/service_factory.mojom.h"
namespace identity {
namespace {
diff --git a/chromium/services/identity/identity_service.h b/chromium/services/identity/identity_service.h
index c0fe76bcc98..9d39063771b 100644
--- a/chromium/services/identity/identity_service.h
+++ b/chromium/services/identity/identity_service.h
@@ -6,7 +6,7 @@
#define SERVICES_IDENTITY_IDENTITY_SERVICE_H_
#include "components/signin/core/browser/signin_manager_base.h"
-#include "services/identity/public/interfaces/identity_manager.mojom.h"
+#include "services/identity/public/mojom/identity_manager.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
diff --git a/chromium/services/identity/public/cpp/BUILD.gn b/chromium/services/identity/public/cpp/BUILD.gn
index 3c0ad80f429..b6a97669512 100644
--- a/chromium/services/identity/public/cpp/BUILD.gn
+++ b/chromium/services/identity/public/cpp/BUILD.gn
@@ -32,6 +32,8 @@ source_set("test_support") {
sources = [
"identity_test_environment.cc",
"identity_test_environment.h",
+ "identity_test_utils.cc",
+ "identity_test_utils.h",
]
public_deps = [
diff --git a/chromium/services/identity/public/cpp/OWNERS b/chromium/services/identity/public/cpp/OWNERS
index 4df0c71cc7d..7aebc8abbf8 100644
--- a/chromium/services/identity/public/cpp/OWNERS
+++ b/chromium/services/identity/public/cpp/OWNERS
@@ -1,4 +1,4 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/identity/public/cpp/account_info.typemap b/chromium/services/identity/public/cpp/account_info.typemap
index f36dad26ab0..8c30fb059b2 100644
--- a/chromium/services/identity/public/cpp/account_info.typemap
+++ b/chromium/services/identity/public/cpp/account_info.typemap
@@ -2,12 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/identity/public/interfaces/account_info.mojom"
+mojom = "//services/identity/public/mojom/account_info.mojom"
public_headers = [ "//components/signin/core/browser/account_info.h" ]
traits_headers =
- [ "//services/identity/public/cpp/account_info_struct_traits.h" ]
+ [ "//services/identity/public/cpp/account_info_mojom_traits.h" ]
sources = [
- "//services/identity/public/cpp/account_info_struct_traits.cc",
+ "//services/identity/public/cpp/account_info_mojom_traits.cc",
]
public_deps = [
# TODO(blundell): In the long term, any files from //components/signin that
diff --git a/chromium/services/identity/public/cpp/account_info_struct_traits.cc b/chromium/services/identity/public/cpp/account_info_mojom_traits.cc
index 1fe4daa5a1a..b843df3c71c 100644
--- a/chromium/services/identity/public/cpp/account_info_struct_traits.cc
+++ b/chromium/services/identity/public/cpp/account_info_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/identity/public/cpp/account_info_struct_traits.h"
+#include "services/identity/public/cpp/account_info_mojom_traits.h"
namespace mojo {
diff --git a/chromium/services/identity/public/cpp/account_info_struct_traits.h b/chromium/services/identity/public/cpp/account_info_mojom_traits.h
index fb9ccf303ef..70763439128 100644
--- a/chromium/services/identity/public/cpp/account_info_struct_traits.h
+++ b/chromium/services/identity/public/cpp/account_info_mojom_traits.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_INFO_STRUCT_TRAITS_H_
-#define SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_INFO_STRUCT_TRAITS_H_
+#ifndef SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_INFO_MOJOM_TRAITS_H_
+#define SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_INFO_MOJOM_TRAITS_H_
#include <string>
#include "components/signin/core/browser/account_info.h"
-#include "services/identity/public/interfaces/account_info.mojom.h"
+#include "services/identity/public/mojom/account_info.mojom.h"
namespace mojo {
@@ -54,4 +54,4 @@ struct StructTraits<identity::mojom::AccountInfo::DataView, ::AccountInfo> {
} // namespace mojo
-#endif // SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_INFO_STRUCT_TRAITS_H_
+#endif // SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_INFO_MOJOM_TRAITS_H_
diff --git a/chromium/services/identity/public/cpp/account_state.typemap b/chromium/services/identity/public/cpp/account_state.typemap
index 69c2539c0ef..e28068fa27e 100644
--- a/chromium/services/identity/public/cpp/account_state.typemap
+++ b/chromium/services/identity/public/cpp/account_state.typemap
@@ -2,12 +2,12 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/identity/public/interfaces/account_state.mojom"
+mojom = "//services/identity/public/mojom/account_state.mojom"
public_headers = [ "//services/identity/public/cpp/account_state.h" ]
traits_headers =
- [ "//services/identity/public/cpp/account_state_struct_traits.h" ]
+ [ "//services/identity/public/cpp/account_state_mojom_traits.h" ]
sources = [
- "//services/identity/public/cpp/account_state_struct_traits.cc",
+ "//services/identity/public/cpp/account_state_mojom_traits.cc",
]
type_mappings = [ "identity.mojom.AccountState=identity::AccountState" ]
diff --git a/chromium/services/identity/public/cpp/account_state_struct_traits.cc b/chromium/services/identity/public/cpp/account_state_mojom_traits.cc
index 5bb5c17bf0a..d864c11311f 100644
--- a/chromium/services/identity/public/cpp/account_state_struct_traits.cc
+++ b/chromium/services/identity/public/cpp/account_state_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/identity/public/cpp/account_state_struct_traits.h"
+#include "services/identity/public/cpp/account_state_mojom_traits.h"
namespace mojo {
diff --git a/chromium/services/identity/public/cpp/account_state_struct_traits.h b/chromium/services/identity/public/cpp/account_state_mojom_traits.h
index 162756c1abc..525132d20d5 100644
--- a/chromium/services/identity/public/cpp/account_state_struct_traits.h
+++ b/chromium/services/identity/public/cpp/account_state_mojom_traits.h
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_STATE_STRUCT_TRAITS_H_
-#define SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_STATE_STRUCT_TRAITS_H_
+#ifndef SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_STATE_MOJOM_TRAITS_H_
+#define SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_STATE_MOJOM_TRAITS_H_
#include "services/identity/public/cpp/account_state.h"
-#include "services/identity/public/interfaces/account_state.mojom.h"
+#include "services/identity/public/mojom/account_state.mojom.h"
namespace mojo {
@@ -27,4 +27,4 @@ struct StructTraits<identity::mojom::AccountState::DataView,
} // namespace mojo
-#endif // SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_STATE_STRUCT_TRAITS_H_
+#endif // SERVICES_IDENTITY_PUBLIC_CPP_ACCOUNT_STATE_MOJOM_TRAITS_H_
diff --git a/chromium/services/identity/public/cpp/google_service_auth_error.typemap b/chromium/services/identity/public/cpp/google_service_auth_error.typemap
index 8212e41b133..7c8df77591d 100644
--- a/chromium/services/identity/public/cpp/google_service_auth_error.typemap
+++ b/chromium/services/identity/public/cpp/google_service_auth_error.typemap
@@ -2,11 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/identity/public/interfaces/google_service_auth_error.mojom"
+mojom = "//services/identity/public/mojom/google_service_auth_error.mojom"
public_headers = [ "//google_apis/gaia/google_service_auth_error.h" ]
-traits_headers = [ "//services/identity/public/cpp/google_service_auth_error_struct_traits.h" ]
+traits_headers = [
+ "//services/identity/public/cpp/google_service_auth_error_mojom_traits.h",
+]
sources = [
- "//services/identity/public/cpp/google_service_auth_error_struct_traits.cc",
+ "//services/identity/public/cpp/google_service_auth_error_mojom_traits.cc",
]
public_deps = [
# TODO(blundell): In the long term, any files from //google_apis that are
diff --git a/chromium/services/identity/public/cpp/google_service_auth_error_struct_traits.cc b/chromium/services/identity/public/cpp/google_service_auth_error_mojom_traits.cc
index c783ffbaee5..5ff3d94eb5f 100644
--- a/chromium/services/identity/public/cpp/google_service_auth_error_struct_traits.cc
+++ b/chromium/services/identity/public/cpp/google_service_auth_error_mojom_traits.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/identity/public/cpp/google_service_auth_error_struct_traits.h"
+#include "services/identity/public/cpp/google_service_auth_error_mojom_traits.h"
-#include "url/mojo/url_gurl_struct_traits.h"
+#include "url/mojom/url_gurl_mojom_traits.h"
namespace mojo {
diff --git a/chromium/services/identity/public/cpp/google_service_auth_error_struct_traits.h b/chromium/services/identity/public/cpp/google_service_auth_error_mojom_traits.h
index 04ffd309854..ce00da66e20 100644
--- a/chromium/services/identity/public/cpp/google_service_auth_error_struct_traits.h
+++ b/chromium/services/identity/public/cpp/google_service_auth_error_mojom_traits.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_IDENTITY_PUBLIC_CPP_GOOGLE_SERVICE_AUTH_ERROR_STRUCT_TRAITS_H_
-#define SERVICES_IDENTITY_PUBLIC_CPP_GOOGLE_SERVICE_AUTH_ERROR_STRUCT_TRAITS_H_
+#ifndef SERVICES_IDENTITY_PUBLIC_CPP_GOOGLE_SERVICE_AUTH_ERROR_MOJOM_TRAITS_H_
+#define SERVICES_IDENTITY_PUBLIC_CPP_GOOGLE_SERVICE_AUTH_ERROR_MOJOM_TRAITS_H_
#include <string>
#include "google_apis/gaia/google_service_auth_error.h"
-#include "services/identity/public/interfaces/google_service_auth_error.mojom.h"
+#include "services/identity/public/mojom/google_service_auth_error.mojom.h"
namespace mojo {
@@ -86,4 +86,4 @@ struct StructTraits<identity::mojom::SecondFactor::DataView,
} // namespace mojo
-#endif // SERVICES_IDENTITY_PUBLIC_CPP_GOOGLE_SERVICE_AUTH_ERROR_STRUCT_TRAITS_H_
+#endif // SERVICES_IDENTITY_PUBLIC_CPP_GOOGLE_SERVICE_AUTH_ERROR_MOJOM_TRAITS_H_
diff --git a/chromium/services/identity/public/cpp/identity_manager.cc b/chromium/services/identity/public/cpp/identity_manager.cc
index 0d73be12bf3..bf9a9d022b7 100644
--- a/chromium/services/identity/public/cpp/identity_manager.cc
+++ b/chromium/services/identity/public/cpp/identity_manager.cc
@@ -13,11 +13,19 @@ IdentityManager::IdentityManager(SigninManagerBase* signin_manager,
: signin_manager_(signin_manager), token_service_(token_service) {
primary_account_info_ = signin_manager_->GetAuthenticatedAccountInfo();
signin_manager_->AddObserver(this);
+#if !defined(OS_CHROMEOS)
+ SigninManager::FromSigninManagerBase(signin_manager_)
+ ->set_diagnostics_client(this);
+#endif
token_service_->AddDiagnosticsObserver(this);
}
IdentityManager::~IdentityManager() {
signin_manager_->RemoveObserver(this);
+#if !defined(OS_CHROMEOS)
+ SigninManager::FromSigninManagerBase(signin_manager_)
+ ->set_diagnostics_client(nullptr);
+#endif
token_service_->RemoveDiagnosticsObserver(this);
}
@@ -52,7 +60,7 @@ IdentityManager::CreateAccessTokenFetcherForPrimaryAccount(
const OAuth2TokenService::ScopeSet& scopes,
PrimaryAccountAccessTokenFetcher::TokenCallback callback,
PrimaryAccountAccessTokenFetcher::Mode mode) {
- return base::MakeUnique<PrimaryAccountAccessTokenFetcher>(
+ return std::make_unique<PrimaryAccountAccessTokenFetcher>(
oauth_consumer_name, signin_manager_, token_service_, scopes,
std::move(callback), mode);
}
@@ -89,17 +97,44 @@ void IdentityManager::SetPrimaryAccountSynchronouslyForTests(
std::string gaia_id,
std::string email_address,
std::string refresh_token) {
+ DCHECK(!refresh_token.empty());
+ SetPrimaryAccountSynchronously(gaia_id, email_address, refresh_token);
+}
+
+void IdentityManager::SetPrimaryAccountSynchronously(
+ std::string gaia_id,
+ std::string email_address,
+ std::string refresh_token) {
signin_manager_->SetAuthenticatedAccountInfo(gaia_id, email_address);
primary_account_info_ = signin_manager_->GetAuthenticatedAccountInfo();
- token_service_->UpdateCredentials(primary_account_info_.account_id,
- refresh_token);
+ if (!refresh_token.empty()) {
+ token_service_->UpdateCredentials(primary_account_info_.account_id,
+ refresh_token);
+ }
}
+#if !defined(OS_CHROMEOS)
+void IdentityManager::WillFireGoogleSigninSucceeded(
+ const AccountInfo& account_info) {
+ primary_account_info_ = account_info;
+}
+
+void IdentityManager::WillFireGoogleSignedOut(const AccountInfo& account_info) {
+ DCHECK(account_info.account_id == primary_account_info_.account_id);
+ DCHECK(account_info.gaia == primary_account_info_.gaia);
+ DCHECK(account_info.email == primary_account_info_.email);
+ primary_account_info_ = AccountInfo();
+}
+#endif
+
void IdentityManager::GoogleSigninSucceeded(const AccountInfo& account_info) {
// Fire observer callbacks asynchronously to mimic this callback itself coming
// in asynchronously from the Identity Service rather than synchronously from
// SigninManager.
+ DCHECK(account_info.account_id == primary_account_info_.account_id);
+ DCHECK(account_info.gaia == primary_account_info_.gaia);
+ DCHECK(account_info.email == primary_account_info_.email);
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&IdentityManager::HandleGoogleSigninSucceeded,
base::Unretained(this), account_info));
@@ -109,6 +144,7 @@ void IdentityManager::GoogleSignedOut(const AccountInfo& account_info) {
// Fire observer callbacks asynchronously to mimic this callback itself coming
// in asynchronously from the Identity Service rather than synchronously from
// SigninManager.
+ DCHECK(!HasPrimaryAccount());
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(&IdentityManager::HandleGoogleSignedOut,
base::Unretained(this), account_info));
@@ -129,17 +165,12 @@ void IdentityManager::OnAccessTokenRequested(
void IdentityManager::HandleGoogleSigninSucceeded(
const AccountInfo& account_info) {
- primary_account_info_ = account_info;
for (auto& observer : observer_list_) {
observer.OnPrimaryAccountSet(account_info);
}
}
void IdentityManager::HandleGoogleSignedOut(const AccountInfo& account_info) {
- DCHECK(account_info.account_id == primary_account_info_.account_id);
- DCHECK(account_info.gaia == primary_account_info_.gaia);
- DCHECK(account_info.email == primary_account_info_.email);
- primary_account_info_ = AccountInfo();
for (auto& observer : observer_list_) {
observer.OnPrimaryAccountCleared(account_info);
}
diff --git a/chromium/services/identity/public/cpp/identity_manager.h b/chromium/services/identity/public/cpp/identity_manager.h
index 07d184b8ee7..45a2ac06004 100644
--- a/chromium/services/identity/public/cpp/identity_manager.h
+++ b/chromium/services/identity/public/cpp/identity_manager.h
@@ -11,12 +11,37 @@
#include "components/signin/core/browser/signin_manager_base.h"
#include "services/identity/public/cpp/primary_account_access_token_fetcher.h"
+#if !defined(OS_CHROMEOS)
+#include "components/signin/core/browser/signin_manager.h"
+#endif
+
+// Necessary to declare this class as a friend.
+namespace chromeos {
+class ChromeSessionManager;
+}
+
+// Necessary to declare this class as a friend.
+class ProfileSyncServiceHarness;
+
+// Necessary to declare functions in identity_test_utils.h as friends.
+class FakeSigninManagerBase;
+class FakeSigninManager;
+
+#if defined(OS_CHROMEOS)
+using SigninManagerForTest = FakeSigninManagerBase;
+#else
+using SigninManagerForTest = FakeSigninManager;
+#endif // OS_CHROMEOS
+
namespace identity {
// Primary client-side interface to the Identity Service, encapsulating a
// connection to a remote implementation of mojom::IdentityManager. See
// ./README.md for detailed documentation.
class IdentityManager : public SigninManagerBase::Observer,
+#if !defined(OS_CHROMEOS)
+ public SigninManager::DiagnosticsClient,
+#endif
public OAuth2TokenService::DiagnosticsObserver {
public:
class Observer {
@@ -86,24 +111,46 @@ class IdentityManager : public SigninManagerBase::Observer,
void AddDiagnosticsObserver(DiagnosticsObserver* observer);
void RemoveDiagnosticsObserver(DiagnosticsObserver* observer);
+ private:
+ // These clients need to call SetPrimaryAccountSynchronouslyForTests().
+ friend void MakePrimaryAccountAvailable(
+ SigninManagerForTest* signin_manager,
+ ProfileOAuth2TokenService* token_service,
+ IdentityManager* identity_manager,
+ const std::string& email);
+ friend ProfileSyncServiceHarness;
+
+ // This client needs to call SetPrimaryAccountSynchronously().
+ friend chromeos::ChromeSessionManager;
+
// Sets the primary account info synchronously with both the IdentityManager
- // and its backing SigninManager/ProfileOAuth2TokenService instances. For use
- // only by tests. Even in testing contexts, use IdentityTestEnvironment if
- // possible (and IdentityTestEnvironment::MakePrimaryAccountAvailable()). This
- // method should be used directly only if the production code is using
- // IdentityManager, but it is not yet feasible to convert the test code to use
- // IdentityTestEnvironment. Any such usage should only be temporary, i.e.,
- // should be followed as quickly as possible by conversion of the test to
- // use IdentityTestEnvironment.
+ // and its backing SigninManager/ProfileOAuth2TokenService instances.
+ // Prefer using the methods in identity_test_{environment, utils}.h to using
+ // this method directly.
void SetPrimaryAccountSynchronouslyForTests(std::string gaia_id,
std::string email_address,
std::string refresh_token);
- private:
+ // Sets the primary account info synchronously with both the IdentityManager
+ // and its backing SigninManager instance. If |refresh_token| is not empty,
+ // sets the refresh token with the backing ProfileOAuth2TokenService
+ // instance. This method should not be used directly; it exists only to serve
+ // one legacy use case at this point.
+ // TODO(https://crbug.com/814787): Eliminate the need for this method.
+ void SetPrimaryAccountSynchronously(std::string gaia_id,
+ std::string email_address,
+ std::string refresh_token);
+
// SigninManagerBase::Observer:
void GoogleSigninSucceeded(const AccountInfo& account_info) override;
void GoogleSignedOut(const AccountInfo& account_info) override;
+#if !defined(OS_CHROMEOS)
+ // SigninManagerBase::DiagnosticsClient:
+ void WillFireGoogleSigninSucceeded(const AccountInfo& account_info) override;
+ void WillFireGoogleSignedOut(const AccountInfo& account_info) override;
+#endif
+
// OAuth2TokenService::DiagnosticsObserver:
void OnAccessTokenRequested(
const std::string& account_id,
diff --git a/chromium/services/identity/public/cpp/identity_manager_unittest.cc b/chromium/services/identity/public/cpp/identity_manager_unittest.cc
index 06a3a56cfba..caa5135300a 100644
--- a/chromium/services/identity/public/cpp/identity_manager_unittest.cc
+++ b/chromium/services/identity/public/cpp/identity_manager_unittest.cc
@@ -61,6 +61,59 @@ class CustomFakeProfileOAuth2TokenService
base::OnceClosure on_access_token_invalidated_callback_;
};
+class TestSigninManagerObserver : public SigninManagerBase::Observer {
+ public:
+ explicit TestSigninManagerObserver(SigninManagerBase* signin_manager)
+ : signin_manager_(signin_manager) {
+ signin_manager_->AddObserver(this);
+ }
+ ~TestSigninManagerObserver() override {
+ signin_manager_->RemoveObserver(this);
+ }
+
+ void set_identity_manager(IdentityManager* identity_manager) {
+ identity_manager_ = identity_manager;
+ }
+
+ void set_on_google_signin_succeeded_callback(base::OnceClosure callback) {
+ on_google_signin_succeeded_callback_ = std::move(callback);
+ }
+ void set_on_google_signed_out_callback(base::OnceClosure callback) {
+ on_google_signed_out_callback_ = std::move(callback);
+ }
+
+ const AccountInfo& primary_account_from_signin_callback() {
+ return primary_account_from_signin_callback_;
+ }
+ const AccountInfo& primary_account_from_signout_callback() {
+ return primary_account_from_signout_callback_;
+ }
+
+ private:
+ // SigninManager::Observer:
+ void GoogleSigninSucceeded(const AccountInfo& account_info) override {
+ ASSERT_TRUE(identity_manager_);
+ primary_account_from_signin_callback_ =
+ identity_manager_->GetPrimaryAccountInfo();
+ if (on_google_signin_succeeded_callback_)
+ std::move(on_google_signin_succeeded_callback_).Run();
+ }
+ void GoogleSignedOut(const AccountInfo& account_info) override {
+ ASSERT_TRUE(identity_manager_);
+ primary_account_from_signout_callback_ =
+ identity_manager_->GetPrimaryAccountInfo();
+ if (on_google_signed_out_callback_)
+ std::move(on_google_signed_out_callback_).Run();
+ }
+
+ SigninManagerBase* signin_manager_;
+ IdentityManager* identity_manager_;
+ base::OnceClosure on_google_signin_succeeded_callback_;
+ base::OnceClosure on_google_signed_out_callback_;
+ AccountInfo primary_account_from_signin_callback_;
+ AccountInfo primary_account_from_signout_callback_;
+};
+
class TestIdentityManagerObserver : IdentityManager::Observer {
public:
explicit TestIdentityManagerObserver(IdentityManager* identity_manager)
@@ -177,12 +230,7 @@ class IdentityManagerTest : public testing::Test {
signin_manager()->SetAuthenticatedAccountInfo(kTestGaiaId, kTestEmail);
- identity_manager_.reset(
- new IdentityManager(&signin_manager_, &token_service_));
- identity_manager_observer_.reset(
- new TestIdentityManagerObserver(identity_manager_.get()));
- identity_manager_diagnostics_observer_.reset(
- new TestIdentityManagerDiagnosticsObserver(identity_manager_.get()));
+ RecreateIdentityManager();
}
IdentityManager* identity_manager() { return identity_manager_.get(); }
@@ -199,6 +247,24 @@ class IdentityManagerTest : public testing::Test {
return &token_service_;
}
+ // Used by some tests that need to re-instantiate IdentityManager after
+ // performing some other setup.
+ void RecreateIdentityManager() {
+ // Reset them all to null first to ensure that they're destroyed, as
+ // otherwise SigninManager ends up getting a new DiagnosticsObserver added
+ // before the old one is removed.
+ identity_manager_observer_.reset();
+ identity_manager_diagnostics_observer_.reset();
+ identity_manager_.reset();
+
+ identity_manager_.reset(
+ new IdentityManager(&signin_manager_, &token_service_));
+ identity_manager_observer_.reset(
+ new TestIdentityManagerObserver(identity_manager_.get()));
+ identity_manager_diagnostics_observer_.reset(
+ new TestIdentityManagerDiagnosticsObserver(identity_manager_.get()));
+ }
+
private:
base::MessageLoop message_loop_;
sync_preferences::TestingPrefServiceSyncable pref_service_;
@@ -356,4 +422,56 @@ TEST_F(IdentityManagerTest, ObserveAccessTokenFetch) {
identity_manager_diagnostics_observer()->token_requestor_scopes());
}
+#if !defined(OS_CHROMEOS)
+TEST_F(IdentityManagerTest,
+ IdentityManagerGetsSignInEventBeforeSigninManagerObserver) {
+ signin_manager()->ForceSignOut();
+
+ base::RunLoop run_loop;
+ TestSigninManagerObserver signin_manager_observer(signin_manager());
+ signin_manager_observer.set_on_google_signin_succeeded_callback(
+ run_loop.QuitClosure());
+
+ // NOTE: For this test to be meaningful, TestSigninManagerObserver
+ // needs to be created before the IdentityManager instance that it's
+ // interacting with. Otherwise, even an implementation where they're
+ // both SigninManager::Observers would work as IdentityManager would
+ // get notified first during the observer callbacks.
+ RecreateIdentityManager();
+ signin_manager_observer.set_identity_manager(identity_manager());
+
+ signin_manager()->SignIn(kTestGaiaId, kTestEmail, "password");
+ run_loop.Run();
+
+ AccountInfo primary_account_from_signin_callback =
+ signin_manager_observer.primary_account_from_signin_callback();
+ EXPECT_EQ(kTestGaiaId, primary_account_from_signin_callback.gaia);
+ EXPECT_EQ(kTestEmail, primary_account_from_signin_callback.email);
+}
+
+TEST_F(IdentityManagerTest,
+ IdentityManagerGetsSignOutEventBeforeSigninManagerObserver) {
+ base::RunLoop run_loop;
+ TestSigninManagerObserver signin_manager_observer(signin_manager());
+ signin_manager_observer.set_on_google_signed_out_callback(
+ run_loop.QuitClosure());
+
+ // NOTE: For this test to be meaningful, TestSigninManagerObserver
+ // needs to be created before the IdentityManager instance that it's
+ // interacting with. Otherwise, even an implementation where they're
+ // both SigninManager::Observers would work as IdentityManager would
+ // get notified first during the observer callbacks.
+ RecreateIdentityManager();
+ signin_manager_observer.set_identity_manager(identity_manager());
+
+ signin_manager()->ForceSignOut();
+ run_loop.Run();
+
+ AccountInfo primary_account_from_signout_callback =
+ signin_manager_observer.primary_account_from_signout_callback();
+ EXPECT_EQ(std::string(), primary_account_from_signout_callback.gaia);
+ EXPECT_EQ(std::string(), primary_account_from_signout_callback.email);
+}
+#endif
+
} // namespace identity
diff --git a/chromium/services/identity/public/cpp/identity_test_environment.cc b/chromium/services/identity/public/cpp/identity_test_environment.cc
index 2a6f28f7073..9c86d4b531b 100644
--- a/chromium/services/identity/public/cpp/identity_test_environment.cc
+++ b/chromium/services/identity/public/cpp/identity_test_environment.cc
@@ -11,6 +11,7 @@
#include "components/signin/core/browser/profile_management_switches.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
+#include "services/identity/public/cpp/identity_test_utils.h"
#if defined(OS_CHROMEOS)
using SigninManagerForTest = FakeSigninManagerBase;
@@ -96,12 +97,15 @@ IdentityManager* IdentityTestEnvironment::identity_manager() {
return internals_->identity_manager();
}
-void IdentityTestEnvironment::MakePrimaryAccountAvailable(
- std::string gaia_id,
- std::string email_address,
- std::string refresh_token) {
- internals_->identity_manager()->SetPrimaryAccountSynchronouslyForTests(
- gaia_id, email_address, refresh_token);
+void IdentityTestEnvironment::MakePrimaryAccountAvailable(std::string email) {
+ identity::MakePrimaryAccountAvailable(internals_->signin_manager(),
+ internals_->token_service(),
+ internals_->identity_manager(), email);
+}
+
+void IdentityTestEnvironment::ClearPrimaryAccount() {
+ identity::ClearPrimaryAccount(internals_->signin_manager(),
+ internals_->identity_manager());
}
void IdentityTestEnvironment::SetAutomaticIssueOfAccessTokens(bool grant) {
@@ -109,6 +113,14 @@ void IdentityTestEnvironment::SetAutomaticIssueOfAccessTokens(bool grant) {
grant);
}
+void IdentityTestEnvironment::WaitForAccessTokenRequestAndRespondWithToken(
+ const std::string& token,
+ const base::Time& expiration) {
+ WaitForAccessTokenRequest();
+ internals_->token_service()->IssueTokenForAllPendingRequests(token,
+ expiration);
+}
+
void IdentityTestEnvironment::WaitForAccessTokenRequestAndRespondWithError(
const GoogleServiceAuthError& error) {
WaitForAccessTokenRequest();
diff --git a/chromium/services/identity/public/cpp/identity_test_environment.h b/chromium/services/identity/public/cpp/identity_test_environment.h
index 355029b433d..03a69516068 100644
--- a/chromium/services/identity/public/cpp/identity_test_environment.h
+++ b/chromium/services/identity/public/cpp/identity_test_environment.h
@@ -23,15 +23,30 @@ class IdentityTestEnvironment : public IdentityManager::DiagnosticsObserver {
// The IdentityManager instance created and owned by this instance.
IdentityManager* identity_manager();
- // Synchronously makes the primary account available with the given values.
- void MakePrimaryAccountAvailable(std::string gaia_id,
- std::string email_address,
- std::string refresh_token);
+ // Makes the primary account available for the given email address, generating
+ // a GAIA ID and refresh token that correspond uniquely to that email address.
+ // On non-ChromeOS platforms, this will also result in the firing of the
+ // IdentityManager and SigninManager callbacks for signin success. On all
+ // platforms, this method blocks until the primary account is available.
+ void MakePrimaryAccountAvailable(std::string email);
+
+ // Clears the primary account. On non-ChromeOS, results in the firing of the
+ // IdentityManager and SigninManager callbacks for signout. Blocks until the
+ // primary account is cleared.
+ void ClearPrimaryAccount();
// When this is set, access token requests will be automatically granted with
// an access token value of "access_token".
void SetAutomaticIssueOfAccessTokens(bool grant);
+ // Waits for an access token request to occur and issues |token| in response.
+ // NOTE: The implementation currently issues tokens in response to *all*
+ // pending access token requests. If you need finer granularity, contact
+ // blundell@chromium.org
+ void WaitForAccessTokenRequestAndRespondWithToken(
+ const std::string& token,
+ const base::Time& expiration);
+
// Waits for an access token request to occur and issues |error| in response.
// NOTE: The implementation currently issues errors in response to *all*
// pending access token requests. If you need finer granularity, contact
diff --git a/chromium/services/identity/public/cpp/identity_test_utils.cc b/chromium/services/identity/public/cpp/identity_test_utils.cc
new file mode 100644
index 00000000000..99083cfe826
--- /dev/null
+++ b/chromium/services/identity/public/cpp/identity_test_utils.cc
@@ -0,0 +1,117 @@
+// Copyright 2018 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/identity/public/cpp/identity_test_utils.h"
+
+#include "base/run_loop.h"
+#include "base/strings/string_split.h"
+#include "components/signin/core/browser/fake_signin_manager.h"
+#include "components/signin/core/browser/profile_oauth2_token_service.h"
+#include "services/identity/public/cpp/identity_manager.h"
+
+#if defined(OS_CHROMEOS)
+using SigninManagerForTest = FakeSigninManagerBase;
+#else
+using SigninManagerForTest = FakeSigninManager;
+#endif // OS_CHROMEOS
+
+namespace identity {
+
+namespace {
+
+class OneShotIdentityManagerObserver : public IdentityManager::Observer {
+ public:
+ OneShotIdentityManagerObserver(IdentityManager* identity_manager,
+ base::OnceClosure done_closure);
+ ~OneShotIdentityManagerObserver() override;
+
+ private:
+ // IdentityManager::Observer:
+ void OnPrimaryAccountSet(const AccountInfo& primary_account_info) override;
+
+ void OnPrimaryAccountCleared(
+ const AccountInfo& previous_primary_account_info) override;
+
+ IdentityManager* identity_manager_;
+ base::OnceClosure done_closure_;
+
+ DISALLOW_COPY_AND_ASSIGN(OneShotIdentityManagerObserver);
+};
+
+OneShotIdentityManagerObserver::OneShotIdentityManagerObserver(
+ IdentityManager* identity_manager,
+ base::OnceClosure done_closure)
+ : identity_manager_(identity_manager),
+ done_closure_(std::move(done_closure)) {
+ identity_manager_->AddObserver(this);
+}
+
+OneShotIdentityManagerObserver::~OneShotIdentityManagerObserver() {
+ identity_manager_->RemoveObserver(this);
+}
+
+void OneShotIdentityManagerObserver::OnPrimaryAccountSet(
+ const AccountInfo& primary_account_info) {
+ DCHECK(done_closure_);
+ std::move(done_closure_).Run();
+}
+
+void OneShotIdentityManagerObserver::OnPrimaryAccountCleared(
+ const AccountInfo& previous_primary_account_info) {
+ DCHECK(done_closure_);
+ std::move(done_closure_).Run();
+}
+
+} // namespace
+
+void MakePrimaryAccountAvailable(SigninManagerForTest* signin_manager,
+ ProfileOAuth2TokenService* token_service,
+ IdentityManager* identity_manager,
+ const std::string& email) {
+ DCHECK(!signin_manager->IsAuthenticated());
+ DCHECK(!identity_manager->HasPrimaryAccount());
+ std::string gaia_id = "gaia_id_for_" + email;
+ std::string refresh_token = "refresh_token_for_" + email;
+
+#if defined(OS_CHROMEOS)
+ // ChromeOS has no real notion of signin, so just plumb the information
+ // through.
+ identity_manager->SetPrimaryAccountSynchronouslyForTests(gaia_id, email,
+ refresh_token);
+#else
+
+ base::RunLoop run_loop;
+ OneShotIdentityManagerObserver signin_observer(identity_manager,
+ run_loop.QuitClosure());
+
+ signin_manager->StartSignInWithRefreshToken(
+ refresh_token, gaia_id, email, /*password=*/"",
+ SigninManager::OAuthTokenFetchedCallback());
+ signin_manager->CompletePendingSignin();
+ token_service->UpdateCredentials(signin_manager->GetAuthenticatedAccountId(),
+ refresh_token);
+
+ run_loop.Run();
+#endif
+}
+
+void ClearPrimaryAccount(SigninManagerForTest* signin_manager,
+ IdentityManager* identity_manager) {
+#if defined(OS_CHROMEOS)
+ // TODO(blundell): If we ever need this functionality on ChromeOS (which seems
+ // unlikely), plumb this through to just clear the primary account info
+ // synchronously with IdentityManager.
+ NOTREACHED();
+#else
+ base::RunLoop run_loop;
+ OneShotIdentityManagerObserver signout_observer(identity_manager,
+ run_loop.QuitClosure());
+
+ signin_manager->ForceSignOut();
+
+ run_loop.Run();
+#endif
+}
+
+} // namespace identity
diff --git a/chromium/services/identity/public/cpp/identity_test_utils.h b/chromium/services/identity/public/cpp/identity_test_utils.h
new file mode 100644
index 00000000000..e78f9ce1635
--- /dev/null
+++ b/chromium/services/identity/public/cpp/identity_test_utils.h
@@ -0,0 +1,53 @@
+// Copyright 2018 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 SERVICES_IDENTITY_PUBLIC_CPP_IDENTITY_TEST_UTILS_H_
+#define SERVICES_IDENTITY_PUBLIC_CPP_IDENTITY_TEST_UTILS_H_
+
+#include <string>
+
+#include "build/build_config.h"
+
+class FakeSigninManagerBase;
+class FakeSigninManager;
+class ProfileOAuth2TokenService;
+
+#if defined(OS_CHROMEOS)
+using SigninManagerForTest = FakeSigninManagerBase;
+#else
+using SigninManagerForTest = FakeSigninManager;
+#endif // OS_CHROMEOS
+
+// Test-related utilities that don't fit in either IdentityTestEnvironment or
+// IdentityManager itself. NOTE: Using these utilities directly is discouraged,
+// but sometimes necessary during conversion. Use IdentityTestEnvironment if
+// possible. These utilities should be used directly only if the production code
+// is using IdentityManager, but it is not yet feasible to convert the test code
+// to use IdentityTestEnvironment. Any such usage should only be temporary,
+// i.e., should be followed as quickly as possible by conversion of the test
+// code to use IdentityTestEnvironment.
+namespace identity {
+
+class IdentityManager;
+
+// Makes the primary account available for the given email address, generating a
+// GAIA ID and refresh token that correspond uniquely to that email address. On
+// non-ChromeOS, results in the firing of the IdentityManager and SigninManager
+// callbacks for signin success. Blocks until the primary account is available.
+// NOTE: See disclaimer at top of file re: direct usage.
+void MakePrimaryAccountAvailable(SigninManagerForTest* signin_manager,
+ ProfileOAuth2TokenService* token_service,
+ IdentityManager* identity_manager,
+ const std::string& email);
+
+// Clears the primary account. On non-ChromeOS, results in the firing of the
+// IdentityManager and SigninManager callbacks for signout. Blocks until the
+// primary account is cleared.
+// NOTE: See disclaimer at top of file re: direct usage.
+void ClearPrimaryAccount(SigninManagerForTest* signin_manager,
+ IdentityManager* identity_manager);
+
+} // namespace identity
+
+#endif // SERVICES_IDENTITY_PUBLIC_CPP_IDENTITY_TEST_UTILS_H_
diff --git a/chromium/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc b/chromium/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc
index cc4fac03e8f..090661d34bd 100644
--- a/chromium/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc
+++ b/chromium/services/identity/public/cpp/primary_account_access_token_fetcher_unittest.cc
@@ -16,7 +16,6 @@
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/fake_profile_oauth2_token_service.h"
#include "components/signin/core/browser/fake_signin_manager.h"
-#include "components/signin/core/browser/profile_management_switches.h"
#include "components/signin/core/browser/test_signin_client.h"
#include "components/sync_preferences/testing_pref_service_syncable.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -62,7 +61,6 @@ class PrimaryAccountAccessTokenFetcherTest
PrimaryAccountAccessTokenFetcherTest() : signin_client_(&pref_service_) {
AccountTrackerService::RegisterPrefs(pref_service_.registry());
- signin::RegisterAccountConsistencyProfilePrefs(pref_service_.registry());
#if defined(OS_CHROMEOS)
SigninManagerBase::RegisterProfilePrefs(pref_service_.registry());
SigninManagerBase::RegisterPrefs(pref_service_.registry());
@@ -71,17 +69,14 @@ class PrimaryAccountAccessTokenFetcherTest
SigninManager::RegisterPrefs(pref_service_.registry());
#endif // OS_CHROMEOS
- signin::SetGaiaOriginIsolatedCallback(
- base::BindRepeating([] { return true; }));
-
- account_tracker_ = base::MakeUnique<AccountTrackerService>();
+ account_tracker_ = std::make_unique<AccountTrackerService>();
account_tracker_->Initialize(&signin_client_);
#if defined(OS_CHROMEOS)
- signin_manager_ = base::MakeUnique<FakeSigninManagerBase>(
+ signin_manager_ = std::make_unique<FakeSigninManagerBase>(
&signin_client_, account_tracker_.get());
#else
- signin_manager_ = base::MakeUnique<FakeSigninManager>(
+ signin_manager_ = std::make_unique<FakeSigninManager>(
&signin_client_, &token_service_, account_tracker_.get(),
/*cookie_manager_service=*/nullptr);
#endif // OS_CHROMEOS
@@ -96,7 +91,7 @@ class PrimaryAccountAccessTokenFetcherTest
PrimaryAccountAccessTokenFetcher::TokenCallback callback,
PrimaryAccountAccessTokenFetcher::Mode mode) {
std::set<std::string> scopes{"scope"};
- return base::MakeUnique<PrimaryAccountAccessTokenFetcher>(
+ return std::make_unique<PrimaryAccountAccessTokenFetcher>(
"test_consumer", signin_manager_.get(), &token_service_, scopes,
std::move(callback), mode);
}
diff --git a/chromium/services/identity/public/cpp/scope_set.typemap b/chromium/services/identity/public/cpp/scope_set.typemap
index eec17a982d2..7612befbafe 100644
--- a/chromium/services/identity/public/cpp/scope_set.typemap
+++ b/chromium/services/identity/public/cpp/scope_set.typemap
@@ -2,9 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/identity/public/interfaces/scope_set.mojom"
+mojom = "//services/identity/public/mojom/scope_set.mojom"
public_headers = [ "//services/identity/public/cpp/scope_set.h" ]
-traits_headers = [ "//services/identity/public/cpp/scope_set_struct_traits.h" ]
+traits_headers = [ "//services/identity/public/cpp/scope_set_mojom_traits.h" ]
public_deps = [
"//services/identity/public/cpp:cpp_types",
]
diff --git a/chromium/services/identity/public/cpp/scope_set_struct_traits.h b/chromium/services/identity/public/cpp/scope_set_mojom_traits.h
index 17882b0d541..accfc720aa8 100644
--- a/chromium/services/identity/public/cpp/scope_set_struct_traits.h
+++ b/chromium/services/identity/public/cpp/scope_set_mojom_traits.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_IDENTITY_PUBLIC_CPP_SCOPE_SET_STRUCT_TRAITS_H_
-#define SERVICES_IDENTITY_PUBLIC_CPP_SCOPE_SET_STRUCT_TRAITS_H_
+#ifndef SERVICES_IDENTITY_PUBLIC_CPP_SCOPE_SET_MOJOM_TRAITS_H_
+#define SERVICES_IDENTITY_PUBLIC_CPP_SCOPE_SET_MOJOM_TRAITS_H_
#include "services/identity/public/cpp/scope_set.h"
@@ -34,4 +34,4 @@ struct StructTraits<identity::mojom::ScopeSet::DataView, identity::ScopeSet> {
} // namespace mojo
-#endif // SERVICES_IDENTITY_PUBLIC_CPP_SCOPE_SET_STRUCT_TRAITS_H_
+#endif // SERVICES_IDENTITY_PUBLIC_CPP_SCOPE_SET_MOJOM_TRAITS_H_
diff --git a/chromium/services/identity/public/interfaces/BUILD.gn b/chromium/services/identity/public/mojom/BUILD.gn
index 8cda1b0c85e..fbfa2ea1f76 100644
--- a/chromium/services/identity/public/interfaces/BUILD.gn
+++ b/chromium/services/identity/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"account.mojom",
"account_info.mojom",
@@ -17,7 +17,7 @@ mojom("interfaces") {
public_deps = [
":constants",
"//mojo/common:common_custom_types",
- "//url/mojo:url_mojom_gurl",
+ "//url/mojom:url_mojom_gurl",
]
}
diff --git a/chromium/services/identity/public/interfaces/OWNERS b/chromium/services/identity/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/identity/public/interfaces/OWNERS
+++ b/chromium/services/identity/public/mojom/OWNERS
diff --git a/chromium/services/identity/public/interfaces/account.mojom b/chromium/services/identity/public/mojom/account.mojom
index 77104a92661..5177a277581 100644
--- a/chromium/services/identity/public/interfaces/account.mojom
+++ b/chromium/services/identity/public/mojom/account.mojom
@@ -4,8 +4,8 @@
module identity.mojom;
-import "services/identity/public/interfaces/account_info.mojom";
-import "services/identity/public/interfaces/account_state.mojom";
+import "services/identity/public/mojom/account_info.mojom";
+import "services/identity/public/mojom/account_state.mojom";
// Represents a user's Google account on this device.
struct Account {
diff --git a/chromium/services/identity/public/interfaces/account_info.mojom b/chromium/services/identity/public/mojom/account_info.mojom
index 670211cef90..670211cef90 100644
--- a/chromium/services/identity/public/interfaces/account_info.mojom
+++ b/chromium/services/identity/public/mojom/account_info.mojom
diff --git a/chromium/services/identity/public/interfaces/account_state.mojom b/chromium/services/identity/public/mojom/account_state.mojom
index e3364c4de99..e3364c4de99 100644
--- a/chromium/services/identity/public/interfaces/account_state.mojom
+++ b/chromium/services/identity/public/mojom/account_state.mojom
diff --git a/chromium/services/identity/public/interfaces/constants.mojom b/chromium/services/identity/public/mojom/constants.mojom
index e4fbfce6b3d..e4fbfce6b3d 100644
--- a/chromium/services/identity/public/interfaces/constants.mojom
+++ b/chromium/services/identity/public/mojom/constants.mojom
diff --git a/chromium/services/identity/public/interfaces/google_service_auth_error.mojom b/chromium/services/identity/public/mojom/google_service_auth_error.mojom
index 435d2c9199e..e5033373e2f 100644
--- a/chromium/services/identity/public/interfaces/google_service_auth_error.mojom
+++ b/chromium/services/identity/public/mojom/google_service_auth_error.mojom
@@ -4,7 +4,7 @@
module identity.mojom;
-import "url/mojo/url.mojom";
+import "url/mojom/url.mojom";
// Defines an authentication error from a Google service. See comments on
// google_service_auth_error.h, to which these interfaces are typemapped.
diff --git a/chromium/services/identity/public/interfaces/identity_manager.mojom b/chromium/services/identity/public/mojom/identity_manager.mojom
index 1f31f2ac0f1..4410269a301 100644
--- a/chromium/services/identity/public/interfaces/identity_manager.mojom
+++ b/chromium/services/identity/public/mojom/identity_manager.mojom
@@ -5,11 +5,11 @@
module identity.mojom;
import "mojo/common/time.mojom";
-import "services/identity/public/interfaces/account.mojom";
-import "services/identity/public/interfaces/account_info.mojom";
-import "services/identity/public/interfaces/account_state.mojom";
-import "services/identity/public/interfaces/google_service_auth_error.mojom";
-import "services/identity/public/interfaces/scope_set.mojom";
+import "services/identity/public/mojom/account.mojom";
+import "services/identity/public/mojom/account_info.mojom";
+import "services/identity/public/mojom/account_state.mojom";
+import "services/identity/public/mojom/google_service_auth_error.mojom";
+import "services/identity/public/mojom/scope_set.mojom";
// Gives access to information about the user's Google accounts.
interface IdentityManager {
diff --git a/chromium/services/identity/public/interfaces/scope_set.mojom b/chromium/services/identity/public/mojom/scope_set.mojom
index f2cd469b93b..f2cd469b93b 100644
--- a/chromium/services/identity/public/interfaces/scope_set.mojom
+++ b/chromium/services/identity/public/mojom/scope_set.mojom
diff --git a/chromium/services/metrics/BUILD.gn b/chromium/services/metrics/BUILD.gn
index 0246bf41eb9..a3984985ee9 100644
--- a/chromium/services/metrics/BUILD.gn
+++ b/chromium/services/metrics/BUILD.gn
@@ -20,7 +20,7 @@ source_set("metrics") {
deps = [
"//mojo/public/cpp/bindings",
"//services/metrics/public/cpp:metrics_cpp",
- "//services/metrics/public/interfaces",
+ "//services/metrics/public/mojom",
"//services/service_manager/public/cpp",
"//url",
]
diff --git a/chromium/services/metrics/public/cpp/BUILD.gn b/chromium/services/metrics/public/cpp/BUILD.gn
index aff3047502c..bea0d6da839 100644
--- a/chromium/services/metrics/public/cpp/BUILD.gn
+++ b/chromium/services/metrics/public/cpp/BUILD.gn
@@ -27,7 +27,7 @@ component("metrics_cpp") {
public_deps = [
"//base",
- "//services/metrics/public/interfaces",
+ "//services/metrics/public/mojom",
"//url",
]
@@ -37,6 +37,20 @@ component("metrics_cpp") {
]
}
+source_set("tests") {
+ testonly = true
+
+ sources = [
+ "metrics_utils_unittest.cc",
+ ]
+
+ deps = [
+ ":metrics_cpp",
+ "//base",
+ "//testing/gtest",
+ ]
+}
+
action("gen_ukm_builders") {
script = "//tools/metrics/ukm/gen_builders.py"
diff --git a/chromium/services/metrics/public/cpp/delegating_ukm_recorder.h b/chromium/services/metrics/public/cpp/delegating_ukm_recorder.h
index 0faa2d433e4..db80932a628 100644
--- a/chromium/services/metrics/public/cpp/delegating_ukm_recorder.h
+++ b/chromium/services/metrics/public/cpp/delegating_ukm_recorder.h
@@ -12,7 +12,7 @@
#include "base/synchronization/lock.h"
#include "services/metrics/public/cpp/metrics_export.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace ukm {
diff --git a/chromium/services/metrics/public/cpp/metrics_utils.cc b/chromium/services/metrics/public/cpp/metrics_utils.cc
index e08843b6447..521c265a17c 100644
--- a/chromium/services/metrics/public/cpp/metrics_utils.cc
+++ b/chromium/services/metrics/public/cpp/metrics_utils.cc
@@ -4,10 +4,11 @@
#include "services/metrics/public/cpp/metrics_utils.h"
-#include <math.h>
-
#include <cmath>
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+
namespace ukm {
int64_t GetExponentialBucketMin(int64_t sample, double bucket_spacing) {
@@ -21,4 +22,22 @@ int64_t GetExponentialBucketMin(int64_t sample, double bucket_spacing) {
bucket_spacing, std::floor(std::log(sample) / std::log(bucket_spacing))));
}
+int64_t GetLinearBucketMin(int64_t sample, int32_t bucket_size) {
+ DCHECK(bucket_size > 0);
+ // Round down to the nearest multiple of |bucket_size| (for negative samples,
+ // this rounds away from zero).
+ int64_t remainder = sample % bucket_size;
+ if (remainder < 0)
+ return sample - (remainder + bucket_size);
+ return sample - remainder;
+}
+
+int64_t GetLinearBucketMin(double sample, int32_t bucket_size) {
+ int64_t val = GetLinearBucketMin(
+ base::saturated_cast<int64_t>(std::floor(sample)), bucket_size);
+ // Ensure that |sample| can't get put into a bucket higher than itself.
+ DCHECK(val <= sample);
+ return val;
+}
+
} // namespace ukm
diff --git a/chromium/services/metrics/public/cpp/metrics_utils.h b/chromium/services/metrics/public/cpp/metrics_utils.h
index 1bffe01387c..f10cddeb67a 100644
--- a/chromium/services/metrics/public/cpp/metrics_utils.h
+++ b/chromium/services/metrics/public/cpp/metrics_utils.h
@@ -17,6 +17,14 @@ namespace ukm {
int64_t METRICS_EXPORT GetExponentialBucketMin(int64_t sample,
double bucket_spacing);
+// Calculates the linear bucket |sample| falls in and returns the lower
+// threshold of that bucket (i.e., rounding down to the nearest multiple of
+// |bucket_size|). Negative sample values will be rounded down as well (away
+// from zero). |bucket_size| is the size of each bucket, and must be a non-zero
+// positive integer.
+int64_t METRICS_EXPORT GetLinearBucketMin(int64_t sample, int32_t bucket_size);
+int64_t METRICS_EXPORT GetLinearBucketMin(double sample, int32_t bucket_size);
+
} // namespace ukm
#endif // SERVICES_METRICS_PUBLIC_CPP_METRICS_UTILS_H_
diff --git a/chromium/services/metrics/public/cpp/metrics_utils_unittest.cc b/chromium/services/metrics/public/cpp/metrics_utils_unittest.cc
new file mode 100644
index 00000000000..27cdca32d74
--- /dev/null
+++ b/chromium/services/metrics/public/cpp/metrics_utils_unittest.cc
@@ -0,0 +1,63 @@
+// Copyright 2018 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/metrics/public/cpp/metrics_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(MetricsUtilsTest, GetLinearBucketMin) {
+ struct {
+ int64_t expected_result;
+ int64_t sample;
+ int32_t bucket_size;
+ } int_test_cases[] = {
+ // Typical positive cases.
+ {35, 38, 5},
+ {50, 51, 50},
+ {50, 99, 50},
+ {20, 25, 10},
+ // Negative samples.
+ {-50, -45, 10},
+ {-50, -48, 10},
+ {-50, -41, 10},
+ {-42, -41, 2},
+ // Zero samples.
+ {0, 0, 1},
+ {0, 0, 10},
+ };
+
+ struct {
+ int64_t expected_result;
+ double sample;
+ int32_t bucket_size;
+ } double_test_cases[] = {
+ // Typical positive cases.
+ {35, 38.0, 5},
+ {50, 50.5, 50},
+ {50, 99.5, 50},
+ {20, 25.0, 10},
+ // Negative samples.
+ {-50, -45.0, 10},
+ {-42, -41.2, 2},
+ {-42, -40.8, 2},
+ // Test that a double close to the next bucker never rounds up.
+ {5, 9.95, 5},
+ };
+
+ // Test int64_t sample cases.
+ for (const auto& test : int_test_cases) {
+ EXPECT_EQ(test.expected_result,
+ ukm::GetLinearBucketMin(test.sample, test.bucket_size))
+ << "For sample: " << test.sample
+ << " with bucket_size: " << test.bucket_size;
+ }
+
+ // Test double sample cases.
+ for (const auto& test : double_test_cases) {
+ EXPECT_EQ(test.expected_result,
+ ukm::GetLinearBucketMin(test.sample, test.bucket_size))
+ << "For sample: " << test.sample
+ << " with bucket_size: " << test.bucket_size;
+ }
+}
diff --git a/chromium/services/metrics/public/cpp/mojo_ukm_recorder.cc b/chromium/services/metrics/public/cpp/mojo_ukm_recorder.cc
index d5ed3899da4..a2938f44a45 100644
--- a/chromium/services/metrics/public/cpp/mojo_ukm_recorder.cc
+++ b/chromium/services/metrics/public/cpp/mojo_ukm_recorder.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "services/metrics/public/interfaces/constants.mojom.h"
+#include "services/metrics/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace ukm {
diff --git a/chromium/services/metrics/public/cpp/mojo_ukm_recorder.h b/chromium/services/metrics/public/cpp/mojo_ukm_recorder.h
index 3616b3fdf94..c76c62d0882 100644
--- a/chromium/services/metrics/public/cpp/mojo_ukm_recorder.h
+++ b/chromium/services/metrics/public/cpp/mojo_ukm_recorder.h
@@ -10,7 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "services/metrics/public/cpp/metrics_export.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace service_manager {
class Connector;
diff --git a/chromium/services/metrics/public/cpp/ukm_entry_builder.cc b/chromium/services/metrics/public/cpp/ukm_entry_builder.cc
index 46f6d29587b..9ce744551e5 100644
--- a/chromium/services/metrics/public/cpp/ukm_entry_builder.cc
+++ b/chromium/services/metrics/public/cpp/ukm_entry_builder.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/metrics/metrics_hashes.h"
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace ukm {
diff --git a/chromium/services/metrics/public/cpp/ukm_entry_builder.h b/chromium/services/metrics/public/cpp/ukm_entry_builder.h
index 1e9695204b8..efcc3d85d7d 100644
--- a/chromium/services/metrics/public/cpp/ukm_entry_builder.h
+++ b/chromium/services/metrics/public/cpp/ukm_entry_builder.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "services/metrics/public/cpp/metrics_export.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace ukm {
diff --git a/chromium/services/metrics/public/cpp/ukm_entry_builder_base.cc b/chromium/services/metrics/public/cpp/ukm_entry_builder_base.cc
index 1e15bf33d98..f55450c405e 100644
--- a/chromium/services/metrics/public/cpp/ukm_entry_builder_base.cc
+++ b/chromium/services/metrics/public/cpp/ukm_entry_builder_base.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace ukm {
diff --git a/chromium/services/metrics/public/cpp/ukm_entry_builder_base.h b/chromium/services/metrics/public/cpp/ukm_entry_builder_base.h
index b602f7a250f..d2447fd32d7 100644
--- a/chromium/services/metrics/public/cpp/ukm_entry_builder_base.h
+++ b/chromium/services/metrics/public/cpp/ukm_entry_builder_base.h
@@ -10,7 +10,7 @@
#include "base/macros.h"
#include "services/metrics/public/cpp/metrics_export.h"
#include "services/metrics/public/cpp/ukm_recorder.h"
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace ukm {
diff --git a/chromium/services/metrics/public/cpp/ukm_recorder.h b/chromium/services/metrics/public/cpp/ukm_recorder.h
index 093d9f8ee50..7e12fd6458e 100644
--- a/chromium/services/metrics/public/cpp/ukm_recorder.h
+++ b/chromium/services/metrics/public/cpp/ukm_recorder.h
@@ -14,7 +14,7 @@
#include "services/metrics/public/cpp/metrics_export.h"
#include "services/metrics/public/cpp/ukm_entry_builder.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
#include "url/gurl.h"
class DocumentWritePageLoadMetricsObserver;
@@ -40,6 +40,7 @@ class BasePredictor;
namespace blink {
class AutoplayUmaHelper;
class Document;
+class UkmTimeAggregator;
}
namespace cc {
@@ -50,9 +51,12 @@ namespace content {
class CrossSiteDocumentResourceHandler;
class WebContentsImpl;
class PluginServiceImpl;
-class DownloadUkmHelper;
} // namespace content
+namespace download {
+class DownloadUkmHelper;
+}
+
namespace password_manager {
class PasswordManagerMetricsRecorder;
} // namespace password_manager
@@ -90,8 +94,9 @@ class UkmEntryBuilder;
class TestRecordingHelper;
namespace internal {
-class UkmEntryBuilderBase;
class SourceUrlRecorderWebContentsObserver;
+class SourceUrlRecorderWebStateObserver;
+class UkmEntryBuilderBase;
}
// This feature controls whether UkmService should be created.
@@ -131,12 +136,14 @@ class METRICS_EXPORT UkmRecorder {
friend autofill::FormStructure;
friend blink::AutoplayUmaHelper;
friend blink::Document;
+ friend blink::UkmTimeAggregator;
friend cc::UkmManager;
friend content::CrossSiteDocumentResourceHandler;
- friend content::DownloadUkmHelper;
friend content::PluginServiceImpl;
friend content::WebContentsImpl;
+ friend download::DownloadUkmHelper;
friend internal::SourceUrlRecorderWebContentsObserver;
+ friend internal::SourceUrlRecorderWebStateObserver;
friend internal::UkmEntryBuilderBase;
friend media::MediaMetricsProvider;
friend media::VideoDecodePerfHistory;
diff --git a/chromium/services/metrics/public/interfaces/BUILD.gn b/chromium/services/metrics/public/mojom/BUILD.gn
index 013e94008e3..bb8e4d890e1 100644
--- a/chromium/services/metrics/public/interfaces/BUILD.gn
+++ b/chromium/services/metrics/public/mojom/BUILD.gn
@@ -4,13 +4,13 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"constants.mojom",
"ukm_interface.mojom",
]
public_deps = [
- "//url/mojo:url_mojom_gurl",
+ "//url/mojom:url_mojom_gurl",
]
}
diff --git a/chromium/services/metrics/public/interfaces/OWNERS b/chromium/services/metrics/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/metrics/public/interfaces/OWNERS
+++ b/chromium/services/metrics/public/mojom/OWNERS
diff --git a/chromium/services/metrics/public/interfaces/constants.mojom b/chromium/services/metrics/public/mojom/constants.mojom
index 73925147cf8..73925147cf8 100644
--- a/chromium/services/metrics/public/interfaces/constants.mojom
+++ b/chromium/services/metrics/public/mojom/constants.mojom
diff --git a/chromium/services/metrics/public/interfaces/ukm_interface.mojom b/chromium/services/metrics/public/mojom/ukm_interface.mojom
index 4daeb8391fd..7a1b4fcd8fa 100644
--- a/chromium/services/metrics/public/interfaces/ukm_interface.mojom
+++ b/chromium/services/metrics/public/mojom/ukm_interface.mojom
@@ -4,7 +4,7 @@
module ukm.mojom;
-import "url/mojo/url.mojom";
+import "url/mojom/url.mojom";
struct UkmMetric {
uint64 metric_hash;
diff --git a/chromium/services/metrics/ukm_recorder_interface.h b/chromium/services/metrics/ukm_recorder_interface.h
index e70ca41f5ff..5c07b239fb4 100644
--- a/chromium/services/metrics/ukm_recorder_interface.h
+++ b/chromium/services/metrics/ukm_recorder_interface.h
@@ -5,7 +5,7 @@
#ifndef COMPONENTS_UKM_UKM_INTERFACE_H_
#define COMPONENTS_UKM_UKM_INTERFACE_H_
-#include "services/metrics/public/interfaces/ukm_interface.mojom.h"
+#include "services/metrics/public/mojom/ukm_interface.mojom.h"
namespace ukm {
class UkmRecorder;
diff --git a/chromium/services/network/BUILD.gn b/chromium/services/network/BUILD.gn
index 1b489163af4..1f99d8ce753 100644
--- a/chromium/services/network/BUILD.gn
+++ b/chromium/services/network/BUILD.gn
@@ -3,22 +3,112 @@
# found in the LICENSE file.
import("//mojo/public/tools/bindings/mojom.gni")
+import("//services/catalog/public/tools/catalog.gni")
+import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+import("//services/service_manager/public/tools/test/service_test.gni")
-static_library("network_service") {
+component("network_service") {
sources = [
"cookie_manager.cc",
"cookie_manager.h",
+ "cors/preflight_controller.cc",
+ "cors/preflight_controller.h",
+ "data_pipe_element_reader.cc",
+ "data_pipe_element_reader.h",
+ "http_server_properties_pref_delegate.cc",
+ "http_server_properties_pref_delegate.h",
+ "ignore_errors_cert_verifier.cc",
+ "ignore_errors_cert_verifier.h",
+ "keepalive_statistics_recorder.cc",
+ "keepalive_statistics_recorder.h",
+ "loader_util.cc",
+ "loader_util.h",
+ "network_change_manager.cc",
+ "network_change_manager.h",
+ "network_context.cc",
+ "network_context.h",
+ "network_sandbox_hook_linux.cc",
+ "network_sandbox_hook_linux.h",
+ "network_service.cc",
+ "network_service.h",
"proxy_config_service_mojo.cc",
"proxy_config_service_mojo.h",
+ "proxy_resolving_client_socket.cc",
+ "proxy_resolving_client_socket.h",
+ "proxy_resolving_client_socket_factory.cc",
+ "proxy_resolving_client_socket_factory.h",
+ "resource_scheduler.cc",
+ "resource_scheduler.h",
+ "resource_scheduler_client.cc",
+ "resource_scheduler_client.h",
+ "restricted_cookie_manager.cc",
+ "restricted_cookie_manager.h",
+ "throttling/network_conditions.cc",
+ "throttling/network_conditions.h",
+ "throttling/throttling_controller.cc",
+ "throttling/throttling_controller.h",
+ "throttling/throttling_network_interceptor.cc",
+ "throttling/throttling_network_interceptor.h",
+ "throttling/throttling_network_transaction.cc",
+ "throttling/throttling_network_transaction.h",
+ "throttling/throttling_network_transaction_factory.cc",
+ "throttling/throttling_network_transaction_factory.h",
+ "throttling/throttling_upload_data_stream.cc",
+ "throttling/throttling_upload_data_stream.h",
+ "udp_socket.cc",
+ "udp_socket.h",
+ "udp_socket_factory.cc",
+ "udp_socket_factory.h",
+ "upload_progress_tracker.cc",
+ "upload_progress_tracker.h",
+ "url_loader.cc",
+ "url_loader.h",
+ "url_loader_factory.cc",
+ "url_loader_factory.h",
+ "url_request_context_builder_mojo.cc",
+ "url_request_context_builder_mojo.h",
+ "url_request_context_owner.cc",
+ "url_request_context_owner.h",
]
deps = [
"//base",
+ "//components/cookie_config",
+ "//components/network_session_configurator/browser",
+ "//components/network_session_configurator/common",
+ "//components/prefs",
+ "//mojo/common:common_base",
"//mojo/public/cpp/bindings",
"//net",
- "//services/network/public/interfaces",
+ "//net:extras",
+ "//services/network/public/cpp",
+ "//services/network/public/mojom",
+ "//services/service_manager/public/cpp",
+ "//services/service_manager/public/mojom",
"//url",
]
+
+ if (is_linux) {
+ deps += [
+ "//sandbox/linux:sandbox_services",
+ "//services/service_manager/sandbox:sandbox",
+ ]
+ }
+
+ # TODO(sdefresne): This depends on net's enable_net_mojo getting turned on for
+ # iOS, which depends on net_with_v8 as well. http://crbug.com/803149
+ if (!is_ios) {
+ sources += [
+ "proxy_resolver_factory_mojo.cc",
+ "proxy_resolver_factory_mojo.h",
+ "proxy_service_mojo.cc",
+ "proxy_service_mojo.h",
+ ]
+ deps += [ "//net:net_browser_services" ]
+ }
+
+ defines = [ "IS_NETWORK_SERVICE_IMPL" ]
}
source_set("tests") {
@@ -26,32 +116,84 @@ source_set("tests") {
sources = [
"cookie_manager_unittest.cc",
+ "cors/cors_url_loader_unittest.cc",
+ "cors/preflight_controller_unittest.cc",
+ "data_pipe_element_reader_unittest.cc",
+ "ignore_errors_cert_verifier_unittest.cc",
+ "keepalive_statistics_recorder_unittest.cc",
+ "network_change_manager_unittest.cc",
+ "network_context_unittest.cc",
+ "network_service_unittest.cc",
"proxy_config_service_mojo_unittest.cc",
+ "proxy_resolving_client_socket_unittest.cc",
+ "resource_scheduler_unittest.cc",
+ "restricted_cookie_manager_unittest.cc",
+ "test/test_url_loader_factory_unittest.cc",
+ "throttling/throttling_controller_unittest.cc",
+ "udp_socket_factory_unittest.cc",
+ "udp_socket_unittest.cc",
+ "upload_progress_tracker_unittest.cc",
+ "url_loader_unittest.cc",
]
+ if (!is_ios) {
+ sources += [ "proxy_resolver_factory_mojo_unittest.cc" ]
+ }
+
deps = [
+ ":network_service",
+ ":test_support",
"//base",
+ "//components/network_session_configurator/browser",
+ "//mojo/common:common_base",
"//mojo/public/cpp/bindings",
"//net",
"//net:test_support",
- "//services/network:network_service",
- "//services/network/public/interfaces",
+ "//services/network/public/cpp",
+ "//services/network/public/mojom",
+ "//services/service_manager/public/cpp",
+ "//services/service_manager/public/cpp:service_test_support",
"//testing/gtest",
]
}
-static_library("test_support") {
+source_set("test_support") {
testonly = true
sources = [
"test/test_data_pipe_getter.cc",
+ "test/test_data_pipe_getter.h",
+ "test/test_url_loader_client.cc",
+ "test/test_url_loader_client.h",
+ "test/test_url_loader_factory.cc",
+ "test/test_url_loader_factory.h",
+ "udp_socket_test_util.cc",
+ "udp_socket_test_util.h",
]
deps = [
"//base",
"//mojo/public/cpp/bindings",
+ "//net",
+ "//net:test_support",
"//services/network:network_service",
- "//services/network/public/interfaces",
+ "//services/network/public/mojom",
"//testing/gtest",
]
}
+
+service_manifest("manifest") {
+ name = "network"
+ source = "manifest.json"
+}
+
+service_manifest("unittest_manifest") {
+ name = "network_unittests"
+ source = "test/service_unittest_manifest.json"
+ packaged_services = [ ":manifest" ]
+}
+
+catalog("tests_catalog") {
+ testonly = true
+ embedded_services = [ ":unittest_manifest" ]
+}
diff --git a/chromium/services/network/DEPS b/chromium/services/network/DEPS
index 88c57e96d95..361831bc726 100644
--- a/chromium/services/network/DEPS
+++ b/chromium/services/network/DEPS
@@ -1,4 +1,15 @@
include_rules = [
+ "+components/cookie_config",
+ "+components/network_session_configurator",
+ # Prefs are used to create an independent file with a persisted key:value
+ # store for networking-related data (Like which servers support QUIC), rather
+ # than to store user preferences.
+ "+components/prefs",
+ "+crypto",
"+ipc",
"+net",
+ "+sandbox",
+ "+services/proxy_resolver/public/mojom",
+ "+services/service_manager/public",
+ "+services/service_manager/sandbox",
]
diff --git a/chromium/services/network/OWNERS b/chromium/services/network/OWNERS
index 716b2b1df40..b5b4f44ca23 100644
--- a/chromium/services/network/OWNERS
+++ b/chromium/services/network/OWNERS
@@ -1 +1,12 @@
-file://content/network/OWNERS
+jam@chromium.org
+kinuko@chromium.org
+mmenke@chromium.org
+rdsmith@chromium.org
+reillyg@chromium.org
+scottmg@chromium.org
+tsepez@chromium.org
+xunjieli@chromium.org
+yhirano@chromium.org
+
+per-file manifest.json=set noparent
+per-file manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/network/PRESUBMIT.py b/chromium/services/network/PRESUBMIT.py
new file mode 100644
index 00000000000..59f334f9748
--- /dev/null
+++ b/chromium/services/network/PRESUBMIT.py
@@ -0,0 +1,22 @@
+# 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.
+"""Presubmit script for //services/network.
+
+See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+def PostUploadHook(cl, change, output_api):
+ """git cl upload will call this hook after the issue is created/modified.
+
+ This hook adds extra try bots to the CL description in order to run network
+ service tests in addition to CQ try bots.
+ """
+ return output_api.EnsureCQIncludeTrybotsAreAdded(
+ cl,
+ [
+ 'master.tryserver.chromium.linux:linux_mojo'
+ ],
+ 'Automatically added network service trybots to run tests on CQ.')
+
diff --git a/chromium/services/network/cookie_manager.cc b/chromium/services/network/cookie_manager.cc
index 0012abbc755..d486ea14226 100644
--- a/chromium/services/network/cookie_manager.cc
+++ b/chromium/services/network/cookie_manager.cc
@@ -121,25 +121,21 @@ class PredicateWrapper {
};
network::mojom::CookieChangeCause ChangeCauseTranslation(
- net::CookieStore::ChangeCause net_cause) {
+ net::CookieChangeCause net_cause) {
switch (net_cause) {
- case net::CookieStore::ChangeCause::INSERTED:
+ case net::CookieChangeCause::INSERTED:
return network::mojom::CookieChangeCause::INSERTED;
- case net::CookieStore::ChangeCause::EXPLICIT:
- case net::CookieStore::ChangeCause::EXPLICIT_DELETE_BETWEEN:
- case net::CookieStore::ChangeCause::EXPLICIT_DELETE_PREDICATE:
- case net::CookieStore::ChangeCause::EXPLICIT_DELETE_SINGLE:
- case net::CookieStore::ChangeCause::EXPLICIT_DELETE_CANONICAL:
+ case net::CookieChangeCause::EXPLICIT:
return network::mojom::CookieChangeCause::EXPLICIT;
- case net::CookieStore::ChangeCause::UNKNOWN_DELETION:
+ case net::CookieChangeCause::UNKNOWN_DELETION:
return network::mojom::CookieChangeCause::UNKNOWN_DELETION;
- case net::CookieStore::ChangeCause::OVERWRITE:
+ case net::CookieChangeCause::OVERWRITE:
return network::mojom::CookieChangeCause::OVERWRITE;
- case net::CookieStore::ChangeCause::EXPIRED:
+ case net::CookieChangeCause::EXPIRED:
return network::mojom::CookieChangeCause::EXPIRED;
- case net::CookieStore::ChangeCause::EVICTED:
+ case net::CookieChangeCause::EVICTED:
return network::mojom::CookieChangeCause::EVICTED;
- case net::CookieStore::ChangeCause::EXPIRED_OVERWRITE:
+ case net::CookieChangeCause::EXPIRED_OVERWRITE:
return network::mojom::CookieChangeCause::EXPIRED_OVERWRITE;
}
NOTREACHED();
@@ -148,9 +144,15 @@ network::mojom::CookieChangeCause ChangeCauseTranslation(
} // namespace
-CookieManager::NotificationRegistration::NotificationRegistration() {}
+CookieManager::ListenerRegistration::ListenerRegistration() {}
-CookieManager::NotificationRegistration::~NotificationRegistration() {}
+CookieManager::ListenerRegistration::~ListenerRegistration() {}
+
+void CookieManager::ListenerRegistration::DispatchCookieStoreChange(
+ const net::CanonicalCookie& cookie,
+ net::CookieChangeCause cause) {
+ listener->OnCookieChange(cookie, ChangeCauseTranslation(cause));
+}
CookieManager::CookieManager(net::CookieStore* cookie_store)
: cookie_store_(cookie_store) {}
@@ -201,98 +203,76 @@ void CookieManager::DeleteCookies(
std::move(callback));
}
-void CookieManager::RequestNotification(
+void CookieManager::AddCookieChangeListener(
const GURL& url,
const std::string& name,
- network::mojom::CookieChangeNotificationPtr notification_pointer) {
- std::unique_ptr<NotificationRegistration> notification_registration(
- std::make_unique<NotificationRegistration>());
- notification_registration->notification_pointer =
- std::move(notification_pointer);
-
- notification_registration->subscription = cookie_store_->AddCallbackForCookie(
- url, name,
- base::BindRepeating(
- &CookieManager::CookieChanged,
- // base::Unretained is safe as destruction of the
- // CookieManager will also destroy the
- // notifications_registered list (which this object will be
- // inserted into, below), which will destroy the
- // CookieChangedSubscription, unregistering the callback.
- base::Unretained(this),
- // base::Unretained is safe as destruction of the
- // NotificationRegistration will also destroy the
- // CookieChangedSubscription, unregistering the callback.
- base::Unretained(notification_registration.get())));
-
- notification_registration->notification_pointer.set_connection_error_handler(
- base::BindOnce(&CookieManager::NotificationPipeBroken,
+ network::mojom::CookieChangeListenerPtr listener) {
+ auto listener_registration = std::make_unique<ListenerRegistration>();
+ listener_registration->listener = std::move(listener);
+
+ listener_registration->subscription =
+ cookie_store_->GetChangeDispatcher().AddCallbackForCookie(
+ url, name,
+ base::BindRepeating(
+ &CookieManager::ListenerRegistration::DispatchCookieStoreChange,
+ // base::Unretained is safe as destruction of the
+ // ListenerRegistration will also destroy the
+ // CookieChangedSubscription, unregistering the callback.
+ base::Unretained(listener_registration.get())));
+
+ listener_registration->listener.set_connection_error_handler(
+ base::BindOnce(&CookieManager::RemoveChangeListener,
// base::Unretained is safe as destruction of the
// CookieManager will also destroy the
// notifications_registered list (which this object will be
// inserted into, below), which will destroy the
- // notification_pointer, rendering this callback moot.
+ // listener, rendering this callback moot.
base::Unretained(this),
// base::Unretained is safe as destruction of the
- // NotificationRegistration will also destroy the
+ // ListenerRegistration will also destroy the
// CookieChangedSubscription, unregistering the callback.
- base::Unretained(notification_registration.get())));
+ base::Unretained(listener_registration.get())));
- notifications_registered_.push_back(std::move(notification_registration));
+ listener_registrations_.push_back(std::move(listener_registration));
}
-void CookieManager::RequestGlobalNotifications(
- network::mojom::CookieChangeNotificationPtr notification_pointer) {
- std::unique_ptr<NotificationRegistration> notification_registration(
- std::make_unique<NotificationRegistration>());
- notification_registration->notification_pointer =
- std::move(notification_pointer);
-
- notification_registration->subscription =
- cookie_store_->AddCallbackForAllChanges(base::BindRepeating(
- &CookieManager::CookieChanged,
- // base::Unretained is safe as destruction of the
- // CookieManager will also destroy the
- // notifications_registered list (which this object will be
- // inserted into, below), which will destroy the
- // CookieChangedSubscription, unregistering the callback.
- base::Unretained(this),
- // base::Unretained is safe as destruction of the
- // NotificationRegistration will also destroy the
- // CookieChangedSubscription, unregistering the callback.
- base::Unretained(notification_registration.get())));
-
- notification_registration->notification_pointer.set_connection_error_handler(
- base::BindOnce(&CookieManager::NotificationPipeBroken,
+void CookieManager::AddGlobalChangeListener(
+ network::mojom::CookieChangeListenerPtr listener) {
+ auto listener_registration = std::make_unique<ListenerRegistration>();
+ listener_registration->listener = std::move(listener);
+
+ listener_registration->subscription =
+ cookie_store_->GetChangeDispatcher().AddCallbackForAllChanges(
+ base::BindRepeating(
+ &CookieManager::ListenerRegistration::DispatchCookieStoreChange,
+ // base::Unretained is safe as destruction of the
+ // ListenerRegistration will also destroy the
+ // CookieChangedSubscription, unregistering the callback.
+ base::Unretained(listener_registration.get())));
+
+ listener_registration->listener.set_connection_error_handler(
+ base::BindOnce(&CookieManager::RemoveChangeListener,
// base::Unretained is safe as destruction of the
// CookieManager will also destroy the
// notifications_registered list (which this object will be
// inserted into, below), which will destroy the
- // notification_pointer, rendering this callback moot.
+ // listener, rendering this callback moot.
base::Unretained(this),
// base::Unretained is safe as destruction of the
- // NotificationRegistration will also destroy the
+ // ListenerRegistration will also destroy the
// CookieChangedSubscription, unregistering the callback.
- base::Unretained(notification_registration.get())));
+ base::Unretained(listener_registration.get())));
- notifications_registered_.push_back(std::move(notification_registration));
+ listener_registrations_.push_back(std::move(listener_registration));
}
-void CookieManager::CookieChanged(NotificationRegistration* registration,
- const net::CanonicalCookie& cookie,
- net::CookieStore::ChangeCause cause) {
- registration->notification_pointer->OnCookieChanged(
- cookie, ChangeCauseTranslation(cause));
-}
-
-void CookieManager::NotificationPipeBroken(
- NotificationRegistration* registration) {
- for (auto it = notifications_registered_.begin();
- it != notifications_registered_.end(); ++it) {
+void CookieManager::RemoveChangeListener(ListenerRegistration* registration) {
+ for (auto it = listener_registrations_.begin();
+ it != listener_registrations_.end(); ++it) {
if (it->get() == registration) {
// It isn't expected this will be a common enough operation for
// the performance of std::vector::erase() to matter.
- notifications_registered_.erase(it);
+ listener_registrations_.erase(it);
return;
}
}
@@ -305,4 +285,9 @@ void CookieManager::CloneInterface(
AddRequest(std::move(new_interface));
}
+void CookieManager::FlushCookieStore(FlushCookieStoreCallback callback) {
+ // Flushes the backing store (if any) to disk.
+ cookie_store_->FlushStore(std::move(callback));
+}
+
} // namespace network
diff --git a/chromium/services/network/cookie_manager.h b/chromium/services/network/cookie_manager.h
index f2c0139d51c..4054689c9ca 100644
--- a/chromium/services/network/cookie_manager.h
+++ b/chromium/services/network/cookie_manager.h
@@ -9,10 +9,12 @@
#include <string>
#include <vector>
+#include "base/component_export.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "net/cookies/cookie_change_dispatcher.h"
#include "net/cookies/cookie_store.h"
-#include "services/network/public/interfaces/cookie_manager.mojom.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
class GURL;
@@ -23,7 +25,8 @@ namespace network {
// This is an IO thread object; all methods on this object must be called on
// the IO thread. Note that this does not restrict the locations from which
// mojo messages may be sent to the object.
-class CookieManager : public network::mojom::CookieManager {
+class COMPONENT_EXPORT(NETWORK_SERVICE) CookieManager
+ : public network::mojom::CookieManager {
public:
// Construct a CookieService that can serve mojo requests for the underlying
// cookie store. |*cookie_store| must outlive this object.
@@ -49,46 +52,47 @@ class CookieManager : public network::mojom::CookieManager {
SetCanonicalCookieCallback callback) override;
void DeleteCookies(network::mojom::CookieDeletionFilterPtr filter,
DeleteCookiesCallback callback) override;
- void RequestNotification(const GURL& url,
- const std::string& name,
- network::mojom::CookieChangeNotificationPtr
- notification_pointer) override;
- void RequestGlobalNotifications(network::mojom::CookieChangeNotificationPtr
- notification_pointer) override;
+ void AddCookieChangeListener(
+ const GURL& url,
+ const std::string& name,
+ network::mojom::CookieChangeListenerPtr listener) override;
+ void AddGlobalChangeListener(
+ network::mojom::CookieChangeListenerPtr listener) override;
void CloneInterface(
network::mojom::CookieManagerRequest new_interface) override;
- uint32_t GetClientsBoundForTesting() const { return bindings_.size(); }
- uint32_t GetNotificationsBoundForTesting() const {
- return notifications_registered_.size();
+ size_t GetClientsBoundForTesting() const { return bindings_.size(); }
+ size_t GetListenersRegisteredForTesting() const {
+ return listener_registrations_.size();
}
+ void FlushCookieStore(FlushCookieStoreCallback callback) override;
+
private:
- struct NotificationRegistration {
- NotificationRegistration();
- ~NotificationRegistration();
+ // State associated with a CookieChangeListener.
+ struct ListenerRegistration {
+ ListenerRegistration();
+ ~ListenerRegistration();
+
+ // Translates a CookieStore change callback to a CookieChangeListener call.
+ void DispatchCookieStoreChange(const net::CanonicalCookie& cookie,
+ net::CookieChangeCause cause);
// Owns the callback registration in the store.
- std::unique_ptr<net::CookieStore::CookieChangedSubscription> subscription;
+ std::unique_ptr<net::CookieChangeSubscription> subscription;
- // Pointer on which to send notifications.
- network::mojom::CookieChangeNotificationPtr notification_pointer;
+ // The observer receiving change notifications.
+ network::mojom::CookieChangeListenerPtr listener;
- DISALLOW_COPY_AND_ASSIGN(NotificationRegistration);
+ DISALLOW_COPY_AND_ASSIGN(ListenerRegistration);
};
- // Used to hook callbacks
- void CookieChanged(NotificationRegistration* registration,
- const net::CanonicalCookie& cookie,
- net::CookieStore::ChangeCause cause);
-
- // Handles connection errors on notification pipes.
- void NotificationPipeBroken(NotificationRegistration* registration);
+ // Handles connection errors on change listener pipes.
+ void RemoveChangeListener(ListenerRegistration* registration);
net::CookieStore* const cookie_store_;
mojo::BindingSet<network::mojom::CookieManager> bindings_;
- std::vector<std::unique_ptr<NotificationRegistration>>
- notifications_registered_;
+ std::vector<std::unique_ptr<ListenerRegistration>> listener_registrations_;
DISALLOW_COPY_AND_ASSIGN(CookieManager);
};
diff --git a/chromium/services/network/cookie_manager_unittest.cc b/chromium/services/network/cookie_manager_unittest.cc
index 3f4d1664fd6..ffc49de606a 100644
--- a/chromium/services/network/cookie_manager_unittest.cc
+++ b/chromium/services/network/cookie_manager_unittest.cc
@@ -14,7 +14,7 @@
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/cookies/cookie_store_test_callbacks.h"
-#include "services/network/public/interfaces/cookie_manager.mojom.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
// Test infrastructure outline:
@@ -22,9 +22,8 @@
// * SynchronousMojoCookieWrapper: Takes a network::mojom::CookieManager at
// construction; exposes synchronous interfaces that wrap the
// network::mojom::CookieManager async interfaces to make testing easier.
-// * CookieChangeNotification: Test class implementing
-// the CookieChangeNotification interface and recording
-// incoming messages on it.
+// * CookieChangeListener: Test class implementing the CookieChangeListener
+// interface and recording incoming messages on it.
// * CookieManagerTest: Test base class. Automatically sets up
// a cookie store, a cookie service wrapping it, a mojo pipe
// connected to the server, and the cookie service implemented
@@ -97,8 +96,8 @@ class SynchronousCookieManager {
return num_deleted;
}
- // No need to wrap RequestNotification and CloneInterface, since their use
- // is pure async.
+ // No need to wrap Add*Listener and CloneInterface, since their use
+ // is purely async.
private:
static void GetCookiesCallback(
base::RunLoop* run_loop,
@@ -122,14 +121,6 @@ class SynchronousCookieManager {
run_loop->Quit();
}
- static void RequestNotificationCallback(
- base::RunLoop* run_loop,
- network::mojom::CookieChangeNotificationRequest* request_out,
- network::mojom::CookieChangeNotificationRequest request) {
- *request_out = std::move(request);
- run_loop->Quit();
- }
-
network::mojom::CookieManager* cookie_service_;
DISALLOW_COPY_AND_ASSIGN(SynchronousCookieManager);
@@ -1457,27 +1448,27 @@ TEST_F(CookieManagerTest, DeleteByAll) {
EXPECT_EQ("A7", cookies[5].Name());
}
+namespace {
+
// Receives and records notifications from the network::mojom::CookieManager.
-class CookieChangeNotification
- : public network::mojom::CookieChangeNotification {
+class CookieChangeListener : public network::mojom::CookieChangeListener {
public:
- struct Notification {
- Notification(const net::CanonicalCookie& cookie_in,
- network::mojom::CookieChangeCause cause_in) {
- cookie = cookie_in;
- cause = cause_in;
- }
+ // Records a cookie change received from CookieManager.
+ struct Change {
+ Change(const net::CanonicalCookie& cookie,
+ network::mojom::CookieChangeCause cause)
+ : cookie(cookie), cause(cause) {}
net::CanonicalCookie cookie;
network::mojom::CookieChangeCause cause;
};
- CookieChangeNotification(
- network::mojom::CookieChangeNotificationRequest request)
+ CookieChangeListener(network::mojom::CookieChangeListenerRequest request)
: run_loop_(nullptr), binding_(this, std::move(request)) {}
- void WaitForSomeNotification() {
- if (!notifications_.empty())
+ // Blocks until the listener observes a cookie change.
+ void WaitForChange() {
+ if (!observed_changes_.empty())
return;
base::RunLoop loop;
run_loop_ = &loop;
@@ -1485,141 +1476,134 @@ class CookieChangeNotification
run_loop_ = nullptr;
}
- // Adds existing notifications to passed in vector.
- void GetCurrentNotifications(std::vector<Notification>* notifications) {
- notifications->insert(notifications->end(), notifications_.begin(),
- notifications_.end());
- notifications_.clear();
+ void ClearObservedChanges() { observed_changes_.clear(); }
+
+ const std::vector<Change>& observed_changes() const {
+ return observed_changes_;
}
- // network::mojom::CookieChangesNotification
- void OnCookieChanged(const net::CanonicalCookie& cookie,
- network::mojom::CookieChangeCause cause) override {
- notifications_.push_back(Notification(cookie, cause));
+ // network::mojom::CookieChangeListener
+ void OnCookieChange(const net::CanonicalCookie& cookie,
+ network::mojom::CookieChangeCause cause) override {
+ observed_changes_.push_back(Change(cookie, cause));
if (run_loop_)
run_loop_->Quit();
}
private:
- std::vector<Notification> notifications_;
+ std::vector<Change> observed_changes_;
// Loop to signal on receiving a notification if not null.
base::RunLoop* run_loop_;
- mojo::Binding<network::mojom::CookieChangeNotification> binding_;
+ mojo::Binding<network::mojom::CookieChangeListener> binding_;
};
-TEST_F(CookieManagerTest, Notification) {
- GURL notification_url("http://www.testing.com/pathele");
- std::string notification_domain("testing.com");
- std::string notification_name("Cookie_Name");
- network::mojom::CookieChangeNotificationPtr ptr;
- network::mojom::CookieChangeNotificationRequest request(
- mojo::MakeRequest(&ptr));
+} // anonymous namespace
+
+TEST_F(CookieManagerTest, AddCookieChangeListener) {
+ const GURL listener_url("http://www.testing.com/pathele");
+ const std::string listener_url_host("www.testing.com");
+ const std::string listener_url_domain("testing.com");
+ const std::string listener_cookie_name("Cookie_Name");
+ ASSERT_EQ(listener_url.host(), listener_url_host);
+
+ network::mojom::CookieChangeListenerPtr listener_ptr;
+ network::mojom::CookieChangeListenerRequest request(
+ mojo::MakeRequest(&listener_ptr));
- CookieChangeNotification notification(std::move(request));
+ CookieChangeListener listener(std::move(request));
- cookie_service_client()->RequestNotification(
- notification_url, notification_name, std::move(ptr));
+ cookie_service_client()->AddCookieChangeListener(
+ listener_url, listener_cookie_name, std::move(listener_ptr));
- std::vector<CookieChangeNotification::Notification> notifications;
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(0u, notifications.size());
- notifications.clear();
+ EXPECT_EQ(0u, listener.observed_changes().size());
// Set a cookie that doesn't match the above notification request in name
// and confirm it doesn't produce a notification.
service_wrapper()->SetCanonicalCookie(
net::CanonicalCookie(
- "DifferentName", "val", notification_url.host(), "/", base::Time(),
+ "DifferentName", "val", listener_url_host, "/", base::Time(),
base::Time(), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_MEDIUM),
true, true);
base::RunLoop().RunUntilIdle();
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(0u, notifications.size());
- notifications.clear();
+ EXPECT_EQ(0u, listener.observed_changes().size());
// Set a cookie that doesn't match the above notification request in url
// and confirm it doesn't produce a notification.
service_wrapper()->SetCanonicalCookie(
net::CanonicalCookie(
- notification_name, "val", "www.other.host", "/", base::Time(),
+ listener_cookie_name, "val", "www.other.host", "/", base::Time(),
base::Time(), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_MEDIUM),
true, true);
base::RunLoop().RunUntilIdle();
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(0u, notifications.size());
- notifications.clear();
+ EXPECT_EQ(0u, listener.observed_changes().size());
// Insert a cookie that does match.
service_wrapper()->SetCanonicalCookie(
net::CanonicalCookie(
- notification_name, "val", notification_url.host(), "/", base::Time(),
+ listener_cookie_name, "val", listener_url_host, "/", base::Time(),
base::Time(), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_MEDIUM),
true, true);
// Expect asynchrony
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(0u, notifications.size());
- notifications.clear();
-
- // Expect notification
- notification.WaitForSomeNotification();
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(1u, notifications.size());
- EXPECT_EQ(notification_name, notifications[0].cookie.Name());
- EXPECT_EQ(notification_url.host(), notifications[0].cookie.Domain());
+ EXPECT_EQ(0u, listener.observed_changes().size());
+
+ // Expect to observe a cookie change.
+ listener.WaitForChange();
+ std::vector<CookieChangeListener::Change> observed_changes =
+ listener.observed_changes();
+ ASSERT_EQ(1u, observed_changes.size());
+ EXPECT_EQ(listener_cookie_name, observed_changes[0].cookie.Name());
+ EXPECT_EQ(listener_url_host, observed_changes[0].cookie.Domain());
EXPECT_EQ(network::mojom::CookieChangeCause::INSERTED,
- notifications[0].cause);
- notifications.clear();
+ observed_changes[0].cause);
+ listener.ClearObservedChanges();
// Delete all cookies matching the domain. This includes one for which
// a notification will be generated, and one for which a notification
// will not be generated.
network::mojom::CookieDeletionFilter filter;
filter.including_domains = std::vector<std::string>();
- filter.including_domains->push_back(notification_domain);
+ filter.including_domains->push_back(listener_url_domain);
// If this test fails, it may indicate a problem which will lead to
// no notifications being generated and the test hanging, so assert.
ASSERT_EQ(2u, service_wrapper()->DeleteCookies(filter));
// The notification may already have arrived, or it may arrive in the future.
- notification.WaitForSomeNotification();
- notification.GetCurrentNotifications(&notifications);
- ASSERT_EQ(1u, notifications.size());
- EXPECT_EQ(notification_name, notifications[0].cookie.Name());
- EXPECT_EQ(notification_url.host(), notifications[0].cookie.Domain());
+ listener.WaitForChange();
+ observed_changes = listener.observed_changes();
+ ASSERT_EQ(1u, observed_changes.size());
+ EXPECT_EQ(listener_cookie_name, observed_changes[0].cookie.Name());
+ EXPECT_EQ(listener_url_host, observed_changes[0].cookie.Domain());
EXPECT_EQ(network::mojom::CookieChangeCause::EXPLICIT,
- notifications[0].cause);
+ observed_changes[0].cause);
}
-TEST_F(CookieManagerTest, GlobalNotifications) {
+TEST_F(CookieManagerTest, AddGlobalChangeListener) {
const std::string kExampleHost = "www.example.com";
const std::string kThisHost = "www.this.com";
const std::string kThisETLDP1 = "this.com";
const std::string kThatHost = "www.that.com";
- network::mojom::CookieChangeNotificationPtr ptr;
- network::mojom::CookieChangeNotificationRequest request(
- mojo::MakeRequest(&ptr));
+ network::mojom::CookieChangeListenerPtr listener_ptr;
+ network::mojom::CookieChangeListenerRequest request(
+ mojo::MakeRequest(&listener_ptr));
- CookieChangeNotification notification(std::move(request));
+ CookieChangeListener listener(std::move(request));
- cookie_service_client()->RequestGlobalNotifications(std::move(ptr));
+ cookie_service_client()->AddGlobalChangeListener(std::move(listener_ptr));
- std::vector<CookieChangeNotification::Notification> notifications;
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(0u, notifications.size());
- notifications.clear();
+ EXPECT_EQ(0u, listener.observed_changes().size());
- // Confirm the right notification is seen from setting a cookie.
+ // Confirm the right change is observed after setting a cookie.
service_wrapper()->SetCanonicalCookie(
net::CanonicalCookie("Thing1", "val", kExampleHost, "/", base::Time(),
base::Time(), base::Time(), /*secure=*/false,
@@ -1629,20 +1613,19 @@ TEST_F(CookieManagerTest, GlobalNotifications) {
true, true);
// Expect asynchrony
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(0u, notifications.size());
- notifications.clear();
+ EXPECT_EQ(0u, listener.observed_changes().size());
base::RunLoop().RunUntilIdle();
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(1u, notifications.size());
- EXPECT_EQ("Thing1", notifications[0].cookie.Name());
- EXPECT_EQ("val", notifications[0].cookie.Value());
- EXPECT_EQ(kExampleHost, notifications[0].cookie.Domain());
- EXPECT_EQ("/", notifications[0].cookie.Path());
+ std::vector<CookieChangeListener::Change> observed_changes =
+ listener.observed_changes();
+ ASSERT_EQ(1u, observed_changes.size());
+ EXPECT_EQ("Thing1", observed_changes[0].cookie.Name());
+ EXPECT_EQ("val", observed_changes[0].cookie.Value());
+ EXPECT_EQ(kExampleHost, observed_changes[0].cookie.Domain());
+ EXPECT_EQ("/", observed_changes[0].cookie.Path());
EXPECT_EQ(network::mojom::CookieChangeCause::INSERTED,
- notifications[0].cause);
- notifications.clear();
+ observed_changes[0].cause);
+ listener.ClearObservedChanges();
// Set two cookies in a row on different domains and confirm they are both
// signalled.
@@ -1662,15 +1645,15 @@ TEST_F(CookieManagerTest, GlobalNotifications) {
true, true);
base::RunLoop().RunUntilIdle();
- notification.GetCurrentNotifications(&notifications);
- EXPECT_EQ(2u, notifications.size());
- EXPECT_EQ("Thing1", notifications[0].cookie.Name());
+ observed_changes = listener.observed_changes();
+ ASSERT_EQ(2u, observed_changes.size());
+ EXPECT_EQ("Thing1", observed_changes[0].cookie.Name());
EXPECT_EQ(network::mojom::CookieChangeCause::INSERTED,
- notifications[0].cause);
- EXPECT_EQ("Thing2", notifications[1].cookie.Name());
+ observed_changes[0].cause);
+ EXPECT_EQ("Thing2", observed_changes[1].cookie.Name());
EXPECT_EQ(network::mojom::CookieChangeCause::INSERTED,
- notifications[1].cause);
- notifications.clear();
+ observed_changes[1].cause);
+ listener.ClearObservedChanges();
// Delete cookies matching one domain; should produce one notification.
network::mojom::CookieDeletionFilter filter;
@@ -1681,79 +1664,69 @@ TEST_F(CookieManagerTest, GlobalNotifications) {
ASSERT_EQ(1u, service_wrapper()->DeleteCookies(filter));
// The notification may already have arrived, or it may arrive in the future.
- notification.WaitForSomeNotification();
- notification.GetCurrentNotifications(&notifications);
- ASSERT_EQ(1u, notifications.size());
- EXPECT_EQ("Thing1", notifications[0].cookie.Name());
- EXPECT_EQ(kThisHost, notifications[0].cookie.Domain());
+ listener.WaitForChange();
+ observed_changes = listener.observed_changes();
+ ASSERT_EQ(1u, observed_changes.size());
+ EXPECT_EQ("Thing1", observed_changes[0].cookie.Name());
+ EXPECT_EQ(kThisHost, observed_changes[0].cookie.Domain());
EXPECT_EQ(network::mojom::CookieChangeCause::EXPLICIT,
- notifications[0].cause);
+ observed_changes[0].cause);
}
// Confirm the service operates properly if a returned notification interface
// is destroyed.
-TEST_F(CookieManagerTest, NotificationRequestDestroyed) {
- // Create two identical notification interfaces.
- GURL notification_url("http://www.testing.com/pathele");
- std::string notification_name("Cookie_Name");
-
- network::mojom::CookieChangeNotificationPtr ptr1;
- network::mojom::CookieChangeNotificationRequest request1(
- mojo::MakeRequest(&ptr1));
- std::unique_ptr<CookieChangeNotification> notification1(
- std::make_unique<CookieChangeNotification>(std::move(request1)));
- cookie_service_client()->RequestNotification(
- notification_url, notification_name, std::move(ptr1));
-
- network::mojom::CookieChangeNotificationPtr ptr2;
- network::mojom::CookieChangeNotificationRequest request2(
- mojo::MakeRequest(&ptr2));
- std::unique_ptr<CookieChangeNotification> notification2(
- std::make_unique<CookieChangeNotification>(std::move(request2)));
- cookie_service_client()->RequestNotification(
- notification_url, notification_name, std::move(ptr2));
+TEST_F(CookieManagerTest, ListenerDestroyed) {
+ // Create two identical listeners.
+ const GURL listener_url("http://www.testing.com/pathele");
+ const std::string listener_url_host("www.testing.com");
+ ASSERT_EQ(listener_url.host(), listener_url_host);
+ const std::string listener_cookie_name("Cookie_Name");
+
+ network::mojom::CookieChangeListenerPtr listener1_ptr;
+ network::mojom::CookieChangeListenerRequest request1(
+ mojo::MakeRequest(&listener1_ptr));
+ auto listener1 = std::make_unique<CookieChangeListener>(std::move(request1));
+ cookie_service_client()->AddCookieChangeListener(
+ listener_url, listener_cookie_name, std::move(listener1_ptr));
+
+ network::mojom::CookieChangeListenerPtr listener2_ptr;
+ network::mojom::CookieChangeListenerRequest request2(
+ mojo::MakeRequest(&listener2_ptr));
+ auto listener2 = std::make_unique<CookieChangeListener>(std::move(request2));
+ cookie_service_client()->AddCookieChangeListener(
+ listener_url, listener_cookie_name, std::move(listener2_ptr));
// Add a cookie and receive a notification on both interfaces.
service_wrapper()->SetCanonicalCookie(
net::CanonicalCookie(
- notification_name, "val", notification_url.host(), "/", base::Time(),
+ listener_cookie_name, "val", listener_url_host, "/", base::Time(),
base::Time(), base::Time(), /*secure=*/false,
/*httponly=*/false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_MEDIUM),
true, true);
- std::vector<CookieChangeNotification::Notification> notifications;
- notification1->GetCurrentNotifications(&notifications);
- EXPECT_EQ(0u, notifications.size());
- notifications.clear();
+ EXPECT_EQ(0u, listener1->observed_changes().size());
+ EXPECT_EQ(0u, listener2->observed_changes().size());
- notification2->GetCurrentNotifications(&notifications);
- EXPECT_EQ(0u, notifications.size());
- notifications.clear();
+ listener1->WaitForChange();
+ EXPECT_EQ(1u, listener1->observed_changes().size());
+ listener1->ClearObservedChanges();
+ listener2->WaitForChange();
+ EXPECT_EQ(1u, listener2->observed_changes().size());
+ listener2->ClearObservedChanges();
+ EXPECT_EQ(2u, service()->GetListenersRegisteredForTesting());
- notification1->WaitForSomeNotification();
- notification1->GetCurrentNotifications(&notifications);
- EXPECT_EQ(1u, notifications.size());
- notifications.clear();
-
- notification2->WaitForSomeNotification();
- notification2->GetCurrentNotifications(&notifications);
- EXPECT_EQ(1u, notifications.size());
- notifications.clear();
- EXPECT_EQ(2u, service()->GetNotificationsBoundForTesting());
-
- // Destroy the first interface
- notification1.reset();
+ // Destroy the first listener.
+ listener1.reset();
// Confirm the second interface can still receive notifications.
network::mojom::CookieDeletionFilter filter;
EXPECT_EQ(1u, service_wrapper()->DeleteCookies(filter));
- notification2->WaitForSomeNotification();
- notification2->GetCurrentNotifications(&notifications);
- EXPECT_EQ(1u, notifications.size());
- notifications.clear();
- EXPECT_EQ(1u, service()->GetNotificationsBoundForTesting());
+ listener2->WaitForChange();
+ EXPECT_EQ(1u, listener2->observed_changes().size());
+
+ EXPECT_EQ(1u, service()->GetListenersRegisteredForTesting());
}
// Confirm we get a connection error notification if the service dies.
diff --git a/chromium/services/network/cors/cors_url_loader_unittest.cc b/chromium/services/network/cors/cors_url_loader_unittest.cc
new file mode 100644
index 00000000000..a88a2addd56
--- /dev/null
+++ b/chromium/services/network/cors/cors_url_loader_unittest.cc
@@ -0,0 +1,262 @@
+// 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 "services/network/public/cpp/cors/cors_url_loader.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
+#include "net/http/http_request_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/cpp/cors/cors_url_loader_factory.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/test/test_url_loader_client.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+namespace {
+
+class TestURLLoaderFactory : public mojom::URLLoaderFactory {
+ public:
+ TestURLLoaderFactory() : weak_factory_(this) {}
+ ~TestURLLoaderFactory() override = default;
+
+ base::WeakPtr<TestURLLoaderFactory> GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+ }
+
+ void NotifyClientOnReceiveResponse(const std::string& extra_header) {
+ DCHECK(client_ptr_);
+ ResourceResponseHead response;
+ response.headers = new net::HttpResponseHeaders(
+ "HTTP/1.1 200 OK\n"
+ "Content-Type: image/png\n");
+ if (!extra_header.empty())
+ response.headers->AddHeader(extra_header);
+
+ client_ptr_->OnReceiveResponse(response, base::nullopt /* ssl_info */,
+ nullptr /* downloaded_file */);
+ }
+
+ void NotifyClientOnComplete(int error_code) {
+ DCHECK(client_ptr_);
+ client_ptr_->OnComplete(URLLoaderCompletionStatus(error_code));
+ }
+
+ bool IsCreateLoaderAndStartCalled() { return !!client_ptr_; }
+
+ private:
+ // mojom::URLLoaderFactory implementation.
+ void CreateLoaderAndStart(mojom::URLLoaderRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override {
+ DCHECK(client);
+ client_ptr_ = std::move(client);
+ }
+
+ void Clone(mojom::URLLoaderFactoryRequest request) override { NOTREACHED(); }
+
+ mojom::URLLoaderClientPtr client_ptr_;
+
+ base::WeakPtrFactory<TestURLLoaderFactory> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestURLLoaderFactory);
+};
+
+class CORSURLLoaderTest : public testing::Test {
+ public:
+ CORSURLLoaderTest() {
+ std::unique_ptr<TestURLLoaderFactory> factory =
+ std::make_unique<TestURLLoaderFactory>();
+ test_url_loader_factory_ = factory->GetWeakPtr();
+ cors_url_loader_factory_ =
+ std::make_unique<CORSURLLoaderFactory>(std::move(factory));
+ }
+
+ protected:
+ // testing::Test implementation.
+ void SetUp() override {
+ feature_list_.InitAndEnableFeature(features::kOutOfBlinkCORS);
+ }
+
+ void CreateLoaderAndStart(const GURL& origin,
+ const GURL& url,
+ mojom::FetchRequestMode fetch_request_mode) {
+ ResourceRequest request;
+ request.fetch_request_mode = fetch_request_mode;
+ request.method = net::HttpRequestHeaders::kGetMethod;
+ request.url = url;
+ request.request_initiator = url::Origin::Create(origin);
+
+ cors_url_loader_factory_->CreateLoaderAndStart(
+ mojo::MakeRequest(&url_loader_), 0 /* routing_id */, 0 /* request_id */,
+ mojom::kURLLoadOptionNone, request,
+ test_cors_loader_client_.CreateInterfacePtr(),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+ }
+
+ bool IsNetworkLoaderStarted() {
+ DCHECK(test_url_loader_factory_);
+ return test_url_loader_factory_->IsCreateLoaderAndStartCalled();
+ }
+
+ void NotifyLoaderClientOnReceiveResponse(
+ const std::string& extra_header = std::string()) {
+ DCHECK(test_url_loader_factory_);
+ test_url_loader_factory_->NotifyClientOnReceiveResponse(extra_header);
+ }
+
+ void NotifyLoaderClientOnComplete(int error_code) {
+ DCHECK(test_url_loader_factory_);
+ test_url_loader_factory_->NotifyClientOnComplete(error_code);
+ }
+
+ const TestURLLoaderClient& client() const { return test_cors_loader_client_; }
+
+ void RunUntilComplete() { test_cors_loader_client_.RunUntilComplete(); }
+
+ private:
+ // Be the first member so it is destroyed last.
+ base::MessageLoop message_loop_;
+
+ // Testing instance to enable kOutOfBlinkCORS feature.
+ base::test::ScopedFeatureList feature_list_;
+
+ // CORSURLLoaderFactory instance under tests.
+ std::unique_ptr<mojom::URLLoaderFactory> cors_url_loader_factory_;
+
+ // TestURLLoaderFactory instance owned by CORSURLLoaderFactory.
+ base::WeakPtr<TestURLLoaderFactory> test_url_loader_factory_;
+
+ // Holds URLLoaderPtr that CreateLoaderAndStart() creates.
+ mojom::URLLoaderPtr url_loader_;
+
+ // TestURLLoaderClient that records callback activities.
+ TestURLLoaderClient test_cors_loader_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(CORSURLLoaderTest);
+};
+
+TEST_F(CORSURLLoaderTest, SameOriginRequest) {
+ const GURL url("http://example.com/foo.png");
+ CreateLoaderAndStart(url.GetOrigin(), url,
+ mojom::FetchRequestMode::kSameOrigin);
+
+ NotifyLoaderClientOnReceiveResponse();
+ NotifyLoaderClientOnComplete(net::OK);
+
+ RunUntilComplete();
+
+ EXPECT_TRUE(IsNetworkLoaderStarted());
+ EXPECT_FALSE(client().has_received_redirect());
+ EXPECT_TRUE(client().has_received_response());
+ EXPECT_TRUE(client().has_received_completion());
+ EXPECT_EQ(net::OK, client().completion_status().error_code);
+}
+
+TEST_F(CORSURLLoaderTest, CrossOriginRequestWithNoCORSMode) {
+ const GURL origin("http://example.com");
+ const GURL url("http://other.com/foo.png");
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kNoCORS);
+
+ NotifyLoaderClientOnReceiveResponse();
+ NotifyLoaderClientOnComplete(net::OK);
+
+ RunUntilComplete();
+
+ EXPECT_TRUE(IsNetworkLoaderStarted());
+ EXPECT_FALSE(client().has_received_redirect());
+ EXPECT_TRUE(client().has_received_response());
+ EXPECT_TRUE(client().has_received_completion());
+ EXPECT_EQ(net::OK, client().completion_status().error_code);
+}
+
+TEST_F(CORSURLLoaderTest, CrossOriginRequestFetchRequestModeSameOrigin) {
+ const GURL origin("http://example.com");
+ const GURL url("http://other.com/foo.png");
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kSameOrigin);
+
+ RunUntilComplete();
+
+ // This call never hits the network URLLoader (i.e. the TestURLLoaderFactory)
+ // because it is fails right away.
+ EXPECT_FALSE(IsNetworkLoaderStarted());
+ EXPECT_FALSE(client().has_received_redirect());
+ EXPECT_FALSE(client().has_received_response());
+ EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
+ ASSERT_TRUE(client().completion_status().cors_error_status);
+ EXPECT_EQ(mojom::CORSError::kDisallowedByMode,
+ client().completion_status().cors_error_status->cors_error);
+}
+
+TEST_F(CORSURLLoaderTest, CrossOriginRequestWithCORSModeButMissingCORSHeader) {
+ const GURL origin("http://example.com");
+ const GURL url("http://other.com/foo.png");
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+
+ NotifyLoaderClientOnReceiveResponse();
+ NotifyLoaderClientOnComplete(net::OK);
+
+ RunUntilComplete();
+
+ EXPECT_TRUE(IsNetworkLoaderStarted());
+ EXPECT_FALSE(client().has_received_redirect());
+ EXPECT_FALSE(client().has_received_response());
+ EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
+ ASSERT_TRUE(client().completion_status().cors_error_status);
+ EXPECT_EQ(mojom::CORSError::kMissingAllowOriginHeader,
+ client().completion_status().cors_error_status->cors_error);
+}
+
+TEST_F(CORSURLLoaderTest, CrossOriginRequestWithCORSMode) {
+ const GURL origin("http://example.com");
+ const GURL url("http://other.com/foo.png");
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+
+ NotifyLoaderClientOnReceiveResponse(
+ "Access-Control-Allow-Origin: http://example.com");
+ NotifyLoaderClientOnComplete(net::OK);
+
+ RunUntilComplete();
+
+ EXPECT_TRUE(IsNetworkLoaderStarted());
+ EXPECT_FALSE(client().has_received_redirect());
+ EXPECT_TRUE(client().has_received_response());
+ EXPECT_TRUE(client().has_received_completion());
+ EXPECT_EQ(net::OK, client().completion_status().error_code);
+}
+
+TEST_F(CORSURLLoaderTest,
+ CrossOriginRequestFetchRequestWithCORSModeButMismatchedCORSHeader) {
+ const GURL origin("http://example.com");
+ const GURL url("http://other.com/foo.png");
+ CreateLoaderAndStart(origin, url, mojom::FetchRequestMode::kCORS);
+
+ NotifyLoaderClientOnReceiveResponse(
+ "Access-Control-Allow-Origin: http://some-other-domain.com");
+ NotifyLoaderClientOnComplete(net::OK);
+
+ RunUntilComplete();
+
+ EXPECT_TRUE(IsNetworkLoaderStarted());
+ EXPECT_FALSE(client().has_received_redirect());
+ EXPECT_FALSE(client().has_received_response());
+ EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
+ ASSERT_TRUE(client().completion_status().cors_error_status);
+ EXPECT_EQ(mojom::CORSError::kAllowOriginMismatch,
+ client().completion_status().cors_error_status->cors_error);
+}
+
+} // namespace
+} // namespace network
diff --git a/chromium/services/network/cors/preflight_controller.cc b/chromium/services/network/cors/preflight_controller.cc
new file mode 100644
index 00000000000..ca47fd1aed5
--- /dev/null
+++ b/chromium/services/network/cors/preflight_controller.cc
@@ -0,0 +1,96 @@
+// Copyright 2018 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/network/cors/preflight_controller.h"
+
+#include <algorithm>
+
+#include "base/strings/string_util.h"
+#include "net/http/http_request_headers.h"
+#include "services/network/public/cpp/cors/cors.h"
+#include "url/gurl.h"
+
+namespace network {
+
+namespace cors {
+
+namespace {
+
+// Algorithm step 3 of the CORS-preflight fetch,
+// https://fetch.spec.whatwg.org/#cors-preflight-fetch-0, that requires
+// - CORS-safelisted request-headers excluded
+// - duplicates excluded
+// - sorted lexicographically
+// - byte-lowercased
+std::string CreateAccessControlRequestHeadersHeader(
+ const net::HttpRequestHeaders& headers) {
+ std::vector<std::string> filtered_headers;
+ for (const auto& header : headers.GetHeaderVector()) {
+ // Exclude CORS-safelisted headers.
+ if (cors::IsCORSSafelistedHeader(header.key, header.value))
+ continue;
+ // Exclude the forbidden headers because they may be added by the user
+ // agent. They must be checked separately and rejected for
+ // JavaScript-initiated requests.
+ if (cors::IsForbiddenHeader(header.key))
+ continue;
+ filtered_headers.push_back(base::ToLowerASCII(header.key));
+ }
+ if (filtered_headers.empty())
+ return std::string();
+
+ // Sort header names lexicographically.
+ std::sort(filtered_headers.begin(), filtered_headers.end());
+
+ return base::JoinString(filtered_headers, ",");
+}
+
+} // namespace
+
+// static
+std::unique_ptr<ResourceRequest> PreflightController::CreatePreflightRequest(
+ const ResourceRequest& request) {
+ DCHECK(!request.url.has_username());
+ DCHECK(!request.url.has_password());
+
+ std::unique_ptr<ResourceRequest> preflight_request =
+ std::make_unique<ResourceRequest>();
+
+ // Algorithm step 1 through 4 of the CORS-preflight fetch,
+ // https://fetch.spec.whatwg.org/#cors-preflight-fetch-0.
+ preflight_request->url = request.url;
+ preflight_request->method = "OPTIONS";
+ preflight_request->priority = request.priority;
+ preflight_request->request_context = request.request_context;
+ preflight_request->referrer = request.referrer;
+ preflight_request->referrer_policy = request.referrer_policy;
+
+ preflight_request->fetch_credentials_mode =
+ mojom::FetchCredentialsMode::kOmit;
+
+ preflight_request->headers.SetHeader(
+ cors::header_names::kAccessControlRequestMethod, request.method);
+
+ std::string request_headers =
+ CreateAccessControlRequestHeadersHeader(request.headers);
+ if (!request_headers.empty()) {
+ preflight_request->headers.SetHeader(
+ cors::header_names::kAccessControlRequestHeaders, request_headers);
+ }
+
+ if (request.is_external_request) {
+ preflight_request->headers.SetHeader(
+ cors::header_names::kAccessControlRequestExternal, "true");
+ }
+
+ // TODO(toyoshim): Remove the following line once the network service is
+ // enabled by default.
+ preflight_request->skip_service_worker = true;
+
+ return preflight_request;
+}
+
+} // namespace cors
+
+} // namespace network
diff --git a/chromium/services/network/cors/preflight_controller.h b/chromium/services/network/cors/preflight_controller.h
new file mode 100644
index 00000000000..40f4809b796
--- /dev/null
+++ b/chromium/services/network/cors/preflight_controller.h
@@ -0,0 +1,39 @@
+// Copyright 2018 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 SERVICES_NETWORK_CORS_PREFLIGHT_CONTROLLER_H_
+#define SERVICES_NETWORK_CORS_PREFLIGHT_CONTROLLER_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "services/network/public/cpp/resource_request.h"
+
+namespace network {
+
+namespace cors {
+
+// A class to manage CORS-preflight, making a CORS-preflight request, checking
+// its result, and owning a CORS-preflight cache.
+// TODO(toyoshim): Features explained above not fully implemented yet.
+// See also https://crbug.com/803766 to check a design doc.
+class COMPONENT_EXPORT(NETWORK_SERVICE) PreflightController {
+ public:
+ // Creates a CORS-preflight ResourceRequest for a specified |request| for a
+ // URL that is originally requested.
+ // Note: This function is exposed for testing only purpose, and production
+ // code outside this class should not call this function directly.
+ static std::unique_ptr<ResourceRequest> CreatePreflightRequest(
+ const ResourceRequest& request);
+
+ // TODO(toyoshim): Implements an asynchronous interface to consult about
+ // CORS-preflight check, that manages a preflight cache, and may make a
+ // preflight request internally.
+};
+
+} // namespace cors
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_CORS_PREFLIGHT_CONTROLLER_H_
diff --git a/chromium/services/network/cors/preflight_controller_unittest.cc b/chromium/services/network/cors/preflight_controller_unittest.cc
new file mode 100644
index 00000000000..75c1a38098f
--- /dev/null
+++ b/chromium/services/network/cors/preflight_controller_unittest.cc
@@ -0,0 +1,108 @@
+// Copyright 2018 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/network/cors/preflight_controller.h"
+
+#include "services/network/public/cpp/cors/cors.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace cors {
+
+namespace {
+
+TEST(PreflightControllerCreatePreflightRequestTest, LexicographicalOrder) {
+ ResourceRequest request;
+ request.headers.SetHeader("Orange", "Orange");
+ request.headers.SetHeader("Apple", "Red");
+ request.headers.SetHeader("Kiwifruit", "Green");
+ request.headers.SetHeader("Content-Type", "application/octet-stream");
+ request.headers.SetHeader("Strawberry", "Red");
+
+ std::unique_ptr<ResourceRequest> preflight =
+ PreflightController::CreatePreflightRequest(request);
+
+ std::string header;
+ EXPECT_TRUE(preflight->headers.GetHeader(
+ cors::header_names::kAccessControlRequestHeaders, &header));
+ EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry", header);
+}
+
+TEST(PreflightControllerCreatePreflightRequestTest, ExcludeSimpleHeaders) {
+ ResourceRequest request;
+ request.headers.SetHeader("Accept", "everything");
+ request.headers.SetHeader("Accept-Language", "everything");
+ request.headers.SetHeader("Content-Language", "everything");
+ request.headers.SetHeader("Save-Data", "on");
+
+ std::unique_ptr<ResourceRequest> preflight =
+ PreflightController::CreatePreflightRequest(request);
+
+ // Do not emit empty-valued headers; an empty list of non-"CORS safelisted"
+ // request headers should cause "Access-Control-Request-Headers:" to be
+ // left out in the preflight request.
+ std::string header;
+ EXPECT_FALSE(preflight->headers.GetHeader(
+ cors::header_names::kAccessControlRequestHeaders, &header));
+}
+
+TEST(PreflightControllerCreatePreflightRequestTest,
+ ExcludeSimpleContentTypeHeader) {
+ ResourceRequest request;
+ request.headers.SetHeader("Content-Type", "text/plain");
+
+ std::unique_ptr<ResourceRequest> preflight =
+ PreflightController::CreatePreflightRequest(request);
+
+ // Empty list also; see comment in test above.
+ std::string header;
+ EXPECT_FALSE(preflight->headers.GetHeader(
+ cors::header_names::kAccessControlRequestHeaders, &header));
+}
+
+TEST(PreflightControllerCreatePreflightRequestTest, IncludeNonSimpleHeader) {
+ ResourceRequest request;
+ request.headers.SetHeader("X-Custom-Header", "foobar");
+
+ std::unique_ptr<ResourceRequest> preflight =
+ PreflightController::CreatePreflightRequest(request);
+
+ std::string header;
+ EXPECT_TRUE(preflight->headers.GetHeader(
+ cors::header_names::kAccessControlRequestHeaders, &header));
+ EXPECT_EQ("x-custom-header", header);
+}
+
+TEST(PreflightControllerCreatePreflightRequestTest,
+ IncludeNonSimpleContentTypeHeader) {
+ ResourceRequest request;
+ request.headers.SetHeader("Content-Type", "application/octet-stream");
+
+ std::unique_ptr<ResourceRequest> preflight =
+ PreflightController::CreatePreflightRequest(request);
+
+ std::string header;
+ EXPECT_TRUE(preflight->headers.GetHeader(
+ cors::header_names::kAccessControlRequestHeaders, &header));
+ EXPECT_EQ("content-type", header);
+}
+
+TEST(PreflightControllerCreatePreflightRequestTest, ExcludeForbiddenHeaders) {
+ ResourceRequest request;
+ request.headers.SetHeader("referer", "https://www.google.com/");
+
+ std::unique_ptr<ResourceRequest> preflight =
+ PreflightController::CreatePreflightRequest(request);
+
+ std::string header;
+ EXPECT_FALSE(preflight->headers.GetHeader(
+ cors::header_names::kAccessControlRequestHeaders, &header));
+}
+
+} // namespace
+
+} // namespace cors
+
+} // namespace network
diff --git a/chromium/services/network/data_pipe_element_reader.cc b/chromium/services/network/data_pipe_element_reader.cc
new file mode 100644
index 00000000000..2bc99828686
--- /dev/null
+++ b/chromium/services/network/data_pipe_element_reader.cc
@@ -0,0 +1,130 @@
+// 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 "services/network/data_pipe_element_reader.h"
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "mojo/public/c/system/types.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+
+namespace network {
+
+DataPipeElementReader::DataPipeElementReader(
+ scoped_refptr<ResourceRequestBody> resource_request_body,
+ mojom::DataPipeGetterPtr data_pipe_getter_)
+ : resource_request_body_(std::move(resource_request_body)),
+ data_pipe_getter_(std::move(data_pipe_getter_)),
+ handle_watcher_(FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+ weak_factory_(this) {}
+
+DataPipeElementReader::~DataPipeElementReader() {}
+
+int DataPipeElementReader::Init(net::CompletionOnceCallback callback) {
+ DCHECK(callback);
+
+ // Init rewinds the stream. Throw away current state.
+ read_callback_.Reset();
+ buf_ = nullptr;
+ buf_length_ = 0;
+ handle_watcher_.Cancel();
+ size_ = 0;
+ bytes_read_ = 0;
+ // Need to do this to prevent any previously pending ReadCallback() invocation
+ // from running.
+ weak_factory_.InvalidateWeakPtrs();
+
+ // Get a new data pipe and start.
+ mojo::DataPipe data_pipe;
+ data_pipe_getter_->Read(std::move(data_pipe.producer_handle),
+ base::BindOnce(&DataPipeElementReader::ReadCallback,
+ weak_factory_.GetWeakPtr()));
+ data_pipe_ = std::move(data_pipe.consumer_handle);
+ handle_watcher_.Watch(
+ data_pipe_.get(), MOJO_HANDLE_SIGNAL_READABLE,
+ base::BindRepeating(&DataPipeElementReader::OnHandleReadable,
+ base::Unretained(this)));
+
+ init_callback_ = std::move(callback);
+ return net::ERR_IO_PENDING;
+}
+
+uint64_t DataPipeElementReader::GetContentLength() const {
+ return size_;
+}
+
+uint64_t DataPipeElementReader::BytesRemaining() const {
+ return size_ - bytes_read_;
+}
+
+int DataPipeElementReader::Read(net::IOBuffer* buf,
+ int buf_length,
+ net::CompletionOnceCallback callback) {
+ DCHECK(callback);
+ DCHECK(!read_callback_);
+ DCHECK(!init_callback_);
+ DCHECK(!buf_);
+
+ int result = ReadInternal(buf, buf_length);
+ if (result == net::ERR_IO_PENDING) {
+ buf_ = buf;
+ buf_length_ = buf_length;
+ read_callback_ = std::move(callback);
+ }
+ return result;
+}
+
+void DataPipeElementReader::ReadCallback(int32_t status, uint64_t size) {
+ if (status == net::OK)
+ size_ = size;
+ if (init_callback_)
+ std::move(init_callback_).Run(status);
+}
+
+void DataPipeElementReader::OnHandleReadable(MojoResult result) {
+ DCHECK(read_callback_);
+ DCHECK(buf_);
+
+ // Final result of the Read() call, to be passed to the consumer.
+ int read_result;
+ if (result == MOJO_RESULT_OK) {
+ read_result = ReadInternal(buf_.get(), buf_length_);
+ } else {
+ read_result = net::ERR_FAILED;
+ }
+
+ buf_ = nullptr;
+ buf_length_ = 0;
+
+ if (read_result != net::ERR_IO_PENDING)
+ std::move(read_callback_).Run(read_result);
+}
+
+int DataPipeElementReader::ReadInternal(net::IOBuffer* buf, int buf_length) {
+ DCHECK(buf);
+ DCHECK_GT(buf_length, 0);
+
+ if (BytesRemaining() == 0)
+ return net::OK;
+
+ uint32_t num_bytes = buf_length;
+ MojoResult rv =
+ data_pipe_->ReadData(buf->data(), &num_bytes, MOJO_READ_DATA_FLAG_NONE);
+ if (rv == MOJO_RESULT_OK) {
+ bytes_read_ += num_bytes;
+ return num_bytes;
+ }
+
+ if (rv == MOJO_RESULT_SHOULD_WAIT) {
+ handle_watcher_.ArmOrNotify();
+ return net::ERR_IO_PENDING;
+ }
+
+ return net::ERR_FAILED;
+}
+
+} // namespace network
diff --git a/chromium/services/network/data_pipe_element_reader.h b/chromium/services/network/data_pipe_element_reader.h
new file mode 100644
index 00000000000..ded004d1668
--- /dev/null
+++ b/chromium/services/network/data_pipe_element_reader.h
@@ -0,0 +1,88 @@
+// 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 SERVICES_NETWORK_DATA_PIPE_ELEMENT_READER_H_
+#define SERVICES_NETWORK_DATA_PIPE_ELEMENT_READER_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/base/completion_once_callback.h"
+#include "net/base/upload_element_reader.h"
+#include "services/network/public/cpp/resource_request_body.h"
+#include "services/network/public/mojom/data_pipe_getter.mojom.h"
+
+namespace net {
+class IOBuffer;
+}
+
+namespace network {
+
+// A subclass of net::UploadElementReader to read data pipes.
+class COMPONENT_EXPORT(NETWORK_SERVICE) DataPipeElementReader
+ : public net::UploadElementReader {
+ public:
+ // |resource_request_body| is just passed in to keep the object around for the
+ // life of the ElementReader.
+ DataPipeElementReader(
+ scoped_refptr<ResourceRequestBody> resource_request_body,
+ mojom::DataPipeGetterPtr data_pipe_getter_);
+
+ ~DataPipeElementReader() override;
+
+ // net::UploadElementReader implementation:
+ int Init(net::CompletionOnceCallback callback) override;
+ uint64_t GetContentLength() const override;
+ uint64_t BytesRemaining() const override;
+ int Read(net::IOBuffer* buf,
+ int buf_length,
+ net::CompletionOnceCallback callback) override;
+
+ private:
+ // Callback invoked by DataPipeGetter::Read.
+ void ReadCallback(int32_t status, uint64_t size);
+
+ // Called by |handle_watcher_| when data is available or the pipe was closed,
+ // and there's a pending Read() call.
+ void OnHandleReadable(MojoResult result);
+
+ // Attempts to read data from |data_pipe_| and write it to |buf|. On success,
+ // writes the amount of data written. On failure, returns a net error code. If
+ // no data was available yet, tells |handle_watcher_| to start watching the
+ // pipe for data to become available and returns ERR_IO_PENDING. It's up to
+ // the caller to update |buf_| and |buf_length_| if needed.
+ int ReadInternal(net::IOBuffer* buf, int buf_length);
+
+ scoped_refptr<ResourceRequestBody> resource_request_body_;
+ mojom::DataPipeGetterPtr data_pipe_getter_;
+ mojo::ScopedDataPipeConsumerHandle data_pipe_;
+ mojo::SimpleWatcher handle_watcher_;
+
+ // Write buffer and its length. Populated when Read() is called but returns
+ // ERR_IO_PENDING. Cleared once the read completes.
+ scoped_refptr<net::IOBuffer> buf_;
+ int buf_length_ = 0;
+
+ // Total size of input, as passed to ReadCallback().
+ uint64_t size_ = 0;
+
+ uint64_t bytes_read_ = 0;
+ net::CompletionOnceCallback init_callback_;
+ net::CompletionOnceCallback read_callback_;
+
+ base::WeakPtrFactory<DataPipeElementReader> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DataPipeElementReader);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_DATA_PIPE_ELEMENT_READER_H_
diff --git a/chromium/services/network/data_pipe_element_reader_unittest.cc b/chromium/services/network/data_pipe_element_reader_unittest.cc
new file mode 100644
index 00000000000..e016cf0b2a5
--- /dev/null
+++ b/chromium/services/network/data_pipe_element_reader_unittest.cc
@@ -0,0 +1,228 @@
+// 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 "services/network/data_pipe_element_reader.h"
+
+#include <stdint.h>
+
+#include <limits>
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "mojo/common/data_pipe_utils.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "net/base/completion_callback.h"
+#include "net/base/io_buffer.h"
+#include "net/base/test_completion_callback.h"
+#include "services/network/public/mojom/data_pipe_getter.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+// Most tests of this class are at the URLLoader layer. These tests focus on
+// things too difficult to cover with integration tests.
+
+namespace network {
+
+namespace {
+
+class PassThroughDataPipeGetter : public mojom::DataPipeGetter {
+ public:
+ explicit PassThroughDataPipeGetter() : binding_(this) {}
+
+ network::mojom::DataPipeGetterPtr GetDataPipeGetterPtr() {
+ EXPECT_FALSE(binding_.is_bound());
+
+ network::mojom::DataPipeGetterPtr data_pipe_getter_ptr;
+ binding_.Bind(mojo::MakeRequest(&data_pipe_getter_ptr));
+ return data_pipe_getter_ptr;
+ }
+
+ void WaitForRead(mojo::ScopedDataPipeProducerHandle* write_pipe,
+ ReadCallback* read_callback) {
+ DCHECK(!run_loop_);
+
+ if (!write_pipe_.is_valid()) {
+ run_loop_ = std::make_unique<base::RunLoop>();
+ run_loop_->Run();
+ run_loop_.reset();
+ }
+
+ EXPECT_TRUE(write_pipe_.is_valid());
+ EXPECT_TRUE(read_callback_);
+
+ *write_pipe = std::move(write_pipe_);
+ *read_callback = std::move(read_callback_);
+ }
+
+ private:
+ // network::mojom::DataPipeGetter implementation:
+ void Read(mojo::ScopedDataPipeProducerHandle pipe,
+ ReadCallback callback) override {
+ EXPECT_FALSE(write_pipe_.is_valid());
+ EXPECT_FALSE(read_callback_);
+
+ write_pipe_ = std::move(pipe);
+ read_callback_ = std::move(callback);
+
+ if (run_loop_)
+ run_loop_->Quit();
+ }
+
+ void Clone(network::mojom::DataPipeGetterRequest request) override {
+ NOTIMPLEMENTED();
+ }
+
+ std::unique_ptr<base::RunLoop> run_loop_;
+
+ mojo::Binding<network::mojom::DataPipeGetter> binding_;
+ mojo::ScopedDataPipeProducerHandle write_pipe_;
+ ReadCallback read_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(PassThroughDataPipeGetter);
+};
+
+class DataPipeElementReaderTest : public testing::Test {
+ public:
+ DataPipeElementReaderTest()
+ : element_reader_(nullptr, data_pipe_getter_.GetDataPipeGetterPtr()) {}
+
+ protected:
+ base::MessageLoopForIO message_loop_;
+ PassThroughDataPipeGetter data_pipe_getter_;
+ DataPipeElementReader element_reader_;
+};
+
+// Test the case where a second Init() call occurs when there's a pending Init()
+// call in progress. The first call should be dropped, in favor of the second
+// one.
+TEST_F(DataPipeElementReaderTest, InitInterruptsInit) {
+ // Value deliberately outside of the range of an uint32_t, to catch any
+ // accidental conversions to an int.
+ const uint64_t kResponseBodySize = std::numeric_limits<uint32_t>::max();
+
+ // The network stack calls Init.
+ net::TestCompletionCallback first_init_callback;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ element_reader_.Init(first_init_callback.callback()));
+
+ // Wait for DataPipeGetter::Read() to be called.
+ mojo::ScopedDataPipeProducerHandle first_write_pipe;
+ network::mojom::DataPipeGetter::ReadCallback first_read_pipe_callback;
+ data_pipe_getter_.WaitForRead(&first_write_pipe, &first_read_pipe_callback);
+
+ // The network stack calls Init again, interrupting the previous call.
+ net::TestCompletionCallback second_init_callback;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ element_reader_.Init(second_init_callback.callback()));
+
+ // Wait for DataPipeGetter::Read() to be called again.
+ mojo::ScopedDataPipeProducerHandle second_write_pipe;
+ network::mojom::DataPipeGetter::ReadCallback second_read_pipe_callback;
+ data_pipe_getter_.WaitForRead(&second_write_pipe, &second_read_pipe_callback);
+
+ // Sending data on the first read pipe should do nothing.
+ std::move(first_read_pipe_callback)
+ .Run(net::ERR_FAILED, kResponseBodySize - 1);
+ // Run any pending tasks, to make sure nothing unexpected is queued.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(first_init_callback.have_result());
+ EXPECT_FALSE(second_init_callback.have_result());
+
+ // Sending data on the second pipe should result in the second init callback
+ // being invoked.
+ std::move(second_read_pipe_callback).Run(net::OK, kResponseBodySize);
+ EXPECT_EQ(net::OK, second_init_callback.WaitForResult());
+ EXPECT_FALSE(first_init_callback.have_result());
+
+ EXPECT_EQ(kResponseBodySize, element_reader_.GetContentLength());
+ EXPECT_EQ(kResponseBodySize, element_reader_.BytesRemaining());
+ EXPECT_FALSE(element_reader_.IsInMemory());
+
+ // Try to read from the body.
+ scoped_refptr<net::IOBufferWithSize> io_buffer(new net::IOBufferWithSize(10));
+ net::TestCompletionCallback read_callback;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ element_reader_.Read(io_buffer.get(), io_buffer->size(),
+ read_callback.callback()));
+
+ // Writes to the first write pipe should either fail, or succeed but be
+ // ignored.
+ mojo::common::BlockingCopyFromString("foo", first_write_pipe);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(read_callback.have_result());
+}
+
+// Test the case where a second Init() call occurs when there's a pending Read()
+// call in progress. The old Read() should be dropped, in favor of the new
+// Init().
+TEST_F(DataPipeElementReaderTest, InitInterruptsRead) {
+ // Value deliberately outside of the range of an uint32_t, to catch any
+ // accidental conversions to an int.
+ const uint64_t kResponseBodySize = std::numeric_limits<uint32_t>::max();
+
+ // The network stack calls Init.
+ net::TestCompletionCallback first_init_callback;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ element_reader_.Init(first_init_callback.callback()));
+
+ // Wait for DataPipeGetter::Read() to be called.
+ mojo::ScopedDataPipeProducerHandle first_write_pipe;
+ network::mojom::DataPipeGetter::ReadCallback first_read_pipe_callback;
+ data_pipe_getter_.WaitForRead(&first_write_pipe, &first_read_pipe_callback);
+ std::move(first_read_pipe_callback).Run(net::OK, kResponseBodySize);
+
+ ASSERT_EQ(net::OK, first_init_callback.WaitForResult());
+
+ scoped_refptr<net::IOBufferWithSize> first_io_buffer(
+ new net::IOBufferWithSize(10));
+ net::TestCompletionCallback first_read_callback;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ element_reader_.Read(first_io_buffer.get(), first_io_buffer->size(),
+ first_read_callback.callback()));
+
+ // The network stack calls Init again, interrupting the previous read.
+ net::TestCompletionCallback second_init_callback;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ element_reader_.Init(second_init_callback.callback()));
+
+ // Wait for DataPipeGetter::Read() to be called again.
+ mojo::ScopedDataPipeProducerHandle second_write_pipe;
+ network::mojom::DataPipeGetter::ReadCallback second_read_pipe_callback;
+ data_pipe_getter_.WaitForRead(&second_write_pipe, &second_read_pipe_callback);
+
+ // Run any pending tasks, to make sure nothing unexpected is queued.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(first_read_callback.have_result());
+ EXPECT_FALSE(second_init_callback.have_result());
+
+ // Sending data on the second pipe should result in the second init callback
+ // being invoked.
+ std::move(second_read_pipe_callback).Run(net::OK, kResponseBodySize);
+ EXPECT_EQ(net::OK, second_init_callback.WaitForResult());
+
+ EXPECT_EQ(kResponseBodySize, element_reader_.GetContentLength());
+ EXPECT_EQ(kResponseBodySize, element_reader_.BytesRemaining());
+ EXPECT_FALSE(element_reader_.IsInMemory());
+
+ // Try to read from the body.
+ scoped_refptr<net::IOBufferWithSize> io_buffer(new net::IOBufferWithSize(10));
+ net::TestCompletionCallback second_read_callback;
+ EXPECT_EQ(net::ERR_IO_PENDING,
+ element_reader_.Read(io_buffer.get(), io_buffer->size(),
+ second_read_callback.callback()));
+
+ // Writes to the first write pipe should either fail, or succeed but be
+ // ignored.
+ mojo::common::BlockingCopyFromString("foo", first_write_pipe);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(second_read_callback.have_result());
+}
+
+} // namespace
+
+} // namespace network
diff --git a/chromium/services/network/http_server_properties_pref_delegate.cc b/chromium/services/network/http_server_properties_pref_delegate.cc
new file mode 100644
index 00000000000..81d33c65fca
--- /dev/null
+++ b/chromium/services/network/http_server_properties_pref_delegate.cc
@@ -0,0 +1,54 @@
+// 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 "services/network/http_server_properties_pref_delegate.h"
+
+#include "base/bind.h"
+#include "base/values.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+const char kPrefPath[] = "net.http_server_properties";
+
+namespace network {
+
+HttpServerPropertiesPrefDelegate::HttpServerPropertiesPrefDelegate(
+ PrefService* pref_service)
+ : pref_service_(pref_service) {
+ pref_change_registrar_.Init(pref_service_);
+}
+
+HttpServerPropertiesPrefDelegate::~HttpServerPropertiesPrefDelegate() {}
+
+void HttpServerPropertiesPrefDelegate::RegisterPrefs(
+ PrefRegistrySimple* pref_registry) {
+ pref_registry->RegisterDictionaryPref(kPrefPath);
+}
+
+const base::DictionaryValue*
+HttpServerPropertiesPrefDelegate::GetServerProperties() const {
+ return pref_service_->GetDictionary(kPrefPath);
+}
+
+void HttpServerPropertiesPrefDelegate::SetServerProperties(
+ const base::DictionaryValue& value,
+ base::OnceClosure callback) {
+ pref_service_->Set(kPrefPath, value);
+ if (callback)
+ pref_service_->CommitPendingWrite(std::move(callback));
+}
+
+void HttpServerPropertiesPrefDelegate::StartListeningForUpdates(
+ const base::RepeatingClosure& callback) {
+ pref_change_registrar_.Add(kPrefPath, callback);
+ // PrefChangeRegistrar isn't notified of initial pref load, so watch for that,
+ // too.
+ if (pref_service_->GetInitializationStatus() ==
+ PrefService::INITIALIZATION_STATUS_WAITING) {
+ pref_service_->AddPrefInitObserver(base::BindOnce(
+ [](const base::Closure& callback, bool) { callback.Run(); }, callback));
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/http_server_properties_pref_delegate.h b/chromium/services/network/http_server_properties_pref_delegate.h
new file mode 100644
index 00000000000..b0bfc79df3f
--- /dev/null
+++ b/chromium/services/network/http_server_properties_pref_delegate.h
@@ -0,0 +1,44 @@
+// 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 SERVICES_NETWORK_HTTP_SERVER_PROPERTIES_PREF_DELEGATE_H_
+#define SERVICES_NETWORK_HTTP_SERVER_PROPERTIES_PREF_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "net/http/http_server_properties.h"
+#include "net/http/http_server_properties_manager.h"
+
+class PrefRegistrySimple;
+
+namespace network {
+
+// Manages disk storage for a net::HttpServerPropertiesManager.
+class HttpServerPropertiesPrefDelegate
+ : public net::HttpServerPropertiesManager::PrefDelegate {
+ public:
+ // The created object must be destroyed before |pref_service|.
+ explicit HttpServerPropertiesPrefDelegate(PrefService* pref_service);
+ ~HttpServerPropertiesPrefDelegate() override;
+
+ static void RegisterPrefs(PrefRegistrySimple* pref_registry);
+
+ // net::HttpServerPropertiesManager::PrefDelegate implementation.
+ const base::DictionaryValue* GetServerProperties() const override;
+ void SetServerProperties(const base::DictionaryValue& value,
+ base::OnceClosure callback) override;
+ void StartListeningForUpdates(
+ const base::RepeatingClosure& callback) override;
+
+ private:
+ PrefService* pref_service_;
+ PrefChangeRegistrar pref_change_registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesPrefDelegate);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_HTTP_SERVER_PROPERTIES_PREF_DELEGATE_H_
diff --git a/chromium/services/network/ignore_errors_cert_verifier.cc b/chromium/services/network/ignore_errors_cert_verifier.cc
new file mode 100644
index 00000000000..9e8d24fccbe
--- /dev/null
+++ b/chromium/services/network/ignore_errors_cert_verifier.cc
@@ -0,0 +1,137 @@
+// 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 "services/network/ignore_errors_cert_verifier.h"
+
+#include <iterator>
+#include <utility>
+
+#include "base/base64.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "crypto/sha2.h"
+#include "net/base/completion_callback.h"
+#include "net/base/hash_value.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_export.h"
+#include "net/cert/asn1_util.h"
+#include "net/cert/cert_verify_result.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
+#include "services/network/public/cpp/network_switches.h"
+
+using ::net::CertVerifier;
+using ::net::CompletionCallback;
+using ::net::HashValue;
+using ::net::SHA256HashValue;
+using ::net::X509Certificate;
+
+namespace network {
+
+// static
+std::unique_ptr<CertVerifier> IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
+ const base::CommandLine& command_line,
+ const char* user_data_dir_switch,
+ std::unique_ptr<CertVerifier> verifier) {
+ if ((user_data_dir_switch && !command_line.HasSwitch(user_data_dir_switch)) ||
+ !command_line.HasSwitch(switches::kIgnoreCertificateErrorsSPKIList)) {
+ return verifier;
+ }
+ auto spki_list =
+ base::SplitString(command_line.GetSwitchValueASCII(
+ switches::kIgnoreCertificateErrorsSPKIList),
+ ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+ return std::make_unique<IgnoreErrorsCertVerifier>(
+ std::move(verifier), IgnoreErrorsCertVerifier::MakeWhitelist(spki_list));
+}
+
+// static
+IgnoreErrorsCertVerifier::SPKIHashSet IgnoreErrorsCertVerifier::MakeWhitelist(
+ const std::vector<std::string>& fingerprints) {
+ IgnoreErrorsCertVerifier::SPKIHashSet whitelist;
+ for (const std::string& fingerprint : fingerprints) {
+ HashValue hash;
+ if (!hash.FromString("sha256/" + fingerprint)) {
+ LOG(ERROR) << "Invalid SPKI: " << fingerprint;
+ continue;
+ }
+ SHA256HashValue sha256;
+ DCHECK_EQ(hash.size(), sizeof(sha256));
+ memcpy(&sha256, hash.data(), sizeof(sha256));
+ whitelist.insert(sha256);
+ }
+ return whitelist;
+}
+
+IgnoreErrorsCertVerifier::IgnoreErrorsCertVerifier(
+ std::unique_ptr<CertVerifier> verifier,
+ IgnoreErrorsCertVerifier::SPKIHashSet whitelist)
+ : verifier_(std::move(verifier)), whitelist_(std::move(whitelist)) {}
+
+IgnoreErrorsCertVerifier::~IgnoreErrorsCertVerifier() {}
+
+int IgnoreErrorsCertVerifier::Verify(const RequestParams& params,
+ net::CRLSet* crl_set,
+ net::CertVerifyResult* verify_result,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<Request>* out_req,
+ const net::NetLogWithSource& net_log) {
+ SPKIHashSet spki_fingerprints;
+ base::StringPiece cert_spki;
+ SHA256HashValue hash;
+ if (net::asn1::ExtractSPKIFromDERCert(
+ net::x509_util::CryptoBufferAsStringPiece(
+ params.certificate()->cert_buffer()),
+ &cert_spki)) {
+ crypto::SHA256HashString(cert_spki, &hash, sizeof(SHA256HashValue));
+ spki_fingerprints.insert(hash);
+ }
+ for (const auto& intermediate :
+ params.certificate()->intermediate_buffers()) {
+ if (net::asn1::ExtractSPKIFromDERCert(
+ net::x509_util::CryptoBufferAsStringPiece(intermediate.get()),
+ &cert_spki)) {
+ crypto::SHA256HashString(cert_spki, &hash, sizeof(SHA256HashValue));
+ spki_fingerprints.insert(hash);
+ }
+ }
+
+ // Intersect SPKI hashes from the chain with the whitelist.
+ auto whitelist_begin = whitelist_.begin();
+ auto whitelist_end = whitelist_.end();
+ auto fingerprints_begin = spki_fingerprints.begin();
+ auto fingerprints_end = spki_fingerprints.end();
+ bool ignore_errors = false;
+ while (whitelist_begin != whitelist_end &&
+ fingerprints_begin != fingerprints_end) {
+ if (*whitelist_begin < *fingerprints_begin) {
+ ++whitelist_begin;
+ } else if (*fingerprints_begin < *whitelist_begin) {
+ ++fingerprints_begin;
+ } else {
+ ignore_errors = true;
+ break;
+ }
+ }
+
+ if (ignore_errors) {
+ verify_result->Reset();
+ verify_result->verified_cert = params.certificate();
+ std::transform(spki_fingerprints.begin(), spki_fingerprints.end(),
+ std::back_inserter(verify_result->public_key_hashes),
+ [](const SHA256HashValue& v) { return HashValue(v); });
+ return net::OK;
+ }
+
+ return verifier_->Verify(params, crl_set, verify_result, callback, out_req,
+ net_log);
+}
+
+void IgnoreErrorsCertVerifier::set_whitelist(const SPKIHashSet& whitelist) {
+ whitelist_ = whitelist;
+}
+
+} // namespace network
diff --git a/chromium/services/network/ignore_errors_cert_verifier.h b/chromium/services/network/ignore_errors_cert_verifier.h
new file mode 100644
index 00000000000..8a7c1415d1d
--- /dev/null
+++ b/chromium/services/network/ignore_errors_cert_verifier.h
@@ -0,0 +1,79 @@
+// 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 SERVICES_NETWORK_IGNORE_ERRORS_CERT_VERIFIER_H_
+#define SERVICES_NETWORK_IGNORE_ERRORS_CERT_VERIFIER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/component_export.h"
+#include "base/containers/flat_set.h"
+#include "net/cert/cert_verifier.h"
+
+namespace net {
+struct SHA256HashValue;
+} // namespace net
+
+namespace network {
+
+// IgnoreErrorsCertVerifier wraps another CertVerifier in order to ignore
+// verification errors from certificate chains that match a whitelist of SPKI
+// fingerprints.
+class COMPONENT_EXPORT(NETWORK_SERVICE) IgnoreErrorsCertVerifier
+ : public net::CertVerifier {
+ public:
+ // SPKIHashSet is a set of SHA-256 SPKI fingerprints (RFC 7469, Section 2.4).
+ using SPKIHashSet = base::flat_set<net::SHA256HashValue>;
+
+ // If the |user_data_dir_switch| is passed in as a valid pointer but
+ // --user-data-dir flag is missing, or --ignore-certificate-errors-spki-list
+ // flag is missing then MaybeWrapCertVerifier returns the supplied verifier.
+ // Otherwise it returns an IgnoreErrorsCertVerifier wrapping the supplied
+ // verifier using the whitelist from the
+ // --ignore-certificate-errors-spki-list flag.
+ //
+ // As the --user-data-dir flag is embedder defined, the flag to check for
+ // needs to be passed in from |user_data_dir_switch|.
+ static std::unique_ptr<net::CertVerifier> MaybeWrapCertVerifier(
+ const base::CommandLine& command_line,
+ const char* user_data_dir_switch,
+ std::unique_ptr<net::CertVerifier> verifier);
+
+ // MakeWhitelist converts a vector of Base64-encoded SHA-256 SPKI fingerprints
+ // into an SPKIHashSet. Invalid fingerprints are logged and skipped.
+ static SPKIHashSet MakeWhitelist(
+ const std::vector<std::string>& fingerprints);
+
+ IgnoreErrorsCertVerifier(std::unique_ptr<net::CertVerifier> verifier,
+ SPKIHashSet whitelist);
+
+ ~IgnoreErrorsCertVerifier() override;
+
+ // Verify skips certificate verification and returns OK if any of the
+ // certificates from the chain in |params| match one of the SPKI fingerprints
+ // from the whitelist. Otherwise, it invokes Verify on the wrapped verifier
+ // and returns the result.
+ int Verify(const RequestParams& params,
+ net::CRLSet* crl_set,
+ net::CertVerifyResult* verify_result,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<Request>* out_req,
+ const net::NetLogWithSource& net_log) override;
+
+ private:
+ friend class IgnoreErrorsCertVerifierTest;
+ void set_whitelist(const SPKIHashSet& whitelist); // Testing only.
+
+ std::unique_ptr<net::CertVerifier> verifier_;
+ SPKIHashSet whitelist_;
+
+ DISALLOW_COPY_AND_ASSIGN(IgnoreErrorsCertVerifier);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_IGNORE_ERRORS_CERT_VERIFIER_H_
diff --git a/chromium/services/network/ignore_errors_cert_verifier_unittest.cc b/chromium/services/network/ignore_errors_cert_verifier_unittest.cc
new file mode 100644
index 00000000000..1db9450784f
--- /dev/null
+++ b/chromium/services/network/ignore_errors_cert_verifier_unittest.cc
@@ -0,0 +1,199 @@
+// 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 "services/network/ignore_errors_cert_verifier.h"
+
+#include "base/base64.h"
+#include "base/files/file_path.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "crypto/sha2.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cert/asn1_util.h"
+#include "net/cert/mock_cert_verifier.h"
+#include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
+#include "net/log/net_log_with_source.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/gtest_util.h"
+#include "net/test/test_data_directory.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using net::CertVerifier;
+using net::MockCertVerifier;
+using net::CompletionCallback;
+using net::HashValue;
+using net::SHA256HashValue;
+using net::X509Certificate;
+using net::TestCompletionCallback;
+using net::CertVerifyResult;
+using net::NetLogWithSource;
+
+using net::ERR_CERT_INVALID;
+using net::ERR_IO_PENDING;
+using net::OK;
+
+using net::test::IsError;
+using net::test::IsOk;
+
+namespace network {
+
+static const char kTestUserDataDirSwitch[] = "test-user-data-dir";
+
+static std::vector<std::string> MakeWhitelist() {
+ base::FilePath certs_dir = net::GetTestCertsDirectory();
+ net::CertificateList certs = net::CreateCertificateListFromFile(
+ certs_dir, "x509_verify_results.chain.pem", X509Certificate::FORMAT_AUTO);
+ std::string hash_base64;
+ base::StringPiece cert_spki;
+ SHA256HashValue hash;
+ net::asn1::ExtractSPKIFromDERCert(
+ net::x509_util::CryptoBufferAsStringPiece(certs[1]->cert_buffer()),
+ &cert_spki);
+
+ crypto::SHA256HashString(cert_spki, &hash, sizeof(SHA256HashValue));
+ base::Base64Encode(base::StringPiece(reinterpret_cast<const char*>(hash.data),
+ sizeof(hash.data)),
+ &hash_base64);
+ return {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", "foobar", hash_base64,
+ "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB="};
+}
+
+class IgnoreErrorsCertVerifierTest : public ::testing::Test {
+ public:
+ IgnoreErrorsCertVerifierTest()
+ : mock_verifier_(new MockCertVerifier()),
+ verifier_(base::WrapUnique(mock_verifier_),
+ IgnoreErrorsCertVerifier::SPKIHashSet()) {}
+ ~IgnoreErrorsCertVerifierTest() override {}
+
+ protected:
+ void SetUp() override {
+ verifier_.set_whitelist(
+ IgnoreErrorsCertVerifier::MakeWhitelist(MakeWhitelist()));
+ };
+
+ // The wrapped CertVerifier. Defaults to returning ERR_CERT_INVALID. Owned by
+ // |verifier_|.
+ MockCertVerifier* mock_verifier_;
+ IgnoreErrorsCertVerifier verifier_;
+};
+
+static void GetNonWhitelistedTestCert(scoped_refptr<X509Certificate>* out) {
+ base::FilePath certs_dir = net::GetTestCertsDirectory();
+ scoped_refptr<X509Certificate> test_cert(
+ net::ImportCertFromFile(certs_dir, "ok_cert.pem"));
+ ASSERT_TRUE(test_cert);
+ out->swap(test_cert);
+}
+
+static CertVerifier::RequestParams MakeRequestParams(
+ const scoped_refptr<X509Certificate>& cert) {
+ return CertVerifier::RequestParams(cert, "example.com", 0, "",
+ net::CertificateList());
+}
+
+static void GetWhitelistedTestCert(scoped_refptr<X509Certificate>* out) {
+ base::FilePath certs_dir = net::GetTestCertsDirectory();
+ *out = net::CreateCertificateChainFromFile(
+ certs_dir, "x509_verify_results.chain.pem", X509Certificate::FORMAT_AUTO);
+ ASSERT_TRUE(*out);
+ ASSERT_EQ(2U, (*out)->intermediate_buffers().size());
+}
+
+TEST_F(IgnoreErrorsCertVerifierTest, TestNoMatchCertOk) {
+ mock_verifier_->set_default_result(OK);
+
+ scoped_refptr<X509Certificate> test_cert;
+ ASSERT_NO_FATAL_FAILURE(GetNonWhitelistedTestCert(&test_cert));
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ std::unique_ptr<CertVerifier::Request> request;
+
+ EXPECT_THAT(callback.GetResult(verifier_.Verify(
+ MakeRequestParams(test_cert), nullptr, &verify_result,
+ callback.callback(), &request, NetLogWithSource())),
+ IsOk());
+}
+
+TEST_F(IgnoreErrorsCertVerifierTest, TestNoMatchCertError) {
+ scoped_refptr<X509Certificate> test_cert;
+ ASSERT_NO_FATAL_FAILURE(GetNonWhitelistedTestCert(&test_cert));
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ std::unique_ptr<CertVerifier::Request> request;
+
+ EXPECT_THAT(callback.GetResult(verifier_.Verify(
+ MakeRequestParams(test_cert), nullptr, &verify_result,
+ callback.callback(), &request, NetLogWithSource())),
+ IsError(ERR_CERT_INVALID));
+}
+
+TEST_F(IgnoreErrorsCertVerifierTest, TestMatch) {
+ scoped_refptr<X509Certificate> test_cert;
+ ASSERT_NO_FATAL_FAILURE(GetWhitelistedTestCert(&test_cert));
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ std::unique_ptr<CertVerifier::Request> request;
+
+ EXPECT_THAT(callback.GetResult(verifier_.Verify(
+ MakeRequestParams(test_cert), nullptr, &verify_result,
+ callback.callback(), &request, NetLogWithSource())),
+ IsOk());
+}
+
+class IgnoreCertificateErrorsSPKIListFlagTest
+ : public ::testing::TestWithParam<bool> {
+ public:
+ IgnoreCertificateErrorsSPKIListFlagTest() {
+ base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ if (GetParam()) {
+ command_line.AppendSwitchASCII(kTestUserDataDirSwitch, "/foo/bar/baz");
+ }
+ command_line.AppendSwitchASCII(switches::kIgnoreCertificateErrorsSPKIList,
+ base::JoinString(MakeWhitelist(), ","));
+
+ auto mock_verifier = std::make_unique<MockCertVerifier>();
+ mock_verifier->set_default_result(ERR_CERT_INVALID);
+ verifier_ = IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
+ command_line, kTestUserDataDirSwitch, std::move(mock_verifier));
+ }
+ ~IgnoreCertificateErrorsSPKIListFlagTest() override {}
+
+ protected:
+ std::unique_ptr<CertVerifier> verifier_;
+};
+
+// Only if both --user-data-dir and --ignore-certificate-errors-from-spki-list
+// are present, certificate verification is bypassed.
+TEST_P(IgnoreCertificateErrorsSPKIListFlagTest, TestUserDataDirSwitchRequired) {
+ scoped_refptr<X509Certificate> test_cert;
+ ASSERT_NO_FATAL_FAILURE(GetWhitelistedTestCert(&test_cert));
+ CertVerifyResult verify_result;
+ TestCompletionCallback callback;
+ std::unique_ptr<CertVerifier::Request> request;
+
+ if (GetParam()) {
+ EXPECT_THAT(callback.GetResult(verifier_->Verify(
+ MakeRequestParams(test_cert), nullptr, &verify_result,
+ callback.callback(), &request, NetLogWithSource())),
+ IsOk());
+ } else {
+ EXPECT_THAT(callback.GetResult(verifier_->Verify(
+ MakeRequestParams(test_cert), nullptr, &verify_result,
+ callback.callback(), &request, NetLogWithSource())),
+ IsError(ERR_CERT_INVALID));
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(WithUserDataDirSwitchPresent,
+ IgnoreCertificateErrorsSPKIListFlagTest,
+ ::testing::Bool());
+
+} // namespace network
diff --git a/chromium/services/network/keepalive_statistics_recorder.cc b/chromium/services/network/keepalive_statistics_recorder.cc
new file mode 100644
index 00000000000..96b7e0a15b7
--- /dev/null
+++ b/chromium/services/network/keepalive_statistics_recorder.cc
@@ -0,0 +1,95 @@
+// Copyright 2018 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/network/keepalive_statistics_recorder.h"
+
+#include <algorithm>
+
+#include "base/metrics/histogram_macros.h"
+
+namespace network {
+
+KeepaliveStatisticsRecorder::KeepaliveStatisticsRecorder() = default;
+KeepaliveStatisticsRecorder::~KeepaliveStatisticsRecorder() {
+ Shutdown();
+}
+
+void KeepaliveStatisticsRecorder::Register(int process_id) {
+ if (!is_active_)
+ return;
+ auto it = per_process_records_.find(process_id);
+ if (it == per_process_records_.end()) {
+ per_process_records_.insert(std::make_pair(process_id, PerProcessStats()));
+ return;
+ }
+
+ ++it->second.num_registrations;
+}
+
+void KeepaliveStatisticsRecorder::Unregister(int process_id) {
+ if (!is_active_)
+ return;
+ auto it = per_process_records_.find(process_id);
+ DCHECK(it != per_process_records_.end());
+
+ if (it->second.num_registrations == 1) {
+ DumpPerProcessStats(it->second);
+ per_process_records_.erase(it);
+ return;
+ }
+ --it->second.num_registrations;
+}
+
+void KeepaliveStatisticsRecorder::OnLoadStarted(int process_id) {
+ if (!is_active_)
+ return;
+ auto it = per_process_records_.find(process_id);
+ if (it != per_process_records_.end()) {
+ ++it->second.num_inflight_requests;
+ it->second.peak_inflight_requests = std::max(
+ it->second.peak_inflight_requests, it->second.num_inflight_requests);
+ }
+ ++num_inflight_requests_;
+ peak_inflight_requests_ =
+ std::max(peak_inflight_requests_, num_inflight_requests_);
+}
+
+void KeepaliveStatisticsRecorder::OnLoadFinished(int process_id) {
+ if (!is_active_)
+ return;
+ auto it = per_process_records_.find(process_id);
+ if (it != per_process_records_.end())
+ --it->second.num_inflight_requests;
+ --num_inflight_requests_;
+}
+
+void KeepaliveStatisticsRecorder::Shutdown() {
+ if (!is_active_)
+ return;
+ for (const auto& pair : per_process_records_)
+ DumpPerProcessStats(pair.second);
+ per_process_records_.clear();
+
+ UMA_HISTOGRAM_COUNTS_1000(
+ "Net.KeepaliveStatisticsRecorder.PeakInflightRequests",
+ peak_inflight_requests_);
+ is_active_ = false;
+}
+
+int KeepaliveStatisticsRecorder::NumInflightRequestsPerProcess(
+ int process_id) const {
+ auto it = per_process_records_.find(process_id);
+ if (it == per_process_records_.end())
+ return 0;
+ return it->second.num_inflight_requests;
+}
+
+void KeepaliveStatisticsRecorder::DumpPerProcessStats(
+ const PerProcessStats& stats) {
+ UMA_HISTOGRAM_COUNTS_100(
+ "Net.KeepaliveStatisticsRecorder.PeakInflightRequestsPerProcess",
+ stats.peak_inflight_requests);
+}
+
+} // namespace network
diff --git a/chromium/services/network/keepalive_statistics_recorder.h b/chromium/services/network/keepalive_statistics_recorder.h
new file mode 100644
index 00000000000..459a57377e5
--- /dev/null
+++ b/chromium/services/network/keepalive_statistics_recorder.h
@@ -0,0 +1,65 @@
+// Copyright 2018 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 SERVICES_NETWORK_KEEPALIVE_STATISTICS_RECORDER_H_
+#define SERVICES_NETWORK_KEEPALIVE_STATISTICS_RECORDER_H_
+
+#include <unordered_map>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+
+namespace network {
+
+// KeepaliveStatisticsRecorder keeps tracks of the number of inflight requests
+// with "keepalive" set and records UMA histograms.
+class COMPONENT_EXPORT(NETWORK_SERVICE) KeepaliveStatisticsRecorder
+ : public base::SupportsWeakPtr<KeepaliveStatisticsRecorder> {
+ public:
+ struct PerProcessStats {
+ int num_registrations = 1;
+ int num_inflight_requests = 0;
+ int peak_inflight_requests = 0;
+ };
+
+ KeepaliveStatisticsRecorder();
+ ~KeepaliveStatisticsRecorder();
+
+ // Registers / Unregisters |process_id| to this object. There can be multiple
+ // Register / Unregister calls with the same |process_id|, and this object
+ // thinks a process |p| is gone when the number of Register calls with |p|
+ // equals to the number of Unregister calls with |p|.
+ void Register(int process_id);
+ void Unregister(int process_id);
+
+ // Called when a request with keepalive set starts.
+ void OnLoadStarted(int process_id);
+ // Called when a request with keepalive set finishes.
+ void OnLoadFinished(int process_id);
+
+ void Shutdown();
+
+ const std::unordered_map<int, PerProcessStats>& per_process_records() const {
+ return per_process_records_;
+ }
+ int NumInflightRequestsPerProcess(int process_id) const;
+ int num_inflight_requests() const { return num_inflight_requests_; }
+ int peak_inflight_requests() const { return peak_inflight_requests_; }
+
+ private:
+ void DumpPerProcessStats(const PerProcessStats& stats);
+
+ std::unordered_map<int, PerProcessStats> per_process_records_;
+ int num_inflight_requests_ = 0;
+ int peak_inflight_requests_ = 0;
+ bool is_active_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(KeepaliveStatisticsRecorder);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_KEEPALIVE_STATISTICS_RECORDER_H_
diff --git a/chromium/services/network/keepalive_statistics_recorder_unittest.cc b/chromium/services/network/keepalive_statistics_recorder_unittest.cc
new file mode 100644
index 00000000000..f320faf4923
--- /dev/null
+++ b/chromium/services/network/keepalive_statistics_recorder_unittest.cc
@@ -0,0 +1,185 @@
+// Copyright 2018 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/network/keepalive_statistics_recorder.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+TEST(KeepaliveStatisticsRecorderTest, InitialState) {
+ KeepaliveStatisticsRecorder r;
+
+ EXPECT_EQ(0, r.num_inflight_requests());
+ EXPECT_EQ(0, r.peak_inflight_requests());
+ EXPECT_TRUE(r.per_process_records().empty());
+}
+
+TEST(KeepaliveStatisticsRecorderTest, Register) {
+ KeepaliveStatisticsRecorder r;
+ constexpr int process_id = 4;
+ r.Register(process_id);
+ EXPECT_EQ(0, r.num_inflight_requests());
+ EXPECT_EQ(0, r.peak_inflight_requests());
+
+ const auto& map = r.per_process_records();
+ EXPECT_EQ(1u, map.size());
+ auto it = map.find(process_id);
+ ASSERT_NE(it, map.end());
+ EXPECT_EQ(1, it->second.num_registrations);
+ EXPECT_EQ(0, it->second.num_inflight_requests);
+ EXPECT_EQ(0, it->second.peak_inflight_requests);
+}
+
+TEST(KeepaliveStatisticsRecorderTest, Unregister) {
+ KeepaliveStatisticsRecorder r;
+ constexpr int process_id = 4;
+ r.Register(process_id);
+ EXPECT_FALSE(r.per_process_records().empty());
+ r.Unregister(process_id);
+ EXPECT_TRUE(r.per_process_records().empty());
+}
+
+TEST(KeepaliveStatisticsRecorderTest, MultipleRegistration) {
+ KeepaliveStatisticsRecorder r;
+ constexpr int process1 = 4;
+ constexpr int process2 = 7;
+ constexpr int process3 = 8;
+
+ r.Register(process1);
+ r.Register(process2);
+ r.Register(process3);
+ r.Register(process1);
+ r.Register(process2);
+
+ r.Unregister(process1);
+ r.Unregister(process3);
+
+ const auto& map = r.per_process_records();
+ EXPECT_EQ(2u, map.size());
+ auto it1 = map.find(process1);
+ auto it2 = map.find(process2);
+ auto it3 = map.find(process3);
+
+ EXPECT_NE(it1, map.end());
+ EXPECT_EQ(1, it1->second.num_registrations);
+ EXPECT_EQ(0, it1->second.num_inflight_requests);
+ EXPECT_EQ(0, it1->second.peak_inflight_requests);
+ EXPECT_NE(it2, map.end());
+ EXPECT_EQ(2, it2->second.num_registrations);
+ EXPECT_EQ(0, it2->second.num_inflight_requests);
+ EXPECT_EQ(0, it2->second.peak_inflight_requests);
+ EXPECT_EQ(it3, map.end());
+}
+
+TEST(KeepaliveStatisticsRecorderTest, IssueOneRequest) {
+ KeepaliveStatisticsRecorder r;
+ constexpr int process = 4;
+
+ r.Register(process);
+ r.OnLoadStarted(process);
+ {
+ const auto& map = r.per_process_records();
+ EXPECT_EQ(1u, map.size());
+ auto it = map.find(process);
+ ASSERT_NE(it, map.end());
+ EXPECT_EQ(1, it->second.num_registrations);
+ EXPECT_EQ(1, it->second.num_inflight_requests);
+ EXPECT_EQ(1, it->second.peak_inflight_requests);
+
+ EXPECT_EQ(1, r.num_inflight_requests());
+ EXPECT_EQ(1, r.peak_inflight_requests());
+ }
+
+ r.OnLoadFinished(process);
+ {
+ const auto& map = r.per_process_records();
+ EXPECT_EQ(1u, map.size());
+ auto it = map.find(process);
+ ASSERT_NE(it, map.end());
+ EXPECT_EQ(1, it->second.num_registrations);
+ EXPECT_EQ(0, it->second.num_inflight_requests);
+ EXPECT_EQ(1, it->second.peak_inflight_requests);
+
+ EXPECT_EQ(0, r.num_inflight_requests());
+ EXPECT_EQ(1, r.peak_inflight_requests());
+ }
+}
+
+TEST(KeepaliveStatisticsRecorderTest, IssueRequests) {
+ KeepaliveStatisticsRecorder r;
+ constexpr int process1 = 2;
+ constexpr int process2 = 3;
+ constexpr int no_process = 0;
+
+ r.Register(process1);
+ r.Register(process1);
+ r.Register(process1);
+ r.Register(process2);
+ r.Register(process2);
+
+ r.OnLoadStarted(process1);
+ r.OnLoadStarted(process1);
+ r.OnLoadStarted(process2);
+ r.OnLoadStarted(process2);
+ r.OnLoadStarted(process2);
+ r.OnLoadStarted(process2);
+ r.OnLoadStarted(no_process);
+ r.OnLoadFinished(process2);
+ r.OnLoadFinished(process2);
+ r.OnLoadFinished(process2);
+ r.OnLoadStarted(process2);
+ r.OnLoadStarted(no_process);
+ r.OnLoadStarted(no_process);
+ r.OnLoadStarted(no_process);
+ r.OnLoadStarted(no_process);
+ r.OnLoadStarted(no_process);
+ r.OnLoadFinished(no_process);
+
+ const auto& map = r.per_process_records();
+ EXPECT_EQ(2u, map.size());
+ auto it1 = map.find(process1);
+ auto it2 = map.find(process2);
+ ASSERT_NE(it1, map.end());
+ EXPECT_EQ(3, it1->second.num_registrations);
+ EXPECT_EQ(2, it1->second.num_inflight_requests);
+ EXPECT_EQ(2, it1->second.peak_inflight_requests);
+
+ ASSERT_NE(it2, map.end());
+ EXPECT_EQ(2, it2->second.num_registrations);
+ EXPECT_EQ(2, it2->second.num_inflight_requests);
+ EXPECT_EQ(4, it2->second.peak_inflight_requests);
+
+ EXPECT_EQ(9, r.num_inflight_requests());
+ EXPECT_EQ(10, r.peak_inflight_requests());
+}
+
+TEST(KeepaliveStatisticsRecorderTest, ProcessReuse) {
+ KeepaliveStatisticsRecorder r;
+ constexpr int process = 2;
+
+ r.Register(process);
+ r.OnLoadStarted(process);
+ r.OnLoadStarted(process);
+ r.OnLoadStarted(process);
+ r.OnLoadFinished(process);
+ r.OnLoadFinished(process);
+ r.OnLoadFinished(process);
+ r.Unregister(process);
+
+ r.Register(process);
+ const auto& map = r.per_process_records();
+ EXPECT_EQ(1u, map.size());
+ auto it = map.find(process);
+ ASSERT_NE(it, map.end());
+ EXPECT_EQ(1, it->second.num_registrations);
+ EXPECT_EQ(0, it->second.num_inflight_requests);
+ EXPECT_EQ(0, it->second.peak_inflight_requests);
+}
+
+} // namespace
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/loader_util.cc b/chromium/services/network/loader_util.cc
index fa818d99d74..5bd04741e63 100644
--- a/chromium/services/network/public/cpp/loader_util.cc
+++ b/chromium/services/network/loader_util.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/loader_util.h"
+#include "services/network/loader_util.h"
#include <string>
diff --git a/chromium/services/network/public/cpp/loader_util.h b/chromium/services/network/loader_util.h
index 30bcb3d07f5..5f41716efc8 100644
--- a/chromium/services/network/public/cpp/loader_util.h
+++ b/chromium/services/network/loader_util.h
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_LOADER_UTIL_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_LOADER_UTIL_H_
+#ifndef SERVICES_NETWORK_LOADER_UTIL_H_
+#define SERVICES_NETWORK_LOADER_UTIL_H_
+#include "base/component_export.h"
#include "base/memory/ref_counted.h"
class GURL;
@@ -23,12 +24,14 @@ struct HttpRawRequestResponseInfo;
struct ResourceResponse;
// The name of the "Accept" header.
-extern const char kAcceptHeader[];
+COMPONENT_EXPORT(NETWORK_SERVICE) extern const char kAcceptHeader[];
// Accept header used for frame requests.
+COMPONENT_EXPORT(NETWORK_SERVICE)
extern const char kFrameAcceptHeader[];
// The default Accept header value to use if none were specified.
+COMPONENT_EXPORT(NETWORK_SERVICE)
extern const char kDefaultAcceptHeader[];
// Helper utilities shared between network service and ResourceDispatcherHost
@@ -36,18 +39,21 @@ extern const char kDefaultAcceptHeader[];
// Whether the response body should be sniffed in order to determine the MIME
// type of the response.
+COMPONENT_EXPORT(NETWORK_SERVICE)
bool ShouldSniffContent(net::URLRequest* url_request,
ResourceResponse* response);
// Fill HttpRawRequestResponseInfo based on raw headers.
+COMPONENT_EXPORT(NETWORK_SERVICE)
scoped_refptr<HttpRawRequestResponseInfo> BuildRawRequestResponseInfo(
const net::URLRequest& request,
const net::HttpRawRequestHeaders& raw_request_headers,
const net::HttpResponseHeaders* raw_response_headers);
// Returns the referrer based on the validity of the URL and command line flags.
+COMPONENT_EXPORT(NETWORK_SERVICE)
std::string ComputeReferrer(const GURL& referrer);
} // namespace network
-#endif // SERVICES_NETWORK_PUBLIC_CPP_LOADER_UTIL_H_
+#endif // SERVICES_NETWORK_LOADER_UTIL_H_
diff --git a/chromium/services/network/manifest.json b/chromium/services/network/manifest.json
new file mode 100644
index 00000000000..d14542c168e
--- /dev/null
+++ b/chromium/services/network/manifest.json
@@ -0,0 +1,23 @@
+{
+ "name": "network",
+ "display_name": "Network Service",
+ "sandbox_type": "network",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "network_service": [
+ "network::mojom::NetworkService"
+ ],
+ "test": [
+ "network::mojom::NetworkServiceTest"
+ ],
+ "url_loader": [
+ "network::mojom::URLLoaderFactory"
+ ]
+ },
+ "requires": {
+ "service_manager": [ "service_manager:all_users" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/network/network_change_manager.cc b/chromium/services/network/network_change_manager.cc
new file mode 100644
index 00000000000..00532f60199
--- /dev/null
+++ b/chromium/services/network/network_change_manager.cc
@@ -0,0 +1,67 @@
+// 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 "services/network/network_change_manager.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/logging.h"
+#include "net/base/network_change_notifier.h"
+
+namespace network {
+
+NetworkChangeManager::NetworkChangeManager(
+ std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier)
+ : network_change_notifier_(std::move(network_change_notifier)) {
+ net::NetworkChangeNotifier::AddNetworkChangeObserver(this);
+ connection_type_ =
+ mojom::ConnectionType(net::NetworkChangeNotifier::GetConnectionType());
+}
+
+NetworkChangeManager::~NetworkChangeManager() {
+ net::NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
+}
+
+void NetworkChangeManager::AddRequest(
+ mojom::NetworkChangeManagerRequest request) {
+ bindings_.AddBinding(this, std::move(request));
+}
+
+void NetworkChangeManager::RequestNotifications(
+ mojom::NetworkChangeManagerClientPtr client_ptr) {
+ client_ptr.set_connection_error_handler(
+ base::Bind(&NetworkChangeManager::NotificationPipeBroken,
+ // base::Unretained is safe as destruction of the
+ // NetworkChangeManager will also destroy the
+ // |clients_| list (which this object will be
+ // inserted into, below), which will destroy the
+ // client_ptr, rendering this callback moot.
+ base::Unretained(this), base::Unretained(client_ptr.get())));
+ client_ptr->OnInitialConnectionType(connection_type_);
+ clients_.push_back(std::move(client_ptr));
+}
+
+size_t NetworkChangeManager::GetNumClientsForTesting() const {
+ return clients_.size();
+}
+
+void NetworkChangeManager::NotificationPipeBroken(
+ mojom::NetworkChangeManagerClient* client) {
+ clients_.erase(
+ std::find_if(clients_.begin(), clients_.end(),
+ [client](mojom::NetworkChangeManagerClientPtr& ptr) {
+ return ptr.get() == client;
+ }));
+}
+
+void NetworkChangeManager::OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType type) {
+ connection_type_ = mojom::ConnectionType(type);
+ for (const auto& client : clients_) {
+ client->OnNetworkChanged(connection_type_);
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/network_change_manager.h b/chromium/services/network/network_change_manager.h
new file mode 100644
index 00000000000..0800582fff2
--- /dev/null
+++ b/chromium/services/network/network_change_manager.h
@@ -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.
+
+#ifndef SERVICES_NETWORK_NETWORK_CHANGE_MANAGER_H_
+#define SERVICES_NETWORK_NETWORK_CHANGE_MANAGER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "net/base/network_change_notifier.h"
+#include "services/network/public/mojom/network_change_manager.mojom.h"
+
+namespace network {
+
+// Implementation of mojom::NetworkChangeManager. All accesses to this class are
+// done through mojo on the main thread. This registers itself to receive
+// broadcasts from net::NetworkChangeNotifier and rebroadcasts the notifications
+// to mojom::NetworkChangeManagerClients through mojo pipes.
+class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkChangeManager
+ : public mojom::NetworkChangeManager,
+ public net::NetworkChangeNotifier::NetworkChangeObserver {
+ public:
+ // If |network_change_notifier| is not null, |this| will take ownership of it.
+ // Otherwise, the global net::NetworkChangeNotifier will be used.
+ explicit NetworkChangeManager(
+ std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier);
+
+ ~NetworkChangeManager() override;
+
+ // Binds a NetworkChangeManager request to this object. Mojo messages
+ // coming through the associated pipe will be served by this object.
+ void AddRequest(mojom::NetworkChangeManagerRequest request);
+
+ // mojom::NetworkChangeManager implementation:
+ void RequestNotifications(
+ mojom::NetworkChangeManagerClientPtr client_ptr) override;
+
+ size_t GetNumClientsForTesting() const;
+
+ private:
+ // Handles connection errors on notification pipes.
+ void NotificationPipeBroken(mojom::NetworkChangeManagerClient* client);
+
+ // net::NetworkChangeNotifier::NetworkChangeObserver implementation:
+ void OnNetworkChanged(
+ net::NetworkChangeNotifier::ConnectionType type) override;
+
+ std::unique_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+ mojo::BindingSet<mojom::NetworkChangeManager> bindings_;
+ std::vector<mojom::NetworkChangeManagerClientPtr> clients_;
+ mojom::ConnectionType connection_type_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkChangeManager);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_NETWORK_CHANGE_MANAGER_H_
diff --git a/chromium/services/network/network_change_manager_unittest.cc b/chromium/services/network/network_change_manager_unittest.cc
new file mode 100644
index 00000000000..0359e811c0a
--- /dev/null
+++ b/chromium/services/network/network_change_manager_unittest.cc
@@ -0,0 +1,220 @@
+// 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 "services/network/network_change_manager.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "net/base/network_change_notifier.h"
+#include "services/network/public/mojom/network_change_manager.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+// Type of notification expected in test.
+enum NotificationType {
+ // Default value.
+ NONE,
+ // OnInitialConnectionType() notification.
+ INITIAL,
+ // OnNetworkChanged() notification.
+ NETWORK_CHANGED,
+};
+
+class TestNetworkChangeManagerClient
+ : public mojom::NetworkChangeManagerClient {
+ public:
+ explicit TestNetworkChangeManagerClient(
+ NetworkChangeManager* network_change_manager)
+ : num_network_changed_(0),
+ run_loop_(std::make_unique<base::RunLoop>()),
+ notification_type_to_wait_(NONE),
+ connection_type_(mojom::ConnectionType::CONNECTION_UNKNOWN),
+ binding_(this) {
+ mojom::NetworkChangeManagerPtr manager_ptr;
+ mojom::NetworkChangeManagerRequest request(mojo::MakeRequest(&manager_ptr));
+ network_change_manager->AddRequest(std::move(request));
+
+ mojom::NetworkChangeManagerClientPtr client_ptr;
+ mojom::NetworkChangeManagerClientRequest client_request(
+ mojo::MakeRequest(&client_ptr));
+ binding_.Bind(std::move(client_request));
+ manager_ptr->RequestNotifications(std::move(client_ptr));
+ }
+
+ ~TestNetworkChangeManagerClient() override {}
+
+ // NetworkChangeManagerClient implementation:
+ void OnInitialConnectionType(mojom::ConnectionType type) override {
+ connection_type_ = type;
+ if (notification_type_to_wait_ == INITIAL)
+ run_loop_->Quit();
+ }
+
+ void OnNetworkChanged(mojom::ConnectionType type) override {
+ num_network_changed_++;
+ connection_type_ = type;
+ if (notification_type_to_wait_ == NETWORK_CHANGED)
+ run_loop_->Quit();
+ }
+
+ // Returns the number of OnNetworkChanged() notifications.
+ size_t num_network_changed() const { return num_network_changed_; }
+
+ void WaitForNotification(NotificationType notification_type) {
+ notification_type_to_wait_ = notification_type;
+ run_loop_->Run();
+ run_loop_.reset(new base::RunLoop());
+ }
+
+ mojom::ConnectionType connection_type() const { return connection_type_; }
+
+ private:
+ size_t num_network_changed_;
+ std::unique_ptr<base::RunLoop> run_loop_;
+ NotificationType notification_type_to_wait_;
+ mojom::ConnectionType connection_type_;
+ mojo::Binding<mojom::NetworkChangeManagerClient> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestNetworkChangeManagerClient);
+};
+
+} // namespace
+
+class NetworkChangeManagerTest : public testing::Test {
+ public:
+ NetworkChangeManagerTest()
+ : network_change_manager_(new NetworkChangeManager(
+ base::WrapUnique(net::NetworkChangeNotifier::CreateMock()))) {
+ network_change_manager_client_ =
+ std::make_unique<TestNetworkChangeManagerClient>(
+ network_change_manager_.get());
+ }
+
+ ~NetworkChangeManagerTest() override {}
+
+ TestNetworkChangeManagerClient* network_change_manager_client() {
+ return network_change_manager_client_.get();
+ }
+
+ NetworkChangeManager* network_change_manager() const {
+ return network_change_manager_.get();
+ }
+
+ void SimulateNetworkChange(net::NetworkChangeNotifier::ConnectionType type) {
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(type);
+ }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<NetworkChangeManager> network_change_manager_;
+ std::unique_ptr<TestNetworkChangeManagerClient>
+ network_change_manager_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkChangeManagerTest);
+};
+
+TEST_F(NetworkChangeManagerTest, ClientNotified) {
+ // Simulate a new network change.
+ SimulateNetworkChange(net::NetworkChangeNotifier::CONNECTION_3G);
+ network_change_manager_client()->WaitForNotification(NETWORK_CHANGED);
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_3G,
+ network_change_manager_client()->connection_type());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, network_change_manager_client()->num_network_changed());
+}
+
+TEST_F(NetworkChangeManagerTest, OneClientPipeBroken) {
+ auto network_change_manager_client2 =
+ std::make_unique<TestNetworkChangeManagerClient>(
+ network_change_manager());
+
+ // Simulate a network change.
+ SimulateNetworkChange(net::NetworkChangeNotifier::CONNECTION_WIFI);
+
+ network_change_manager_client()->WaitForNotification(NETWORK_CHANGED);
+ network_change_manager_client2->WaitForNotification(NETWORK_CHANGED);
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_WIFI,
+ network_change_manager_client2->connection_type());
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_EQ(2u, network_change_manager()->GetNumClientsForTesting());
+
+ EXPECT_EQ(1u, network_change_manager_client()->num_network_changed());
+ EXPECT_EQ(1u, network_change_manager_client2->num_network_changed());
+ network_change_manager_client2.reset();
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(1u, network_change_manager()->GetNumClientsForTesting());
+
+ // Simulate a second network change, and the remaining client should be
+ // notified.
+ SimulateNetworkChange(net::NetworkChangeNotifier::CONNECTION_2G);
+
+ network_change_manager_client()->WaitForNotification(NETWORK_CHANGED);
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_2G,
+ network_change_manager_client()->connection_type());
+ EXPECT_EQ(2u, network_change_manager_client()->num_network_changed());
+}
+
+TEST_F(NetworkChangeManagerTest, NewClientReceivesCurrentType) {
+ // Simulate a network change.
+ SimulateNetworkChange(net::NetworkChangeNotifier::CONNECTION_BLUETOOTH);
+
+ network_change_manager_client()->WaitForNotification(NETWORK_CHANGED);
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_BLUETOOTH,
+ network_change_manager_client()->connection_type());
+ base::RunLoop().RunUntilIdle();
+
+ // Register a new client after the network change and it should receive the
+ // up-to-date connection type.
+ TestNetworkChangeManagerClient network_change_manager_client2(
+ network_change_manager());
+ network_change_manager_client2.WaitForNotification(INITIAL);
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_BLUETOOTH,
+ network_change_manager_client2.connection_type());
+}
+
+TEST(NetworkChangeConnectionTypeTest, ConnectionTypeEnumMatch) {
+ for (int typeInt = net::NetworkChangeNotifier::CONNECTION_UNKNOWN;
+ typeInt != net::NetworkChangeNotifier::CONNECTION_LAST; typeInt++) {
+ mojom::ConnectionType mojoType = mojom::ConnectionType(typeInt);
+ switch (typeInt) {
+ case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_UNKNOWN, mojoType);
+ break;
+ case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_ETHERNET, mojoType);
+ break;
+ case net::NetworkChangeNotifier::CONNECTION_WIFI:
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_WIFI, mojoType);
+ break;
+ case net::NetworkChangeNotifier::CONNECTION_2G:
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_2G, mojoType);
+ break;
+ case net::NetworkChangeNotifier::CONNECTION_3G:
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_3G, mojoType);
+ break;
+ case net::NetworkChangeNotifier::CONNECTION_4G:
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_4G, mojoType);
+ break;
+ case net::NetworkChangeNotifier::CONNECTION_NONE:
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_NONE, mojoType);
+ break;
+ case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_BLUETOOTH, mojoType);
+ EXPECT_EQ(mojom::ConnectionType::CONNECTION_LAST, mojoType);
+ break;
+ }
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/network_context.cc b/chromium/services/network/network_context.cc
new file mode 100644
index 00000000000..b681ac5f60c
--- /dev/null
+++ b/chromium/services/network/network_context.cc
@@ -0,0 +1,476 @@
+// 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 "services/network/network_context.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/optional.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "build/build_config.h"
+#include "components/cookie_config/cookie_store_util.h"
+#include "components/network_session_configurator/browser/network_session_configurator.h"
+#include "components/network_session_configurator/common/network_switches.h"
+#include "components/prefs/json_pref_store.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/pref_service_factory.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/dns/host_resolver.h"
+#include "net/dns/mapped_host_resolver.h"
+#include "net/extras/sqlite/sqlite_channel_id_store.h"
+#include "net/extras/sqlite/sqlite_persistent_cookie_store.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_server_properties.h"
+#include "net/http/http_server_properties_manager.h"
+#include "net/http/http_transaction_factory.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/reporting/reporting_policy.h"
+#include "net/ssl/channel_id_service.h"
+#include "net/ssl/default_channel_id_store.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "services/network/http_server_properties_pref_delegate.h"
+#include "services/network/ignore_errors_cert_verifier.h"
+#include "services/network/network_service.h"
+#include "services/network/proxy_config_service_mojo.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "services/network/resource_scheduler_client.h"
+#include "services/network/restricted_cookie_manager.h"
+#include "services/network/throttling/network_conditions.h"
+#include "services/network/throttling/throttling_controller.h"
+#include "services/network/throttling/throttling_network_transaction_factory.h"
+#include "services/network/udp_socket_factory.h"
+#include "services/network/url_loader.h"
+#include "services/network/url_loader_factory.h"
+#include "services/network/url_request_context_builder_mojo.h"
+
+namespace network {
+
+namespace {
+
+net::CertVerifier* g_cert_verifier_for_testing = nullptr;
+
+// A CertVerifier that forwards all requests to |g_cert_verifier_for_testing|.
+// This is used to allow NetworkContexts to have their own
+// std::unique_ptr<net::CertVerifier> while forwarding calls to the shared
+// verifier.
+class WrappedTestingCertVerifier : public net::CertVerifier {
+ public:
+ ~WrappedTestingCertVerifier() override = default;
+
+ // CertVerifier implementation
+ int Verify(const RequestParams& params,
+ net::CRLSet* crl_set,
+ net::CertVerifyResult* verify_result,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<Request>* out_req,
+ const net::NetLogWithSource& net_log) override {
+ verify_result->Reset();
+ if (!g_cert_verifier_for_testing)
+ return net::ERR_FAILED;
+ return g_cert_verifier_for_testing->Verify(params, crl_set, verify_result,
+ callback, out_req, net_log);
+ }
+};
+
+} // namespace
+
+constexpr bool NetworkContext::enable_resource_scheduler_;
+
+NetworkContext::NetworkContext(NetworkService* network_service,
+ mojom::NetworkContextRequest request,
+ mojom::NetworkContextParamsPtr params)
+ : network_service_(network_service),
+ params_(std::move(params)),
+ binding_(this, std::move(request)) {
+ url_request_context_owner_ = MakeURLRequestContext(params_.get());
+ url_request_context_getter_ =
+ url_request_context_owner_.url_request_context_getter;
+ cookie_manager_ =
+ std::make_unique<CookieManager>(GetURLRequestContext()->cookie_store());
+ network_service_->RegisterNetworkContext(this);
+ binding_.set_connection_error_handler(base::BindOnce(
+ &NetworkContext::OnConnectionError, base::Unretained(this)));
+ resource_scheduler_ =
+ std::make_unique<ResourceScheduler>(enable_resource_scheduler_);
+}
+
+// TODO(mmenke): Share URLRequestContextBulder configuration between two
+// constructors. Can only share them once consumer code is ready for its
+// corresponding options to be overwritten.
+NetworkContext::NetworkContext(
+ NetworkService* network_service,
+ mojom::NetworkContextRequest request,
+ mojom::NetworkContextParamsPtr params,
+ std::unique_ptr<URLRequestContextBuilderMojo> builder)
+ : network_service_(network_service),
+ params_(std::move(params)),
+ binding_(this, std::move(request)) {
+ url_request_context_owner_ = ApplyContextParamsToBuilder(
+ builder.get(), params_.get(), network_service->quic_disabled(),
+ network_service->net_log());
+ url_request_context_getter_ =
+ url_request_context_owner_.url_request_context_getter;
+ network_service_->RegisterNetworkContext(this);
+ cookie_manager_ =
+ std::make_unique<CookieManager>(GetURLRequestContext()->cookie_store());
+ resource_scheduler_ =
+ std::make_unique<ResourceScheduler>(enable_resource_scheduler_);
+}
+
+NetworkContext::NetworkContext(
+ NetworkService* network_service,
+ mojom::NetworkContextRequest request,
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter)
+ : network_service_(network_service),
+ url_request_context_getter_(std::move(url_request_context_getter)),
+ binding_(this, std::move(request)),
+ cookie_manager_(std::make_unique<CookieManager>(
+ url_request_context_getter_->GetURLRequestContext()
+ ->cookie_store())) {
+ // May be nullptr in tests.
+ if (network_service_)
+ network_service_->RegisterNetworkContext(this);
+ resource_scheduler_ =
+ std::make_unique<ResourceScheduler>(enable_resource_scheduler_);
+}
+
+NetworkContext::~NetworkContext() {
+ // May be nullptr in tests.
+ if (network_service_)
+ network_service_->DeregisterNetworkContext(this);
+}
+
+std::unique_ptr<NetworkContext> NetworkContext::CreateForTesting() {
+ return base::WrapUnique(
+ new NetworkContext(mojom::NetworkContextParams::New()));
+}
+
+void NetworkContext::SetCertVerifierForTesting(
+ net::CertVerifier* cert_verifier) {
+ g_cert_verifier_for_testing = cert_verifier;
+}
+
+void NetworkContext::CreateURLLoaderFactory(
+ mojom::URLLoaderFactoryRequest request,
+ uint32_t process_id,
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client) {
+ loader_factory_bindings_.AddBinding(
+ std::make_unique<URLLoaderFactory>(this, process_id,
+ std::move(resource_scheduler_client)),
+ std::move(request));
+}
+
+void NetworkContext::CreateURLLoaderFactory(
+ mojom::URLLoaderFactoryRequest request,
+ uint32_t process_id) {
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client;
+ if (process_id != 0) {
+ // Zero process ID means it's from the browser process and we don't want
+ // to throttle the requests.
+ resource_scheduler_client = base::MakeRefCounted<ResourceSchedulerClient>(
+ process_id, ++current_resource_scheduler_client_id_,
+ resource_scheduler_.get(),
+ GetURLRequestContext()->network_quality_estimator());
+ }
+ CreateURLLoaderFactory(std::move(request), process_id,
+ std::move(resource_scheduler_client));
+}
+
+void NetworkContext::GetCookieManager(mojom::CookieManagerRequest request) {
+ cookie_manager_->AddRequest(std::move(request));
+}
+
+void NetworkContext::GetRestrictedCookieManager(
+ mojom::RestrictedCookieManagerRequest request,
+ int32_t render_process_id,
+ int32_t render_frame_id) {
+ // TODO(crbug.com/729800): RestrictedCookieManager should own its bindings
+ // and NetworkContext should own the RestrictedCookieManager
+ // instances.
+ mojo::MakeStrongBinding(std::make_unique<RestrictedCookieManager>(
+ GetURLRequestContext()->cookie_store(),
+ render_process_id, render_frame_id),
+ std::move(request));
+}
+
+void NetworkContext::DisableQuic() {
+ GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->DisableQuic();
+}
+
+net::URLRequestContext* NetworkContext::GetURLRequestContext() {
+ return url_request_context_getter_->GetURLRequestContext();
+}
+
+void NetworkContext::Cleanup() {
+ // The NetworkService is going away, so have to destroy the
+ // net::URLRequestContext held by this NetworkContext.
+ delete this;
+}
+
+NetworkContext::NetworkContext(mojom::NetworkContextParamsPtr params)
+ : network_service_(nullptr), params_(std::move(params)), binding_(this) {
+ url_request_context_owner_ = MakeURLRequestContext(params_.get());
+ url_request_context_getter_ =
+ url_request_context_owner_.url_request_context_getter;
+
+ resource_scheduler_ =
+ std::make_unique<ResourceScheduler>(enable_resource_scheduler_);
+}
+
+void NetworkContext::OnConnectionError() {
+ // Don't delete |this| in response to connection errors when it was created by
+ // CreateForTesting.
+ if (network_service_)
+ delete this;
+}
+
+URLRequestContextOwner NetworkContext::MakeURLRequestContext(
+ mojom::NetworkContextParams* network_context_params) {
+ URLRequestContextBuilderMojo builder;
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+
+ if (command_line->HasSwitch(switches::kHostResolverRules)) {
+ std::unique_ptr<net::HostResolver> host_resolver(
+ net::HostResolver::CreateDefaultResolver(nullptr));
+ std::unique_ptr<net::MappedHostResolver> remapped_host_resolver(
+ new net::MappedHostResolver(std::move(host_resolver)));
+ remapped_host_resolver->SetRulesFromString(
+ command_line->GetSwitchValueASCII(switches::kHostResolverRules));
+ builder.set_host_resolver(std::move(remapped_host_resolver));
+ }
+ builder.set_accept_language("en-us,en");
+ builder.set_user_agent(network_context_params->user_agent);
+
+ // The cookie configuration is in this method, which is only used by the
+ // network process, and not ApplyContextParamsToBuilder which is used by the
+ // browser as well. This is because this code path doesn't handle encryption
+ // and other configuration done in QuotaPolicyCookieStore yet (and we still
+ // have to figure out which of the latter needs to move to the network
+ // process). TODO: http://crbug.com/789644
+ if (network_context_params->cookie_path) {
+ DCHECK(network_context_params->channel_id_path);
+ net::CookieCryptoDelegate* crypto_delegate = nullptr;
+
+ scoped_refptr<base::SequencedTaskRunner> client_task_runner =
+ base::MessageLoop::current()->task_runner();
+ scoped_refptr<base::SequencedTaskRunner> background_task_runner =
+ base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::BACKGROUND,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN});
+
+ scoped_refptr<net::SQLiteChannelIDStore> channel_id_db =
+ new net::SQLiteChannelIDStore(
+ network_context_params->channel_id_path.value(),
+ background_task_runner);
+ std::unique_ptr<net::ChannelIDService> channel_id_service(
+ std::make_unique<net::ChannelIDService>(
+ new net::DefaultChannelIDStore(channel_id_db.get())));
+
+ scoped_refptr<net::SQLitePersistentCookieStore> sqlite_store(
+ new net::SQLitePersistentCookieStore(
+ network_context_params->cookie_path.value(), client_task_runner,
+ background_task_runner,
+ network_context_params->restore_old_session_cookies,
+ crypto_delegate));
+
+ std::unique_ptr<net::CookieMonster> cookie_store =
+ std::make_unique<net::CookieMonster>(sqlite_store.get(),
+ channel_id_service.get());
+ if (network_context_params->persist_session_cookies)
+ cookie_store->SetPersistSessionCookies(true);
+
+ cookie_store->SetChannelIDServiceID(channel_id_service->GetUniqueID());
+ builder.SetCookieAndChannelIdStores(std::move(cookie_store),
+ std::move(channel_id_service));
+ } else {
+ DCHECK(!network_context_params->restore_old_session_cookies);
+ DCHECK(!network_context_params->persist_session_cookies);
+ }
+
+ if (g_cert_verifier_for_testing) {
+ builder.SetCertVerifier(std::make_unique<WrappedTestingCertVerifier>());
+ } else {
+ std::unique_ptr<net::CertVerifier> cert_verifier =
+ net::CertVerifier::CreateDefault();
+ builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier(
+ *command_line, nullptr, std::move(cert_verifier)));
+ }
+
+ // |network_service_| may be nullptr in tests.
+ return ApplyContextParamsToBuilder(
+ &builder, network_context_params,
+ network_service_ ? network_service_->quic_disabled() : false,
+ network_service_ ? network_service_->net_log() : nullptr);
+}
+
+URLRequestContextOwner NetworkContext::ApplyContextParamsToBuilder(
+ URLRequestContextBuilderMojo* builder,
+ mojom::NetworkContextParams* network_context_params,
+ bool quic_disabled,
+ net::NetLog* net_log) {
+ if (net_log)
+ builder->set_net_log(net_log);
+
+ builder->set_enable_brotli(network_context_params->enable_brotli);
+ if (network_context_params->context_name)
+ builder->set_name(*network_context_params->context_name);
+
+ if (network_context_params->proxy_resolver_factory) {
+ builder->SetMojoProxyResolverFactory(
+ proxy_resolver::mojom::ProxyResolverFactoryPtr(
+ std::move(network_context_params->proxy_resolver_factory)));
+ }
+
+ if (!network_context_params->http_cache_enabled) {
+ builder->DisableHttpCache();
+ } else {
+ net::URLRequestContextBuilder::HttpCacheParams cache_params;
+ cache_params.max_size = network_context_params->http_cache_max_size;
+ if (!network_context_params->http_cache_path) {
+ cache_params.type =
+ net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY;
+ } else {
+ cache_params.path = *network_context_params->http_cache_path;
+ cache_params.type = network_session_configurator::ChooseCacheType(
+ *base::CommandLine::ForCurrentProcess());
+ }
+
+ builder->EnableHttpCache(cache_params);
+ }
+
+ if (!network_context_params->initial_proxy_config &&
+ !network_context_params->proxy_config_client_request.is_pending()) {
+ network_context_params->initial_proxy_config =
+ net::ProxyConfig::CreateDirect();
+ }
+ builder->set_proxy_config_service(std::make_unique<ProxyConfigServiceMojo>(
+ std::move(network_context_params->proxy_config_client_request),
+ std::move(network_context_params->initial_proxy_config),
+ std::move(network_context_params->proxy_config_poller_client)));
+
+ std::unique_ptr<PrefService> pref_service;
+ if (network_context_params->http_server_properties_path) {
+ scoped_refptr<JsonPrefStore> json_pref_store(new JsonPrefStore(
+ *network_context_params->http_server_properties_path,
+ base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskShutdownBehavior::BLOCK_SHUTDOWN,
+ base::TaskPriority::BACKGROUND})));
+ PrefServiceFactory pref_service_factory;
+ pref_service_factory.set_user_prefs(json_pref_store);
+ pref_service_factory.set_async(true);
+ scoped_refptr<PrefRegistrySimple> pref_registry(new PrefRegistrySimple());
+ HttpServerPropertiesPrefDelegate::RegisterPrefs(pref_registry.get());
+ pref_service = pref_service_factory.Create(pref_registry.get());
+
+ builder->SetHttpServerProperties(
+ std::make_unique<net::HttpServerPropertiesManager>(
+ std::make_unique<HttpServerPropertiesPrefDelegate>(
+ pref_service.get()),
+ net_log));
+ }
+
+ builder->set_data_enabled(network_context_params->enable_data_url_support);
+#if !BUILDFLAG(DISABLE_FILE_SUPPORT)
+ builder->set_file_enabled(network_context_params->enable_file_url_support);
+#else // BUILDFLAG(DISABLE_FILE_SUPPORT)
+ DCHECK(!network_context_params->enable_file_url_support);
+#endif
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+ builder->set_ftp_enabled(network_context_params->enable_ftp_url_support);
+#else // BUILDFLAG(DISABLE_FTP_SUPPORT)
+ DCHECK(!network_context_params->enable_ftp_url_support);
+#endif
+
+#if BUILDFLAG(ENABLE_REPORTING)
+ if (base::FeatureList::IsEnabled(features::kReporting))
+ builder->set_reporting_policy(std::make_unique<net::ReportingPolicy>());
+ else
+ builder->set_reporting_policy(nullptr);
+
+ builder->set_network_error_logging_enabled(
+ base::FeatureList::IsEnabled(features::kNetworkErrorLogging));
+#endif // BUILDFLAG(ENABLE_REPORTING)
+
+ net::HttpNetworkSession::Params session_params;
+ bool is_quic_force_disabled = false;
+ if (quic_disabled)
+ is_quic_force_disabled = true;
+
+ network_session_configurator::ParseCommandLineAndFieldTrials(
+ *base::CommandLine::ForCurrentProcess(), is_quic_force_disabled,
+ network_context_params->quic_user_agent_id, &session_params);
+
+ session_params.http_09_on_non_default_ports_enabled =
+ network_context_params->http_09_on_non_default_ports_enabled;
+
+ builder->set_http_network_session_params(session_params);
+
+ builder->SetCreateHttpTransactionFactoryCallback(
+ base::BindOnce([](net::HttpNetworkSession* session)
+ -> std::unique_ptr<net::HttpTransactionFactory> {
+ return std::make_unique<ThrottlingNetworkTransactionFactory>(session);
+ }));
+ return URLRequestContextOwner(std::move(pref_service), builder->Build());
+}
+
+void NetworkContext::ClearNetworkingHistorySince(
+ base::Time time,
+ base::OnceClosure completion_callback) {
+ // TODO(mmenke): Neither of these methods waits until the changes have been
+ // commited to disk. They probably should, as most similar methods net/
+ // exposes do.
+
+ // Completes synchronously.
+ GetURLRequestContext()->transport_security_state()->DeleteAllDynamicDataSince(
+ time);
+
+ GetURLRequestContext()->http_server_properties()->Clear(
+ std::move(completion_callback));
+}
+
+void NetworkContext::SetNetworkConditions(
+ const std::string& profile_id,
+ mojom::NetworkConditionsPtr conditions) {
+ std::unique_ptr<NetworkConditions> network_conditions;
+ if (conditions) {
+ network_conditions.reset(new NetworkConditions(
+ conditions->offline, conditions->latency.InMillisecondsF(),
+ conditions->download_throughput, conditions->upload_throughput));
+ }
+ ThrottlingController::SetConditions(profile_id,
+ std::move(network_conditions));
+}
+
+void NetworkContext::CreateUDPSocket(mojom::UDPSocketRequest request,
+ mojom::UDPSocketReceiverPtr receiver) {
+ if (!udp_socket_factory_)
+ udp_socket_factory_ = std::make_unique<UDPSocketFactory>();
+ udp_socket_factory_->CreateUDPSocket(std::move(request), std::move(receiver));
+}
+
+void NetworkContext::AddHSTSForTesting(const std::string& host,
+ base::Time expiry,
+ bool include_subdomains,
+ AddHSTSForTestingCallback callback) {
+ net::TransportSecurityState* state =
+ GetURLRequestContext()->transport_security_state();
+ state->AddHSTS(host, expiry, include_subdomains);
+ std::move(callback).Run();
+}
+
+} // namespace network
diff --git a/chromium/services/network/network_context.h b/chromium/services/network/network_context.h
new file mode 100644
index 00000000000..b39c97b3296
--- /dev/null
+++ b/chromium/services/network/network_context.h
@@ -0,0 +1,174 @@
+// 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 SERVICES_NETWORK_NETWORK_CONTEXT_H_
+#define SERVICES_NETWORK_NETWORK_CONTEXT_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
+#include "services/network/cookie_manager.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/url_request_context_owner.h"
+
+namespace net {
+class CertVerifier;
+class URLRequestContext;
+} // namespace net
+
+namespace network {
+class NetworkService;
+class ResourceScheduler;
+class ResourceSchedulerClient;
+class UDPSocketFactory;
+class URLRequestContextBuilderMojo;
+
+// A NetworkContext creates and manages access to a URLRequestContext.
+//
+// When the network service is enabled, NetworkContexts are created through
+// NetworkService's mojo interface and are owned jointly by the NetworkService
+// and the NetworkContextPtr used to talk to them, and the NetworkContext is
+// destroyed when either one is torn down.
+//
+// When the network service is disabled, NetworkContexts may be created through
+// NetworkService::CreateNetworkContextWithBuilder, and take in a
+// URLRequestContextBuilderMojo to seed construction of the NetworkContext's
+// URLRequestContext. When that happens, the consumer takes ownership of the
+// NetworkContext directly, has direct access to its URLRequestContext, and is
+// responsible for destroying it before the NetworkService.
+class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkContext
+ : public mojom::NetworkContext {
+ public:
+ NetworkContext(NetworkService* network_service,
+ mojom::NetworkContextRequest request,
+ mojom::NetworkContextParamsPtr params);
+
+ // Temporary constructor that allows creating an in-process NetworkContext
+ // with a pre-populated URLRequestContextBuilderMojo.
+ NetworkContext(NetworkService* network_service,
+ mojom::NetworkContextRequest request,
+ mojom::NetworkContextParamsPtr params,
+ std::unique_ptr<URLRequestContextBuilderMojo> builder);
+
+ // Creates a NetworkContext that wraps a consumer-provided URLRequestContext
+ // that the NetworkContext does not own.
+ // TODO(mmenke): Remove this constructor when the network service ships.
+ NetworkContext(
+ NetworkService* network_service,
+ mojom::NetworkContextRequest request,
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter);
+
+ ~NetworkContext() override;
+
+ static std::unique_ptr<NetworkContext> CreateForTesting();
+
+ // Sets a global CertVerifier to use when initializing all profiles.
+ static void SetCertVerifierForTesting(net::CertVerifier* cert_verifier);
+
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter() {
+ return url_request_context_getter_;
+ }
+
+ NetworkService* network_service() { return network_service_; }
+
+ ResourceScheduler* resource_scheduler() { return resource_scheduler_.get(); }
+
+ // Creates a URLLoaderFactory with a ResourceSchedulerClient specified. This
+ // is used to reuse the existing ResourceSchedulerClient for cloned
+ // URLLoaderFactory.
+ void CreateURLLoaderFactory(
+ mojom::URLLoaderFactoryRequest request,
+ uint32_t process_id,
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client);
+
+ // mojom::NetworkContext implementation:
+ void CreateURLLoaderFactory(mojom::URLLoaderFactoryRequest request,
+ uint32_t process_id) override;
+ void GetCookieManager(mojom::CookieManagerRequest request) override;
+ void GetRestrictedCookieManager(mojom::RestrictedCookieManagerRequest request,
+ int32_t render_process_id,
+ int32_t render_frame_id) override;
+ void ClearNetworkingHistorySince(
+ base::Time time,
+ base::OnceClosure completion_callback) override;
+ void SetNetworkConditions(const std::string& profile_id,
+ mojom::NetworkConditionsPtr conditions) override;
+ void CreateUDPSocket(mojom::UDPSocketRequest request,
+ mojom::UDPSocketReceiverPtr receiver) override;
+ void AddHSTSForTesting(const std::string& host,
+ base::Time expiry,
+ bool include_subdomains,
+ AddHSTSForTestingCallback callback) override;
+
+ net::URLRequestContext* GetURLRequestContext();
+
+ // Called when the associated NetworkService is going away. Guaranteed to
+ // destroy NetworkContext's URLRequestContext.
+ void Cleanup();
+
+ // Disables use of QUIC by the NetworkContext.
+ void DisableQuic();
+
+ // Applies the values in |network_context_params| to |builder|, and builds
+ // the URLRequestContext.
+ static URLRequestContextOwner ApplyContextParamsToBuilder(
+ URLRequestContextBuilderMojo* builder,
+ mojom::NetworkContextParams* network_context_params,
+ bool quic_disabled,
+ net::NetLog* net_log);
+
+ private:
+ // Constructor only used in tests.
+ explicit NetworkContext(mojom::NetworkContextParamsPtr params);
+
+ // On connection errors the NetworkContext destroys itself.
+ void OnConnectionError();
+
+ URLRequestContextOwner MakeURLRequestContext(
+ mojom::NetworkContextParams* network_context_params);
+
+ NetworkService* const network_service_;
+
+ std::unique_ptr<ResourceScheduler> resource_scheduler_;
+
+ // Holds owning pointer to |url_request_context_|. Will contain a nullptr for
+ // |url_request_context| when the NetworkContextImpl doesn't own its own
+ // URLRequestContext.
+ URLRequestContextOwner url_request_context_owner_;
+
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+
+ // Put it below |url_request_context_| so that it outlives all the
+ // NetworkServiceURLLoaderFactory instances.
+ mojo::StrongBindingSet<mojom::URLLoaderFactory> loader_factory_bindings_;
+
+ mojom::NetworkContextParamsPtr params_;
+
+ mojo::Binding<mojom::NetworkContext> binding_;
+
+ std::unique_ptr<CookieManager> cookie_manager_;
+
+ std::unique_ptr<UDPSocketFactory> udp_socket_factory_;
+
+ int current_resource_scheduler_client_id_ = 0;
+
+ // TODO(yhirano): Consult with switches::kDisableResourceScheduler.
+ constexpr static bool enable_resource_scheduler_ = true;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkContext);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_NETWORK_CONTEXT_H_
diff --git a/chromium/services/network/network_context_unittest.cc b/chromium/services/network/network_context_unittest.cc
new file mode 100644
index 00000000000..83e6955b23c
--- /dev/null
+++ b/chromium/services/network/network_context_unittest.cc
@@ -0,0 +1,784 @@
+// 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 <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/location.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/run_loop.h"
+#include "base/strings/string_split.h"
+#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "components/network_session_configurator/browser/network_session_configurator.h"
+#include "components/network_session_configurator/common/network_switches.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "net/base/cache_type.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_options.h"
+#include "net/cookies/cookie_store.h"
+#include "net/disk_cache/disk_cache.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_server_properties_manager.h"
+#include "net/http/http_transaction_factory.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_service.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "net/url_request/url_request_job_factory.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/proxy_config.mojom.h"
+#include "services/network/udp_socket_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/scheme_host_port.h"
+#include "url/url_constants.h"
+
+namespace network {
+
+namespace {
+
+mojom::NetworkContextParamsPtr CreateContextParams() {
+ mojom::NetworkContextParamsPtr params = mojom::NetworkContextParams::New();
+ // Use a fixed proxy config, to avoid dependencies on local network
+ // configuration.
+ params->initial_proxy_config = net::ProxyConfig::CreateDirect();
+ return params;
+}
+
+class NetworkContextTest : public testing::Test {
+ public:
+ NetworkContextTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ network_service_(NetworkService::CreateForTesting()) {}
+ ~NetworkContextTest() override {}
+
+ std::unique_ptr<NetworkContext> CreateContextWithParams(
+ mojom::NetworkContextParamsPtr context_params) {
+ return std::make_unique<NetworkContext>(
+ network_service_.get(), mojo::MakeRequest(&network_context_ptr_),
+ std::move(context_params));
+ }
+
+ // Searches through |backend|'s stats to discover its type. Only supports
+ // blockfile and simple caches.
+ net::URLRequestContextBuilder::HttpCacheParams::Type GetBackendType(
+ disk_cache::Backend* backend) {
+ base::StringPairs stats;
+ backend->GetStats(&stats);
+ for (const auto& pair : stats) {
+ if (pair.first != "Cache type")
+ continue;
+
+ if (pair.second == "Simple Cache")
+ return net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE;
+ if (pair.second == "Blockfile Cache")
+ return net::URLRequestContextBuilder::HttpCacheParams::DISK_BLOCKFILE;
+ break;
+ }
+
+ NOTREACHED();
+ return net::URLRequestContextBuilder::HttpCacheParams::IN_MEMORY;
+ }
+
+ mojom::NetworkService* network_service() const {
+ return network_service_.get();
+ }
+
+ protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<NetworkService> network_service_;
+ // Stores the NetworkContextPtr of the most recently created NetworkContext,
+ // since destroying this before the NetworkContext itself triggers deletion of
+ // the NetworkContext. These tests are probably fine anyways, since the
+ // message loop must be spun for that to happen.
+ mojom::NetworkContextPtr network_context_ptr_;
+};
+
+TEST_F(NetworkContextTest, DisableQuic) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kEnableQuic);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+ // By default, QUIC should be enabled for new NetworkContexts when the command
+ // line indicates it should be.
+ EXPECT_TRUE(network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params()
+ .enable_quic);
+
+ // Disabling QUIC should disable it on existing NetworkContexts.
+ network_service()->DisableQuic();
+ EXPECT_FALSE(network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params()
+ .enable_quic);
+
+ // Disabling QUIC should disable it new NetworkContexts.
+ std::unique_ptr<NetworkContext> network_context2 =
+ CreateContextWithParams(CreateContextParams());
+ EXPECT_FALSE(network_context2->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params()
+ .enable_quic);
+
+ // Disabling QUIC again should be harmless.
+ network_service()->DisableQuic();
+ std::unique_ptr<NetworkContext> network_context3 =
+ CreateContextWithParams(CreateContextParams());
+ EXPECT_FALSE(network_context3->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params()
+ .enable_quic);
+}
+
+TEST_F(NetworkContextTest, EnableBrotli) {
+ for (bool enable_brotli : {true, false}) {
+ mojom::NetworkContextParamsPtr context_params =
+ mojom::NetworkContextParams::New();
+ context_params->enable_brotli = enable_brotli;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_EQ(enable_brotli,
+ network_context->GetURLRequestContext()->enable_brotli());
+ }
+}
+
+TEST_F(NetworkContextTest, ContextName) {
+ const char kContextName[] = "Jim";
+ mojom::NetworkContextParamsPtr context_params =
+ mojom::NetworkContextParams::New();
+ context_params->context_name = std::string(kContextName);
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_EQ(kContextName, network_context->GetURLRequestContext()->name());
+}
+
+TEST_F(NetworkContextTest, QuicUserAgentId) {
+ const char kQuicUserAgentId[] = "007";
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->quic_user_agent_id = kQuicUserAgentId;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_EQ(kQuicUserAgentId, network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params()
+ .quic_user_agent_id);
+}
+
+TEST_F(NetworkContextTest, DisableDataUrlSupport) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->enable_data_url_support = false;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_FALSE(
+ network_context->GetURLRequestContext()->job_factory()->IsHandledProtocol(
+ url::kDataScheme));
+}
+
+TEST_F(NetworkContextTest, EnableDataUrlSupport) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->enable_data_url_support = true;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_TRUE(
+ network_context->GetURLRequestContext()->job_factory()->IsHandledProtocol(
+ url::kDataScheme));
+}
+
+TEST_F(NetworkContextTest, DisableFileUrlSupport) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->enable_file_url_support = false;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_FALSE(
+ network_context->GetURLRequestContext()->job_factory()->IsHandledProtocol(
+ url::kFileScheme));
+}
+
+#if !BUILDFLAG(DISABLE_FILE_SUPPORT)
+TEST_F(NetworkContextTest, EnableFileUrlSupport) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->enable_file_url_support = true;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_TRUE(
+ network_context->GetURLRequestContext()->job_factory()->IsHandledProtocol(
+ url::kFileScheme));
+}
+#endif // !BUILDFLAG(DISABLE_FILE_SUPPORT)
+
+TEST_F(NetworkContextTest, DisableFtpUrlSupport) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->enable_ftp_url_support = false;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_FALSE(
+ network_context->GetURLRequestContext()->job_factory()->IsHandledProtocol(
+ url::kFtpScheme));
+}
+
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+TEST_F(NetworkContextTest, EnableFtpUrlSupport) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->enable_ftp_url_support = true;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_TRUE(
+ network_context->GetURLRequestContext()->job_factory()->IsHandledProtocol(
+ url::kFtpScheme));
+}
+#endif // !BUILDFLAG(DISABLE_FTP_SUPPORT)
+
+#if BUILDFLAG(ENABLE_REPORTING)
+TEST_F(NetworkContextTest, DisableReporting) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndDisableFeature(features::kReporting);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+ EXPECT_FALSE(network_context->GetURLRequestContext()->reporting_service());
+}
+
+TEST_F(NetworkContextTest, EnableReporting) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(features::kReporting);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+ EXPECT_TRUE(network_context->GetURLRequestContext()->reporting_service());
+}
+
+TEST_F(NetworkContextTest, DisableNetworkErrorLogging) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndDisableFeature(features::kNetworkErrorLogging);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+ EXPECT_FALSE(
+ network_context->GetURLRequestContext()->network_error_logging_service());
+}
+
+TEST_F(NetworkContextTest, EnableNetworkErrorLogging) {
+ base::test::ScopedFeatureList scoped_feature_list_;
+ scoped_feature_list_.InitAndEnableFeature(features::kNetworkErrorLogging);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+ EXPECT_TRUE(
+ network_context->GetURLRequestContext()->network_error_logging_service());
+}
+#endif // BUILDFLAG(ENABLE_REPORTING)
+
+TEST_F(NetworkContextTest, Http09Disabled) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->http_09_on_non_default_ports_enabled = false;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_FALSE(network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params()
+ .http_09_on_non_default_ports_enabled);
+}
+
+TEST_F(NetworkContextTest, Http09Enabled) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->http_09_on_non_default_ports_enabled = true;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_TRUE(network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params()
+ .http_09_on_non_default_ports_enabled);
+}
+
+TEST_F(NetworkContextTest, DefaultHttpNetworkSessionParams) {
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+
+ const net::HttpNetworkSession::Params& params =
+ network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params();
+
+ EXPECT_TRUE(params.enable_http2);
+ EXPECT_FALSE(params.enable_quic);
+ EXPECT_EQ(1350u, params.quic_max_packet_length);
+ EXPECT_TRUE(params.origins_to_force_quic_on.empty());
+ EXPECT_FALSE(params.enable_user_alternate_protocol_ports);
+ EXPECT_FALSE(params.ignore_certificate_errors);
+ EXPECT_EQ(0, params.testing_fixed_http_port);
+ EXPECT_EQ(0, params.testing_fixed_https_port);
+}
+
+// Make sure that network_session_configurator is hooked up.
+TEST_F(NetworkContextTest, FixedHttpPort) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kTestingFixedHttpPort, "800");
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kTestingFixedHttpsPort, "801");
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+
+ const net::HttpNetworkSession::Params& params =
+ network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetSession()
+ ->params();
+
+ EXPECT_EQ(800, params.testing_fixed_http_port);
+ EXPECT_EQ(801, params.testing_fixed_https_port);
+}
+
+TEST_F(NetworkContextTest, NoCache) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->http_cache_enabled = false;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ EXPECT_FALSE(network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetCache());
+}
+
+TEST_F(NetworkContextTest, MemoryCache) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->http_cache_enabled = true;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ net::HttpCache* cache = network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetCache();
+ ASSERT_TRUE(cache);
+
+ disk_cache::Backend* backend = nullptr;
+ net::TestCompletionCallback callback;
+ int rv = cache->GetBackend(&backend, callback.callback());
+ EXPECT_EQ(net::OK, callback.GetResult(rv));
+ ASSERT_TRUE(backend);
+
+ EXPECT_EQ(net::MEMORY_CACHE, backend->GetCacheType());
+}
+
+TEST_F(NetworkContextTest, DiskCache) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->http_cache_enabled = true;
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ context_params->http_cache_path = temp_dir.GetPath();
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ net::HttpCache* cache = network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetCache();
+ ASSERT_TRUE(cache);
+
+ disk_cache::Backend* backend = nullptr;
+ net::TestCompletionCallback callback;
+ int rv = cache->GetBackend(&backend, callback.callback());
+ EXPECT_EQ(net::OK, callback.GetResult(rv));
+ ASSERT_TRUE(backend);
+
+ EXPECT_EQ(net::DISK_CACHE, backend->GetCacheType());
+ EXPECT_EQ(network_session_configurator::ChooseCacheType(
+ *base::CommandLine::ForCurrentProcess()),
+ GetBackendType(backend));
+}
+
+// This makes sure that network_session_configurator::ChooseCacheType is
+// connected to NetworkContext.
+TEST_F(NetworkContextTest, SimpleCache) {
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kUseSimpleCacheBackend, "on");
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->http_cache_enabled = true;
+
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ context_params->http_cache_path = temp_dir.GetPath();
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+ net::HttpCache* cache = network_context->GetURLRequestContext()
+ ->http_transaction_factory()
+ ->GetCache();
+ ASSERT_TRUE(cache);
+
+ disk_cache::Backend* backend = nullptr;
+ net::TestCompletionCallback callback;
+ int rv = cache->GetBackend(&backend, callback.callback());
+ EXPECT_EQ(net::OK, callback.GetResult(rv));
+ ASSERT_TRUE(backend);
+
+ base::StringPairs stats;
+ backend->GetStats(&stats);
+ EXPECT_EQ(net::URLRequestContextBuilder::HttpCacheParams::DISK_SIMPLE,
+ GetBackendType(backend));
+}
+
+TEST_F(NetworkContextTest, HttpServerPropertiesToDisk) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ base::FilePath file_path = temp_dir.GetPath().AppendASCII("foo");
+ EXPECT_FALSE(base::PathExists(file_path));
+
+ const url::SchemeHostPort kSchemeHostPort("https", "foo", 443);
+
+ // Create a context with on-disk storage of HTTP server properties.
+ mojom::NetworkContextParamsPtr context_params =
+ mojom::NetworkContextParams::New();
+ context_params->http_server_properties_path = file_path;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+
+ // Wait for properties to load from disk, and sanity check initial state.
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(network_context->GetURLRequestContext()
+ ->http_server_properties()
+ ->GetSupportsSpdy(kSchemeHostPort));
+
+ // Set a property.
+ network_context->GetURLRequestContext()
+ ->http_server_properties()
+ ->SetSupportsSpdy(kSchemeHostPort, true);
+ // Deleting the context will cause it to flush state. Wait for the pref
+ // service to flush to disk.
+ network_context.reset();
+ scoped_task_environment_.RunUntilIdle();
+
+ // Create a new NetworkContext using the same path for HTTP server properties.
+ context_params = mojom::NetworkContextParams::New();
+ context_params->http_server_properties_path = file_path;
+ network_context = CreateContextWithParams(std::move(context_params));
+
+ // Wait for properties to load from disk.
+ scoped_task_environment_.RunUntilIdle();
+
+ EXPECT_TRUE(network_context->GetURLRequestContext()
+ ->http_server_properties()
+ ->GetSupportsSpdy(kSchemeHostPort));
+
+ // Now check that ClearNetworkingHistorySince clears the data.
+ base::RunLoop run_loop2;
+ network_context->ClearNetworkingHistorySince(
+ base::Time::Now() - base::TimeDelta::FromHours(1),
+ run_loop2.QuitClosure());
+ run_loop2.Run();
+ EXPECT_FALSE(network_context->GetURLRequestContext()
+ ->http_server_properties()
+ ->GetSupportsSpdy(kSchemeHostPort));
+
+ // Clear destroy the network context and let any pending writes complete
+ // before destroying |temp_dir|, to avoid leaking any files.
+ network_context.reset();
+ scoped_task_environment_.RunUntilIdle();
+ ASSERT_TRUE(temp_dir.Delete());
+}
+
+// Checks that ClearNetworkingHistorySince() works clears in-memory pref stores,
+// and invokes the closure passed to it.
+TEST_F(NetworkContextTest, ClearHttpServerPropertiesInMemory) {
+ const url::SchemeHostPort kSchemeHostPort("https", "foo", 443);
+
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(mojom::NetworkContextParams::New());
+
+ EXPECT_FALSE(network_context->GetURLRequestContext()
+ ->http_server_properties()
+ ->GetSupportsSpdy(kSchemeHostPort));
+ network_context->GetURLRequestContext()
+ ->http_server_properties()
+ ->SetSupportsSpdy(kSchemeHostPort, true);
+ EXPECT_TRUE(network_context->GetURLRequestContext()
+ ->http_server_properties()
+ ->GetSupportsSpdy(kSchemeHostPort));
+
+ base::RunLoop run_loop;
+ network_context->ClearNetworkingHistorySince(
+ base::Time::Now() - base::TimeDelta::FromHours(1),
+ run_loop.QuitClosure());
+ run_loop.Run();
+ EXPECT_FALSE(network_context->GetURLRequestContext()
+ ->http_server_properties()
+ ->GetSupportsSpdy(kSchemeHostPort));
+}
+
+void SetCookieCallback(base::RunLoop* run_loop, bool* result_out, bool result) {
+ *result_out = result;
+ run_loop->Quit();
+}
+
+void GetCookieListCallback(base::RunLoop* run_loop,
+ net::CookieList* result_out,
+ const net::CookieList& result) {
+ *result_out = result;
+ run_loop->Quit();
+}
+
+TEST_F(NetworkContextTest, CookieManager) {
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(mojom::NetworkContextParams::New());
+
+ mojom::CookieManagerPtr cookie_manager_ptr;
+ mojom::CookieManagerRequest cookie_manager_request(
+ mojo::MakeRequest(&cookie_manager_ptr));
+ network_context->GetCookieManager(std::move(cookie_manager_request));
+
+ // Set a cookie through the cookie interface.
+ base::RunLoop run_loop1;
+ bool result = false;
+ cookie_manager_ptr->SetCanonicalCookie(
+ net::CanonicalCookie("TestCookie", "1", "www.test.com", "/", base::Time(),
+ base::Time(), base::Time(), false, false,
+ net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_LOW),
+ true, true, base::BindOnce(&SetCookieCallback, &run_loop1, &result));
+ run_loop1.Run();
+ EXPECT_TRUE(result);
+
+ // Confirm that cookie is visible directly through the store associated with
+ // the network context.
+ base::RunLoop run_loop2;
+ net::CookieList cookies;
+ network_context->GetURLRequestContext()
+ ->cookie_store()
+ ->GetCookieListWithOptionsAsync(
+ GURL("http://www.test.com/whatever"), net::CookieOptions(),
+ base::Bind(&GetCookieListCallback, &run_loop2, &cookies));
+ run_loop2.Run();
+ ASSERT_EQ(1u, cookies.size());
+ EXPECT_EQ("TestCookie", cookies[0].Name());
+}
+
+TEST_F(NetworkContextTest, ProxyConfig) {
+ // Create a bunch of proxy rules to switch between. All that matters is that
+ // they're all different. It's important that none of these configs require
+ // fetching a PAC scripts, as this test checks
+ // ProxyResolutionService::config(), which is only updated after fetching PAC
+ // scripts (if applicable).
+ net::ProxyConfig proxy_configs[3];
+ proxy_configs[0].proxy_rules().ParseFromString("http=foopy:80");
+ proxy_configs[1].proxy_rules().ParseFromString("http=foopy:80;ftp=foopy2");
+ proxy_configs[2] = net::ProxyConfig::CreateDirect();
+
+ // Sanity check.
+ EXPECT_FALSE(proxy_configs[0].Equals(proxy_configs[1]));
+ EXPECT_FALSE(proxy_configs[0].Equals(proxy_configs[2]));
+ EXPECT_FALSE(proxy_configs[1].Equals(proxy_configs[2]));
+
+ // Try each proxy config as the initial config, to make sure setting the
+ // initial config works.
+ for (const auto& initial_proxy_config : proxy_configs) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->initial_proxy_config = initial_proxy_config;
+ mojom::ProxyConfigClientPtr config_client;
+ context_params->proxy_config_client_request =
+ mojo::MakeRequest(&config_client);
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+
+ net::ProxyResolutionService* proxy_resolution_service =
+ network_context->GetURLRequestContext()->proxy_resolution_service();
+ // Kick the ProxyResolutionService into action, as it doesn't start updating
+ // its config until it's first used.
+ proxy_resolution_service->ForceReloadProxyConfig();
+ EXPECT_TRUE(proxy_resolution_service->config());
+ EXPECT_TRUE(
+ proxy_resolution_service->config()->Equals(initial_proxy_config));
+
+ // Always go through the other configs in the same order. This has the
+ // advantage of testing the case where there's no change, for
+ // proxy_config[0].
+ for (const auto& proxy_config : proxy_configs) {
+ config_client->OnProxyConfigUpdated(proxy_config);
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_TRUE(proxy_resolution_service->config());
+ EXPECT_TRUE(proxy_resolution_service->config()->Equals(proxy_config));
+ }
+ }
+}
+
+// Verify that a proxy config works without a ProxyConfigClientRequest.
+TEST_F(NetworkContextTest, StaticProxyConfig) {
+ net::ProxyConfig proxy_config;
+ proxy_config.proxy_rules().ParseFromString("http=foopy:80;ftp=foopy2");
+
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->initial_proxy_config = proxy_config;
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+
+ net::ProxyResolutionService* proxy_resolution_service =
+ network_context->GetURLRequestContext()->proxy_resolution_service();
+ // Kick the ProxyResolutionService into action, as it doesn't start updating
+ // its config until it's first used.
+ proxy_resolution_service->ForceReloadProxyConfig();
+ EXPECT_TRUE(proxy_resolution_service->config());
+ EXPECT_TRUE(proxy_resolution_service->config()->Equals(proxy_config));
+}
+
+TEST_F(NetworkContextTest, NoInitialProxyConfig) {
+ mojom::NetworkContextParamsPtr context_params = CreateContextParams();
+ context_params->initial_proxy_config.reset();
+ mojom::ProxyConfigClientPtr config_client;
+ context_params->proxy_config_client_request =
+ mojo::MakeRequest(&config_client);
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(std::move(context_params));
+
+ net::ProxyResolutionService* proxy_resolution_service =
+ network_context->GetURLRequestContext()->proxy_resolution_service();
+ EXPECT_FALSE(proxy_resolution_service->config());
+ EXPECT_FALSE(proxy_resolution_service->fetched_config());
+
+ // Before there's a proxy configuration, proxy requests should hang.
+ net::ProxyInfo proxy_info;
+ net::TestCompletionCallback test_callback;
+ net::ProxyResolutionService::Request* request = nullptr;
+ ASSERT_EQ(net::ERR_IO_PENDING, proxy_resolution_service->ResolveProxy(
+ GURL("http://bar/"), "GET", &proxy_info,
+ test_callback.callback(), &request,
+ nullptr, net::NetLogWithSource()));
+ scoped_task_environment_.RunUntilIdle();
+ EXPECT_FALSE(proxy_resolution_service->config());
+ EXPECT_FALSE(proxy_resolution_service->fetched_config());
+ ASSERT_FALSE(test_callback.have_result());
+
+ net::ProxyConfig proxy_config;
+ proxy_config.proxy_rules().ParseFromString("http=foopy:80");
+ config_client->OnProxyConfigUpdated(proxy_config);
+ ASSERT_EQ(net::OK, test_callback.WaitForResult());
+
+ EXPECT_TRUE(proxy_info.is_http());
+ EXPECT_EQ("foopy", proxy_info.proxy_server().host_port_pair().host());
+}
+
+class TestProxyConfigLazyPoller : public mojom::ProxyConfigPollerClient {
+ public:
+ TestProxyConfigLazyPoller() : binding_(this) {}
+ ~TestProxyConfigLazyPoller() override {}
+
+ void OnLazyProxyConfigPoll() override { ++times_polled_; }
+
+ mojom::ProxyConfigPollerClientPtr BindInterface() {
+ mojom::ProxyConfigPollerClientPtr interface;
+ binding_.Bind(MakeRequest(&interface));
+ return interface;
+ }
+
+ int GetAndClearTimesPolled() {
+ int out = times_polled_;
+ times_polled_ = 0;
+ return out;
+ }
+
+ private:
+ int times_polled_ = 0;
+ mojo::Binding<ProxyConfigPollerClient> binding_;
+
+ std::unique_ptr<base::RunLoop> run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestProxyConfigLazyPoller);
+};
+
+net::IPEndPoint GetLocalHostWithAnyPort() {
+ return net::IPEndPoint(net::IPAddress(127, 0, 0, 1), 0);
+}
+
+std::vector<uint8_t> CreateTestMessage(uint8_t initial, size_t size) {
+ std::vector<uint8_t> array(size);
+ for (size_t i = 0; i < size; ++i)
+ array[i] = static_cast<uint8_t>((i + initial) % 256);
+ return array;
+}
+
+TEST_F(NetworkContextTest, CreateUDPSocket) {
+ std::unique_ptr<NetworkContext> network_context =
+ CreateContextWithParams(CreateContextParams());
+
+ // Create a server socket to listen for incoming datagrams.
+ test::UDPSocketReceiverImpl receiver;
+ mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
+ mojom::UDPSocketReceiverPtr receiver_interface_ptr;
+ receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ mojom::UDPSocketPtr server_socket;
+ network_context->CreateUDPSocket(mojo::MakeRequest(&server_socket),
+ std::move(receiver_interface_ptr));
+ network::test::UDPSocketTestHelper helper(&server_socket);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ // Create a client socket to send datagrams.
+ mojom::UDPSocketPtr client_socket;
+ mojom::UDPSocketRequest client_socket_request(
+ mojo::MakeRequest(&client_socket));
+ network_context->CreateUDPSocket(std::move(client_socket_request), nullptr);
+
+ net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
+ network::test::UDPSocketTestHelper client_helper(&client_socket);
+ ASSERT_EQ(net::OK,
+ client_helper.ConnectSync(server_addr, nullptr, &client_addr));
+
+ // This test assumes that the loopback interface doesn't drop UDP packets for
+ // a small number of packets.
+ const size_t kDatagramCount = 6;
+ const size_t kDatagramSize = 255;
+ server_socket->ReceiveMore(kDatagramCount);
+
+ for (size_t i = 0; i < kDatagramCount; ++i) {
+ std::vector<uint8_t> test_msg(
+ CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize));
+ int result = client_helper.SendSync(test_msg);
+ EXPECT_EQ(net::OK, result);
+ }
+
+ receiver.WaitForReceivedResults(kDatagramCount);
+ EXPECT_EQ(kDatagramCount, receiver.results().size());
+
+ int i = 0;
+ for (const auto& result : receiver.results()) {
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_EQ(result.src_addr, client_addr);
+ EXPECT_EQ(CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize),
+ result.data.value());
+ i++;
+ }
+}
+
+} // namespace
+
+} // namespace network
diff --git a/chromium/services/network/network_sandbox_hook_linux.cc b/chromium/services/network/network_sandbox_hook_linux.cc
new file mode 100644
index 00000000000..983a6dac494
--- /dev/null
+++ b/chromium/services/network/network_sandbox_hook_linux.cc
@@ -0,0 +1,38 @@
+// 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 "services/network/network_sandbox_hook_linux.h"
+#include "sandbox/linux/syscall_broker/broker_command.h"
+
+#include "base/rand_util.h"
+#include "base/sys_info.h"
+
+using sandbox::syscall_broker::BrokerFilePermission;
+using sandbox::syscall_broker::MakeBrokerCommandSet;
+
+namespace network {
+
+bool NetworkPreSandboxHook(service_manager::SandboxLinux::Options options) {
+ auto* instance = service_manager::SandboxLinux::GetInstance();
+
+ // TODO(tsepez): remove universal permission under filesytem root.
+ instance->StartBrokerProcess(
+ MakeBrokerCommandSet({
+ sandbox::syscall_broker::COMMAND_ACCESS,
+ sandbox::syscall_broker::COMMAND_MKDIR,
+ sandbox::syscall_broker::COMMAND_OPEN,
+ sandbox::syscall_broker::COMMAND_READLINK,
+ sandbox::syscall_broker::COMMAND_RENAME,
+ sandbox::syscall_broker::COMMAND_RMDIR,
+ sandbox::syscall_broker::COMMAND_STAT,
+ sandbox::syscall_broker::COMMAND_UNLINK,
+ }),
+ {BrokerFilePermission::ReadWriteCreateRecursive("/")},
+ service_manager::SandboxLinux::PreSandboxHook(), options);
+
+ instance->EngageNamespaceSandbox(false /* from_zygote */);
+ return true;
+}
+
+} // namespace network
diff --git a/chromium/services/network/network_sandbox_hook_linux.h b/chromium/services/network/network_sandbox_hook_linux.h
new file mode 100644
index 00000000000..c398ac424c5
--- /dev/null
+++ b/chromium/services/network/network_sandbox_hook_linux.h
@@ -0,0 +1,18 @@
+// 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 SERVICES_NETWORK_NETWORK_SANDBOX_HOOK_LINUX_H_
+#define SERVICES_NETWORK_NETWORK_SANDBOX_HOOK_LINUX_H_
+
+#include "base/component_export.h"
+#include "services/service_manager/sandbox/linux/sandbox_linux.h"
+
+namespace network {
+
+COMPONENT_EXPORT(NETWORK_SERVICE)
+bool NetworkPreSandboxHook(service_manager::SandboxLinux::Options options);
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_NETWORK_SANDBOX_HOOK_LINUX_H_
diff --git a/chromium/services/network/network_service.cc b/chromium/services/network/network_service.cc
new file mode 100644
index 00000000000..58324f439e9
--- /dev/null
+++ b/chromium/services/network/network_service.cc
@@ -0,0 +1,224 @@
+// 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 "services/network/network_service.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "net/base/logging_network_change_observer.h"
+#include "net/base/network_change_notifier.h"
+#include "net/log/file_net_log_observer.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_util.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "services/network/network_context.h"
+#include "services/network/public/cpp/network_switches.h"
+#include "services/network/url_request_context_builder_mojo.h"
+
+namespace network {
+
+namespace {
+
+std::unique_ptr<net::NetworkChangeNotifier>
+CreateNetworkChangeNotifierIfNeeded() {
+ // There is a global singleton net::NetworkChangeNotifier if NetworkService
+ // is running inside of the browser process.
+ if (!net::NetworkChangeNotifier::HasNetworkChangeNotifier()) {
+#if defined(OS_ANDROID)
+ // On Android, NetworkChangeNotifier objects are always set up in process
+ // before NetworkService is run.
+ return nullptr;
+#elif defined(OS_CHROMEOS) || defined(OS_IOS) || defined(OS_FUCHSIA)
+ // ChromeOS has its own implementation of NetworkChangeNotifier that lives
+ // outside of //net. iOS doesn't embed //content. Fuchsia doesn't have an
+ // implementation yet.
+ // TODO(xunjieli): Figure out what to do for these 3 platforms.
+ NOTIMPLEMENTED();
+ return nullptr;
+#endif
+ return base::WrapUnique(net::NetworkChangeNotifier::Create());
+ }
+ return nullptr;
+}
+
+} // namespace
+
+class NetworkService::MojoNetLog : public net::NetLog {
+ public:
+ MojoNetLog() {}
+
+ // If specified by the command line, stream network events (NetLog) to a
+ // file on disk. This will last for the duration of the process.
+ void ProcessCommandLine(const base::CommandLine& command_line) {
+ if (!command_line.HasSwitch(switches::kLogNetLog))
+ return;
+
+ base::FilePath log_path =
+ command_line.GetSwitchValuePath(switches::kLogNetLog);
+
+ // TODO(eroman): Should get capture mode from the command line.
+ net::NetLogCaptureMode capture_mode =
+ net::NetLogCaptureMode::IncludeCookiesAndCredentials();
+
+ file_net_log_observer_ =
+ net::FileNetLogObserver::CreateUnbounded(log_path, nullptr);
+ file_net_log_observer_->StartObserving(this, capture_mode);
+ }
+
+ ~MojoNetLog() override {
+ if (file_net_log_observer_)
+ file_net_log_observer_->StopObserving(nullptr, base::OnceClosure());
+ }
+
+ private:
+ std::unique_ptr<net::FileNetLogObserver> file_net_log_observer_;
+ DISALLOW_COPY_AND_ASSIGN(MojoNetLog);
+};
+
+NetworkService::NetworkService(
+ std::unique_ptr<service_manager::BinderRegistry> registry,
+ mojom::NetworkServiceRequest request,
+ net::NetLog* net_log)
+ : registry_(std::move(registry)), binding_(this) {
+ // |registry_| is nullptr when an in-process NetworkService is
+ // created directly. The latter is done in concert with using
+ // CreateNetworkContextWithBuilder to ease the transition to using the
+ // network service.
+ if (registry_) {
+ DCHECK(!request.is_pending());
+ registry_->AddInterface<mojom::NetworkService>(
+ base::BindRepeating(&NetworkService::Bind, base::Unretained(this)));
+ } else if (request.is_pending()) {
+ Bind(std::move(request));
+ }
+
+ network_change_manager_ = std::make_unique<NetworkChangeManager>(
+ CreateNetworkChangeNotifierIfNeeded());
+
+ if (net_log) {
+ net_log_ = net_log;
+ } else {
+ owned_net_log_ = std::make_unique<MojoNetLog>();
+ // Note: The command line switches are only checked when not using the
+ // embedder's NetLog, as it may already be writing to the destination log
+ // file.
+ owned_net_log_->ProcessCommandLine(*base::CommandLine::ForCurrentProcess());
+ net_log_ = owned_net_log_.get();
+ }
+
+ // Add an observer that will emit network change events to the ChromeNetLog.
+ // Assuming NetworkChangeNotifier dispatches in FIFO order, we should be
+ // logging the network change before other IO thread consumers respond to it.
+ network_change_observer_.reset(
+ new net::LoggingNetworkChangeObserver(net_log_));
+}
+
+NetworkService::~NetworkService() {
+ // Call each Network and ask it to release its net::URLRequestContext, as they
+ // may have references to shared objects owned by the NetworkService. The
+ // NetworkContexts deregister themselves in Cleanup(), so have to be careful.
+ while (!network_contexts_.empty())
+ (*network_contexts_.begin())->Cleanup();
+}
+
+std::unique_ptr<NetworkService> NetworkService::Create(
+ mojom::NetworkServiceRequest request,
+ net::NetLog* net_log) {
+ return std::make_unique<NetworkService>(nullptr, std::move(request), net_log);
+}
+
+std::unique_ptr<mojom::NetworkContext>
+NetworkService::CreateNetworkContextWithBuilder(
+ mojom::NetworkContextRequest request,
+ mojom::NetworkContextParamsPtr params,
+ std::unique_ptr<URLRequestContextBuilderMojo> builder,
+ net::URLRequestContext** url_request_context) {
+ std::unique_ptr<NetworkContext> network_context =
+ std::make_unique<NetworkContext>(this, std::move(request),
+ std::move(params), std::move(builder));
+ *url_request_context = network_context->GetURLRequestContext();
+ return network_context;
+}
+
+std::unique_ptr<NetworkService> NetworkService::CreateForTesting() {
+ return base::WrapUnique(
+ new NetworkService(std::make_unique<service_manager::BinderRegistry>()));
+}
+
+void NetworkService::RegisterNetworkContext(NetworkContext* network_context) {
+ DCHECK_EQ(0u, network_contexts_.count(network_context));
+ network_contexts_.insert(network_context);
+ if (quic_disabled_)
+ network_context->DisableQuic();
+}
+
+void NetworkService::DeregisterNetworkContext(NetworkContext* network_context) {
+ DCHECK_EQ(1u, network_contexts_.count(network_context));
+ network_contexts_.erase(network_context);
+}
+
+void NetworkService::SetClient(mojom::NetworkServiceClientPtr client) {
+ client_ = std::move(client);
+}
+
+void NetworkService::CreateNetworkContext(
+ mojom::NetworkContextRequest request,
+ mojom::NetworkContextParamsPtr params) {
+ // The NetworkContext will destroy itself on connection error, or when the
+ // service is destroyed.
+ new NetworkContext(this, std::move(request), std::move(params));
+}
+
+void NetworkService::DisableQuic() {
+ quic_disabled_ = true;
+
+ for (auto* network_context : network_contexts_) {
+ network_context->DisableQuic();
+ }
+}
+
+void NetworkService::SetRawHeadersAccess(uint32_t process_id, bool allow) {
+ DCHECK(process_id);
+ if (allow)
+ processes_with_raw_headers_access_.insert(process_id);
+ else
+ processes_with_raw_headers_access_.erase(process_id);
+}
+
+bool NetworkService::HasRawHeadersAccess(uint32_t process_id) const {
+ // Allow raw headers for browser-initiated requests.
+ if (!process_id)
+ return true;
+ return processes_with_raw_headers_access_.find(process_id) !=
+ processes_with_raw_headers_access_.end();
+}
+
+net::NetLog* NetworkService::net_log() const {
+ return net_log_;
+}
+
+void NetworkService::GetNetworkChangeManager(
+ mojom::NetworkChangeManagerRequest request) {
+ network_change_manager_->AddRequest(std::move(request));
+}
+
+void NetworkService::OnBindInterface(
+ const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_->BindInterface(interface_name, std::move(interface_pipe));
+}
+
+void NetworkService::Bind(mojom::NetworkServiceRequest request) {
+ DCHECK(!binding_.is_bound());
+ binding_.Bind(std::move(request));
+}
+
+} // namespace network
diff --git a/chromium/services/network/network_service.h b/chromium/services/network/network_service.h
new file mode 100644
index 00000000000..23c188a7889
--- /dev/null
+++ b/chromium/services/network/network_service.h
@@ -0,0 +1,148 @@
+// 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 SERVICES_NETWORK_NETWORK_SERVICE_H_
+#define SERVICES_NETWORK_NETWORK_SERVICE_H_
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/network/keepalive_statistics_recorder.h"
+#include "services/network/network_change_manager.h"
+#include "services/network/network_service.h"
+#include "services/network/public/mojom/network_change_manager.mojom.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service.h"
+
+namespace net {
+class NetLog;
+class LoggingNetworkChangeObserver;
+class URLRequestContext;
+} // namespace net
+
+namespace network {
+
+class NetworkContext;
+class URLRequestContextBuilderMojo;
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkService
+ : public service_manager::Service,
+ public network::mojom::NetworkService {
+ public:
+ // |net_log| is an optional shared NetLog, which will be used instead of the
+ // service's own NetLog. It must outlive the NetworkService.
+ //
+ // TODO(https://crbug.com/767450): Once the NetworkService can always create
+ // its own NetLog in production, remove the |net_log| argument.
+ NetworkService(std::unique_ptr<service_manager::BinderRegistry> registry,
+ mojom::NetworkServiceRequest request = nullptr,
+ net::NetLog* net_log = nullptr);
+
+ ~NetworkService() override;
+
+ // Can be used to seed a NetworkContext with a consumer-configured
+ // URLRequestContextBuilder, which |params| will then be applied to. The
+ // results URLRequestContext will be written to |url_request_context|, which
+ // is owned by the NetworkContext, and can be further modified before first
+ // use. The returned NetworkContext must be destroyed before the
+ // NetworkService.
+ //
+ // This method is intended to ease the transition to an out-of-process
+ // NetworkService, and will be removed once that ships. It should only be
+ // called if the network service is disabled.
+ std::unique_ptr<mojom::NetworkContext> CreateNetworkContextWithBuilder(
+ mojom::NetworkContextRequest request,
+ mojom::NetworkContextParamsPtr params,
+ std::unique_ptr<URLRequestContextBuilderMojo> builder,
+ net::URLRequestContext** url_request_context);
+
+ // Allows late binding if the mojo request wasn't specified in the
+ // constructor.
+ void Bind(mojom::NetworkServiceRequest request);
+
+ // Creates a NetworkService instance on the current thread, optionally using
+ // the passed-in NetLog. Does not take ownership of |net_log|. Must be
+ // destroyed before |net_log|.
+ //
+ // TODO(https://crbug.com/767450): Make it so NetworkService can always create
+ // its own NetLog, instead of sharing one.
+ static std::unique_ptr<NetworkService> Create(
+ network::mojom::NetworkServiceRequest request,
+ net::NetLog* net_log = nullptr);
+
+ static std::unique_ptr<NetworkService> CreateForTesting();
+
+ // These are called by NetworkContexts as they are being created and
+ // destroyed.
+ void RegisterNetworkContext(NetworkContext* network_context);
+ void DeregisterNetworkContext(NetworkContext* network_context);
+
+ // mojom::NetworkService implementation:
+ void SetClient(mojom::NetworkServiceClientPtr client) override;
+ void CreateNetworkContext(mojom::NetworkContextRequest request,
+ mojom::NetworkContextParamsPtr params) override;
+ void DisableQuic() override;
+ void SetRawHeadersAccess(uint32_t process_id, bool allow) override;
+ void GetNetworkChangeManager(
+ mojom::NetworkChangeManagerRequest request) override;
+
+ bool quic_disabled() const { return quic_disabled_; }
+ bool HasRawHeadersAccess(uint32_t process_id) const;
+
+ mojom::NetworkServiceClient* client() { return client_.get(); }
+ net::NetLog* net_log() const;
+ KeepaliveStatisticsRecorder* keepalive_statistics_recorder() {
+ return &keepalive_statistics_recorder_;
+ }
+
+ private:
+ class MojoNetLog;
+
+ friend class NetworkService;
+
+ // service_manager::Service implementation.
+ void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
+
+ std::unique_ptr<MojoNetLog> owned_net_log_;
+ // TODO(https://crbug.com/767450): Remove this, once Chrome no longer creates
+ // its own NetLog.
+ net::NetLog* net_log_;
+
+ mojom::NetworkServiceClientPtr client_;
+
+ KeepaliveStatisticsRecorder keepalive_statistics_recorder_;
+
+ // Observer that logs network changes to the NetLog. Must be below the NetLog
+ // and the NetworkChangeNotifier (Once this class creates it), so it's
+ // destroyed before them.
+ std::unique_ptr<net::LoggingNetworkChangeObserver> network_change_observer_;
+
+ std::unique_ptr<NetworkChangeManager> network_change_manager_;
+
+ std::unique_ptr<service_manager::BinderRegistry> registry_;
+
+ mojo::Binding<mojom::NetworkService> binding_;
+
+ // NetworkContexts register themselves with the NetworkService so that they
+ // can be cleaned up when the NetworkService goes away. This is needed as
+ // NetworkContexts share global state with the NetworkService, so must be
+ // destroyed first.
+ std::set<NetworkContext*> network_contexts_;
+ std::set<uint32_t> processes_with_raw_headers_access_;
+
+ bool quic_disabled_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkService);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_NETWORK_SERVICE_H_
diff --git a/chromium/services/network/network_service_unittest.cc b/chromium/services/network/network_service_unittest.cc
new file mode 100644
index 00000000000..8520b43fa0a
--- /dev/null
+++ b/chromium/services/network/network_service_unittest.cc
@@ -0,0 +1,469 @@
+// 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 <memory>
+
+#include "base/run_loop.h"
+#include "base/strings/string_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "build/build_config.h"
+#include "net/base/mock_network_change_notifier.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
+#include "services/network/public/mojom/network_change_manager.mojom.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/test/test_url_loader_client.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/cpp/service_test.h"
+#include "services/service_manager/public/mojom/service_factory.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+const char kNetworkServiceName[] = "network";
+
+mojom::NetworkContextParamsPtr CreateContextParams() {
+ mojom::NetworkContextParamsPtr params = mojom::NetworkContextParams::New();
+ // Use a fixed proxy config, to avoid dependencies on local network
+ // configuration.
+ params->initial_proxy_config = net::ProxyConfig::CreateDirect();
+ return params;
+}
+
+class NetworkServiceTest : public testing::Test {
+ public:
+ NetworkServiceTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ service_(NetworkService::CreateForTesting()) {}
+ ~NetworkServiceTest() override {}
+
+ NetworkService* service() const { return service_.get(); }
+
+ void DestroyService() { service_.reset(); }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ std::unique_ptr<NetworkService> service_;
+};
+
+// Test shutdown in the case a NetworkContext is destroyed before the
+// NetworkService.
+TEST_F(NetworkServiceTest, CreateAndDestroyContext) {
+ mojom::NetworkContextPtr network_context;
+ service()->CreateNetworkContext(mojo::MakeRequest(&network_context),
+ CreateContextParams());
+ network_context.reset();
+ // Make sure the NetworkContext is destroyed.
+ base::RunLoop().RunUntilIdle();
+}
+
+// Test shutdown in the case there is still a live NetworkContext when the
+// NetworkService is destroyed. The service should destroy the NetworkContext
+// itself.
+TEST_F(NetworkServiceTest, DestroyingServiceDestroysContext) {
+ mojom::NetworkContextPtr network_context;
+ service()->CreateNetworkContext(mojo::MakeRequest(&network_context),
+ CreateContextParams());
+ base::RunLoop run_loop;
+ network_context.set_connection_error_handler(run_loop.QuitClosure());
+ DestroyService();
+
+ // Destroying the service should destroy the context, causing a connection
+ // error.
+ run_loop.Run();
+}
+
+namespace {
+
+class ServiceTestClient : public service_manager::test::ServiceTestClient,
+ public service_manager::mojom::ServiceFactory {
+ public:
+ explicit ServiceTestClient(service_manager::test::ServiceTest* test)
+ : service_manager::test::ServiceTestClient(test) {
+ registry_.AddInterface<service_manager::mojom::ServiceFactory>(base::Bind(
+ &ServiceTestClient::BindServiceFactoryRequest, base::Unretained(this)));
+ }
+ ~ServiceTestClient() override {}
+
+ protected:
+ void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
+ registry_.BindInterface(interface_name, std::move(interface_pipe));
+ }
+
+ void CreateService(
+ service_manager::mojom::ServiceRequest request,
+ const std::string& name,
+ service_manager::mojom::PIDReceiverPtr pid_receiver) override {
+ if (name == kNetworkServiceName) {
+ service_context_.reset(new service_manager::ServiceContext(
+ NetworkService::CreateForTesting(), std::move(request)));
+ }
+ }
+
+ void BindServiceFactoryRequest(
+ service_manager::mojom::ServiceFactoryRequest request) {
+ service_factory_bindings_.AddBinding(this, std::move(request));
+ }
+
+ std::unique_ptr<service_manager::ServiceContext> service_context_;
+
+ private:
+ service_manager::BinderRegistry registry_;
+ mojo::BindingSet<service_manager::mojom::ServiceFactory>
+ service_factory_bindings_;
+};
+
+} // namespace
+
+class NetworkServiceTestWithService
+ : public service_manager::test::ServiceTest {
+ public:
+ NetworkServiceTestWithService()
+ : ServiceTest("network_unittests",
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+ ~NetworkServiceTestWithService() override {}
+
+ void LoadURL(const GURL& url) {
+ ResourceRequest request;
+ request.url = url;
+ request.method = "GET";
+ request.request_initiator = url::Origin();
+ StartLoadingURL(request, 0);
+ client_->RunUntilComplete();
+ }
+
+ void StartLoadingURL(const ResourceRequest& request, uint32_t process_id) {
+ client_.reset(new TestURLLoaderClient());
+ mojom::URLLoaderFactoryPtr loader_factory;
+ network_context_->CreateURLLoaderFactory(mojo::MakeRequest(&loader_factory),
+ process_id);
+
+ loader_factory->CreateLoaderAndStart(
+ mojo::MakeRequest(&loader_), 1, 1, mojom::kURLLoadOptionNone, request,
+ client_->CreateInterfacePtr(),
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
+ }
+
+ net::EmbeddedTestServer* test_server() { return &test_server_; }
+ TestURLLoaderClient* client() { return client_.get(); }
+ mojom::URLLoader* loader() { return loader_.get(); }
+ mojom::NetworkService* service() { return network_service_.get(); }
+ mojom::NetworkContext* context() { return network_context_.get(); }
+
+ private:
+ std::unique_ptr<service_manager::Service> CreateService() override {
+ return std::make_unique<ServiceTestClient>(this);
+ }
+
+ void SetUp() override {
+ base::FilePath services_test_data(FILE_PATH_LITERAL("services/test/data"));
+ test_server_.AddDefaultHandlers(services_test_data);
+ ASSERT_TRUE(test_server_.Start());
+ service_manager::test::ServiceTest::SetUp();
+ connector()->BindInterface(kNetworkServiceName, &network_service_);
+ mojom::NetworkContextParamsPtr context_params =
+ mojom::NetworkContextParams::New();
+ network_service_->CreateNetworkContext(mojo::MakeRequest(&network_context_),
+ std::move(context_params));
+ }
+
+ net::EmbeddedTestServer test_server_;
+ std::unique_ptr<TestURLLoaderClient> client_;
+ mojom::NetworkServicePtr network_service_;
+ mojom::NetworkContextPtr network_context_;
+ mojom::URLLoaderPtr loader_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkServiceTestWithService);
+};
+
+// Verifies that loading a URL through the network service's mojo interface
+// works.
+TEST_F(NetworkServiceTestWithService, Basic) {
+ LoadURL(test_server()->GetURL("/echo"));
+ EXPECT_EQ(net::OK, client()->completion_status().error_code);
+}
+
+// Verifies that raw headers are only reported if requested.
+TEST_F(NetworkServiceTestWithService, RawRequestHeadersAbsent) {
+ ResourceRequest request;
+ request.url = test_server()->GetURL("/server-redirect?/echo");
+ request.method = "GET";
+ request.request_initiator = url::Origin();
+ StartLoadingURL(request, 0);
+ client()->RunUntilRedirectReceived();
+ EXPECT_TRUE(client()->has_received_redirect());
+ EXPECT_TRUE(!client()->response_head().raw_request_response_info);
+ loader()->FollowRedirect();
+ client()->RunUntilComplete();
+ EXPECT_TRUE(!client()->response_head().raw_request_response_info);
+}
+
+TEST_F(NetworkServiceTestWithService, RawRequestHeadersPresent) {
+ ResourceRequest request;
+ request.url = test_server()->GetURL("/server-redirect?/echo");
+ request.method = "GET";
+ request.report_raw_headers = true;
+ request.request_initiator = url::Origin();
+ StartLoadingURL(request, 0);
+ client()->RunUntilRedirectReceived();
+ EXPECT_TRUE(client()->has_received_redirect());
+ {
+ scoped_refptr<HttpRawRequestResponseInfo> request_response_info =
+ client()->response_head().raw_request_response_info;
+ ASSERT_TRUE(request_response_info);
+ EXPECT_EQ(301, request_response_info->http_status_code);
+ EXPECT_EQ("Moved Permanently", request_response_info->http_status_text);
+ EXPECT_TRUE(base::StartsWith(request_response_info->request_headers_text,
+ "GET /server-redirect?/echo HTTP/1.1\r\n",
+ base::CompareCase::SENSITIVE));
+ EXPECT_GE(request_response_info->request_headers.size(), 1lu);
+ EXPECT_GE(request_response_info->response_headers.size(), 1lu);
+ EXPECT_TRUE(base::StartsWith(request_response_info->response_headers_text,
+ "HTTP/1.1 301 Moved Permanently\r",
+ base::CompareCase::SENSITIVE));
+ }
+ loader()->FollowRedirect();
+ client()->RunUntilComplete();
+ {
+ scoped_refptr<HttpRawRequestResponseInfo> request_response_info =
+ client()->response_head().raw_request_response_info;
+ EXPECT_EQ(200, request_response_info->http_status_code);
+ EXPECT_EQ("OK", request_response_info->http_status_text);
+ EXPECT_TRUE(base::StartsWith(request_response_info->request_headers_text,
+ "GET /echo HTTP/1.1\r\n",
+ base::CompareCase::SENSITIVE));
+ EXPECT_GE(request_response_info->request_headers.size(), 1lu);
+ EXPECT_GE(request_response_info->response_headers.size(), 1lu);
+ EXPECT_TRUE(base::StartsWith(request_response_info->response_headers_text,
+ "HTTP/1.1 200 OK\r",
+ base::CompareCase::SENSITIVE));
+ }
+}
+
+TEST_F(NetworkServiceTestWithService, RawRequestAccessControl) {
+ const uint32_t process_id = 42;
+ ResourceRequest request;
+ request.url = test_server()->GetURL("/nocache.html");
+ request.method = "GET";
+ request.report_raw_headers = true;
+ request.request_initiator = url::Origin();
+
+ StartLoadingURL(request, process_id);
+ client()->RunUntilComplete();
+ EXPECT_FALSE(client()->response_head().raw_request_response_info);
+ service()->SetRawHeadersAccess(process_id, true);
+ StartLoadingURL(request, process_id);
+ client()->RunUntilComplete();
+ {
+ scoped_refptr<HttpRawRequestResponseInfo> request_response_info =
+ client()->response_head().raw_request_response_info;
+ ASSERT_TRUE(request_response_info);
+ EXPECT_EQ(200, request_response_info->http_status_code);
+ EXPECT_EQ("OK", request_response_info->http_status_text);
+ }
+
+ service()->SetRawHeadersAccess(process_id, false);
+ StartLoadingURL(request, process_id);
+ client()->RunUntilComplete();
+ EXPECT_FALSE(client()->response_head().raw_request_response_info.get());
+}
+
+TEST_F(NetworkServiceTestWithService, SetNetworkConditions) {
+ mojom::NetworkConditionsPtr network_conditions =
+ mojom::NetworkConditions::New();
+ network_conditions->offline = true;
+ context()->SetNetworkConditions("42", std::move(network_conditions));
+
+ ResourceRequest request;
+ request.url = test_server()->GetURL("/nocache.html");
+ request.method = "GET";
+
+ StartLoadingURL(request, 0);
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::OK, client()->completion_status().error_code);
+
+ request.headers.AddHeaderFromString(
+ "X-DevTools-Emulate-Network-Conditions-Client-Id: 42");
+ StartLoadingURL(request, 0);
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::ERR_INTERNET_DISCONNECTED,
+ client()->completion_status().error_code);
+
+ network_conditions = mojom::NetworkConditions::New();
+ network_conditions->offline = false;
+ context()->SetNetworkConditions("42", std::move(network_conditions));
+ StartLoadingURL(request, 0);
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::OK, client()->completion_status().error_code);
+
+ network_conditions = mojom::NetworkConditions::New();
+ network_conditions->offline = true;
+ context()->SetNetworkConditions("42", std::move(network_conditions));
+
+ request.headers.AddHeaderFromString(
+ "X-DevTools-Emulate-Network-Conditions-Client-Id: 42");
+ StartLoadingURL(request, 0);
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::ERR_INTERNET_DISCONNECTED,
+ client()->completion_status().error_code);
+ context()->SetNetworkConditions("42", nullptr);
+ StartLoadingURL(request, 0);
+ client()->RunUntilComplete();
+ EXPECT_EQ(net::OK, client()->completion_status().error_code);
+}
+
+class TestNetworkChangeManagerClient
+ : public mojom::NetworkChangeManagerClient {
+ public:
+ explicit TestNetworkChangeManagerClient(
+ mojom::NetworkService* network_service)
+ : connection_type_(mojom::ConnectionType::CONNECTION_UNKNOWN),
+ binding_(this) {
+ mojom::NetworkChangeManagerPtr manager_ptr;
+ mojom::NetworkChangeManagerRequest request(mojo::MakeRequest(&manager_ptr));
+ network_service->GetNetworkChangeManager(std::move(request));
+
+ mojom::NetworkChangeManagerClientPtr client_ptr;
+ mojom::NetworkChangeManagerClientRequest client_request(
+ mojo::MakeRequest(&client_ptr));
+ binding_.Bind(std::move(client_request));
+ manager_ptr->RequestNotifications(std::move(client_ptr));
+ }
+
+ ~TestNetworkChangeManagerClient() override {}
+
+ // NetworkChangeManagerClient implementation:
+ void OnInitialConnectionType(mojom::ConnectionType type) override {
+ if (type == connection_type_)
+ run_loop_.Quit();
+ }
+
+ void OnNetworkChanged(mojom::ConnectionType type) override {
+ if (type == connection_type_)
+ run_loop_.Quit();
+ }
+
+ // Waits for the desired |connection_type| notification.
+ void WaitForNotification(mojom::ConnectionType type) {
+ connection_type_ = type;
+ run_loop_.Run();
+ }
+
+ private:
+ base::RunLoop run_loop_;
+ mojom::ConnectionType connection_type_;
+ mojo::Binding<mojom::NetworkChangeManagerClient> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestNetworkChangeManagerClient);
+};
+
+class NetworkChangeTest : public testing::Test {
+ public:
+ NetworkChangeTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {
+ service_ = NetworkService::CreateForTesting();
+ }
+
+ ~NetworkChangeTest() override {}
+
+ NetworkService* service() const { return service_.get(); }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+#if defined(OS_ANDROID)
+ // On Android, NetworkChangeNotifier setup is more involved and needs to
+ // to be split between UI thread and network thread. Use a mock
+ // NetworkChangeNotifier in tests, so the test setup is simpler.
+ net::test::MockNetworkChangeNotifier network_change_notifier_;
+#endif
+ std::unique_ptr<NetworkService> service_;
+};
+
+// mojom:NetworkChangeManager isn't supported on these platforms.
+// See the same ifdef in CreateNetworkChangeNotifierIfNeeded.
+#if defined(OS_CHROMEOS) || defined(OS_FUCHSIA) || defined(OS_IOS)
+#define MAYBE_NetworkChangeManagerRequest DISABLED_NetworkChangeManagerRequest
+#else
+#define MAYBE_NetworkChangeManagerRequest NetworkChangeManagerRequest
+#endif
+TEST_F(NetworkChangeTest, MAYBE_NetworkChangeManagerRequest) {
+ TestNetworkChangeManagerClient manager_client(service());
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ manager_client.WaitForNotification(mojom::ConnectionType::CONNECTION_3G);
+}
+
+class NetworkServiceNetworkChangeTest
+ : public service_manager::test::ServiceTest {
+ public:
+ NetworkServiceNetworkChangeTest()
+ : ServiceTest("network_unittests",
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+ ~NetworkServiceNetworkChangeTest() override {}
+
+ mojom::NetworkService* service() { return network_service_.get(); }
+
+ private:
+ // A ServiceTestClient that broadcasts a network change notification in the
+ // network service's process.
+ class ServiceTestClientWithNetworkChange : public ServiceTestClient {
+ public:
+ explicit ServiceTestClientWithNetworkChange(
+ service_manager::test::ServiceTest* test)
+ : ServiceTestClient(test) {}
+ ~ServiceTestClientWithNetworkChange() override {}
+
+ protected:
+ void CreateService(
+ service_manager::mojom::ServiceRequest request,
+ const std::string& name,
+ service_manager::mojom::PIDReceiverPtr pid_receiver) override {
+ if (name == kNetworkServiceName) {
+ service_context_.reset(new service_manager::ServiceContext(
+ NetworkService::CreateForTesting(), std::move(request)));
+ // Send a broadcast after NetworkService is actually created.
+ // Otherwise, this NotifyObservers is a no-op.
+ net::NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
+ net::NetworkChangeNotifier::CONNECTION_3G);
+ }
+ }
+ };
+ std::unique_ptr<service_manager::Service> CreateService() override {
+ return std::make_unique<ServiceTestClientWithNetworkChange>(this);
+ }
+
+ void SetUp() override {
+ service_manager::test::ServiceTest::SetUp();
+ connector()->BindInterface(kNetworkServiceName, &network_service_);
+ }
+
+ mojom::NetworkServicePtr network_service_;
+#if defined(OS_ANDROID)
+ // On Android, NetworkChangeNotifier setup is more involved and needs
+ // to be split between UI thread and network thread. Use a mock
+ // NetworkChangeNotifier in tests, so the test setup is simpler.
+ net::test::MockNetworkChangeNotifier network_change_notifier_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkServiceNetworkChangeTest);
+};
+
+TEST_F(NetworkServiceNetworkChangeTest, MAYBE_NetworkChangeManagerRequest) {
+ TestNetworkChangeManagerClient manager_client(service());
+ manager_client.WaitForNotification(mojom::ConnectionType::CONNECTION_3G);
+}
+
+} // namespace
+
+} // namespace network
diff --git a/chromium/services/network/proxy_config_service_mojo.h b/chromium/services/network/proxy_config_service_mojo.h
index d8fb3455721..c08515ebe7a 100644
--- a/chromium/services/network/proxy_config_service_mojo.h
+++ b/chromium/services/network/proxy_config_service_mojo.h
@@ -5,13 +5,14 @@
#ifndef SERVICES_NETWORK_PROXY_CONFIG_SERVICE_MOJO_H_
#define SERVICES_NETWORK_PROXY_CONFIG_SERVICE_MOJO_H_
+#include "base/component_export.h"
#include "base/macros.h"
#include "base/observer_list.h"
#include "base/optional.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "net/proxy/proxy_config.h"
-#include "net/proxy/proxy_config_service.h"
-#include "services/network/public/interfaces/proxy_config.mojom.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/proxy_resolution/proxy_config_service.h"
+#include "services/network/public/mojom/proxy_config.mojom.h"
namespace net {
class ProxyConfig;
@@ -20,8 +21,9 @@ class ProxyConfig;
namespace network {
// ProxyConfigService that gets its proxy configuration over a Mojo pipe.
-class ProxyConfigServiceMojo : public net::ProxyConfigService,
- public mojom::ProxyConfigClient {
+class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyConfigServiceMojo
+ : public net::ProxyConfigService,
+ public mojom::ProxyConfigClient {
public:
// |proxy_config_client_request| is the Mojo pipe over which new
// configurations are received. |initial_proxy_config| is the initial proxy
diff --git a/chromium/services/network/proxy_config_service_mojo_unittest.cc b/chromium/services/network/proxy_config_service_mojo_unittest.cc
index 75730d9cc7c..39543f1cdd2 100644
--- a/chromium/services/network/proxy_config_service_mojo_unittest.cc
+++ b/chromium/services/network/proxy_config_service_mojo_unittest.cc
@@ -6,9 +6,9 @@
#include "base/macros.h"
#include "base/test/scoped_task_environment.h"
-#include "net/proxy/proxy_config.h"
-#include "net/proxy/proxy_config_service.h"
-#include "services/network/public/interfaces/proxy_config.mojom.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/proxy_resolution/proxy_config_service.h"
+#include "services/network/public/mojom/proxy_config.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
diff --git a/chromium/services/network/proxy_resolver_factory_mojo.cc b/chromium/services/network/proxy_resolver_factory_mojo.cc
new file mode 100644
index 00000000000..c397eed40c2
--- /dev/null
+++ b/chromium/services/network/proxy_resolver_factory_mojo.cc
@@ -0,0 +1,377 @@
+// Copyright 2015 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/network/proxy_resolver_factory_mojo.h"
+
+#include <set>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/sequence_checker.h"
+#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "net/base/load_states.h"
+#include "net/base/net_errors.h"
+#include "net/dns/mojo_host_resolver_impl.h"
+#include "net/interfaces/host_resolver_service.mojom.h"
+#include "net/log/net_log.h"
+#include "net/log/net_log_capture_mode.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
+#include "net/proxy_resolution/pac_file_data.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolver.h"
+#include "net/proxy_resolution/proxy_resolver_error_observer.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+
+namespace network {
+
+namespace {
+
+std::unique_ptr<base::Value> NetLogErrorCallback(
+ int line_number,
+ const std::string* message,
+ net::NetLogCaptureMode /* capture_mode */) {
+ std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+ dict->SetInteger("line_number", line_number);
+ dict->SetString("message", *message);
+ return std::move(dict);
+}
+
+// A mixin that forwards logging to (Bound)NetLog and ProxyResolverErrorObserver
+// and DNS requests to a MojoHostResolverImpl, which is implemented in terms of
+// a HostResolver.
+template <typename ClientInterface>
+class ClientMixin : public ClientInterface {
+ public:
+ ClientMixin(net::HostResolver* host_resolver,
+ net::ProxyResolverErrorObserver* error_observer,
+ net::NetLog* net_log,
+ const net::NetLogWithSource& net_log_with_source)
+ : host_resolver_(host_resolver, net_log_with_source),
+ error_observer_(error_observer),
+ net_log_(net_log),
+ net_log_with_source_(net_log_with_source) {}
+
+ // Overridden from ClientInterface:
+ void Alert(const std::string& message) override {
+ auto callback = net::NetLog::StringCallback("message", &message);
+ net_log_with_source_.AddEvent(net::NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ callback);
+ if (net_log_)
+ net_log_->AddGlobalEntry(net::NetLogEventType::PAC_JAVASCRIPT_ALERT,
+ callback);
+ }
+
+ void OnError(int32_t line_number, const std::string& message) override {
+ auto callback = base::Bind(&NetLogErrorCallback, line_number, &message);
+ net_log_with_source_.AddEvent(net::NetLogEventType::PAC_JAVASCRIPT_ERROR,
+ callback);
+ if (net_log_)
+ net_log_->AddGlobalEntry(net::NetLogEventType::PAC_JAVASCRIPT_ERROR,
+ callback);
+ if (error_observer_) {
+ error_observer_->OnPACScriptError(line_number,
+ base::UTF8ToUTF16(message));
+ }
+ }
+
+ void ResolveDns(
+ std::unique_ptr<net::HostResolver::RequestInfo> request_info,
+ net::interfaces::HostResolverRequestClientPtr client) override {
+ host_resolver_.Resolve(std::move(request_info), std::move(client));
+ }
+
+ protected:
+ bool dns_request_in_progress() {
+ return host_resolver_.request_in_progress();
+ }
+
+ private:
+ net::MojoHostResolverImpl host_resolver_;
+ net::ProxyResolverErrorObserver* const error_observer_;
+ net::NetLog* const net_log_;
+ const net::NetLogWithSource net_log_with_source_;
+};
+
+// Implementation of ProxyResolver that connects to a Mojo service to evaluate
+// PAC scripts. This implementation only knows about Mojo services, and
+// therefore that service may live in or out of process.
+//
+// This implementation reports disconnections from the Mojo service (i.e. if the
+// service is out-of-process and that process crashes) using the error code
+// ERR_PAC_SCRIPT_TERMINATED.
+class ProxyResolverMojo : public net::ProxyResolver {
+ public:
+ // Constructs a ProxyResolverMojo that connects to a mojo proxy resolver
+ // implementation using |resolver_ptr|. The implementation uses
+ // |host_resolver| as the DNS resolver, using |host_resolver_binding| to
+ // communicate with it.
+ ProxyResolverMojo(
+ proxy_resolver::mojom::ProxyResolverPtr resolver_ptr,
+ net::HostResolver* host_resolver,
+ std::unique_ptr<net::ProxyResolverErrorObserver> error_observer,
+ net::NetLog* net_log);
+ ~ProxyResolverMojo() override;
+
+ // ProxyResolver implementation:
+ int GetProxyForURL(const GURL& url,
+ net::ProxyInfo* results,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<Request>* request,
+ const net::NetLogWithSource& net_log) override;
+
+ private:
+ class Job;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ // Mojo error handler.
+ void OnConnectionError();
+
+ // Connection to the Mojo proxy resolver.
+ proxy_resolver::mojom::ProxyResolverPtr mojo_proxy_resolver_ptr_;
+
+ net::HostResolver* host_resolver_;
+
+ std::unique_ptr<net::ProxyResolverErrorObserver> error_observer_;
+
+ net::NetLog* net_log_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolverMojo);
+};
+
+class ProxyResolverMojo::Job
+ : public ProxyResolver::Request,
+ public ClientMixin<proxy_resolver::mojom::ProxyResolverRequestClient> {
+ public:
+ Job(ProxyResolverMojo* resolver,
+ const GURL& url,
+ net::ProxyInfo* results,
+ const net::CompletionCallback& callback,
+ const net::NetLogWithSource& net_log);
+ ~Job() override;
+
+ // Returns the LoadState of this job.
+ net::LoadState GetLoadState() override;
+
+ private:
+ // Mojo error handler.
+ void OnConnectionError();
+
+ // Overridden from proxy_resolver::mojom::ProxyResolverRequestClient:
+ void ReportResult(int32_t error, const net::ProxyInfo& proxy_info) override;
+
+ // Completes a request with a result code.
+ void CompleteRequest(int result);
+
+ const GURL url_;
+ net::ProxyInfo* results_;
+ net::CompletionCallback callback_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+ mojo::Binding<proxy_resolver::mojom::ProxyResolverRequestClient> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(Job);
+};
+
+ProxyResolverMojo::Job::Job(ProxyResolverMojo* resolver,
+ const GURL& url,
+ net::ProxyInfo* results,
+ const net::CompletionCallback& callback,
+ const net::NetLogWithSource& net_log)
+ : ClientMixin<proxy_resolver::mojom::ProxyResolverRequestClient>(
+ resolver->host_resolver_,
+ resolver->error_observer_.get(),
+ resolver->net_log_,
+ net_log),
+ url_(url),
+ results_(results),
+ callback_(callback),
+ binding_(this) {
+ proxy_resolver::mojom::ProxyResolverRequestClientPtr client;
+ binding_.Bind(mojo::MakeRequest(&client));
+ resolver->mojo_proxy_resolver_ptr_->GetProxyForUrl(url_, std::move(client));
+ binding_.set_connection_error_handler(base::Bind(
+ &ProxyResolverMojo::Job::OnConnectionError, base::Unretained(this)));
+}
+
+ProxyResolverMojo::Job::~Job() {}
+
+net::LoadState ProxyResolverMojo::Job::GetLoadState() {
+ return dns_request_in_progress()
+ ? net::LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT
+ : net::LOAD_STATE_RESOLVING_PROXY_FOR_URL;
+}
+
+void ProxyResolverMojo::Job::OnConnectionError() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DVLOG(1) << "ProxyResolverMojo::Job::OnConnectionError";
+ CompleteRequest(net::ERR_PAC_SCRIPT_TERMINATED);
+}
+
+void ProxyResolverMojo::Job::CompleteRequest(int result) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ net::CompletionCallback callback = base::ResetAndReturn(&callback_);
+ binding_.Close();
+ callback.Run(result);
+}
+
+void ProxyResolverMojo::Job::ReportResult(int32_t error,
+ const net::ProxyInfo& proxy_info) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DVLOG(1) << "ProxyResolverMojo::Job::ReportResult: " << error;
+
+ if (error == net::OK) {
+ *results_ = proxy_info;
+ DVLOG(1) << "Servers: " << results_->ToPacString();
+ }
+
+ CompleteRequest(error);
+}
+
+ProxyResolverMojo::ProxyResolverMojo(
+ proxy_resolver::mojom::ProxyResolverPtr resolver_ptr,
+ net::HostResolver* host_resolver,
+ std::unique_ptr<net::ProxyResolverErrorObserver> error_observer,
+ net::NetLog* net_log)
+ : mojo_proxy_resolver_ptr_(std::move(resolver_ptr)),
+ host_resolver_(host_resolver),
+ error_observer_(std::move(error_observer)),
+ net_log_(net_log) {
+ mojo_proxy_resolver_ptr_.set_connection_error_handler(base::Bind(
+ &ProxyResolverMojo::OnConnectionError, base::Unretained(this)));
+}
+
+ProxyResolverMojo::~ProxyResolverMojo() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+}
+
+void ProxyResolverMojo::OnConnectionError() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DVLOG(1) << "ProxyResolverMojo::OnConnectionError";
+
+ // Disconnect from the Mojo proxy resolver service.
+ mojo_proxy_resolver_ptr_.reset();
+}
+
+int ProxyResolverMojo::GetProxyForURL(const GURL& url,
+ net::ProxyInfo* results,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<Request>* request,
+ const net::NetLogWithSource& net_log) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+ if (!mojo_proxy_resolver_ptr_)
+ return net::ERR_PAC_SCRIPT_TERMINATED;
+
+ *request = std::make_unique<Job>(this, url, results, callback, net_log);
+
+ return net::ERR_IO_PENDING;
+}
+
+} // namespace
+
+// A Job to create a ProxyResolver instance.
+//
+// Note: a Job instance is not tied to a particular resolve request, and hence
+// there is no per-request logging to be done (any netlog events are only sent
+// globally) so this always uses an empty NetLogWithSource.
+class ProxyResolverFactoryMojo::Job
+ : public ClientMixin<
+ proxy_resolver::mojom::ProxyResolverFactoryRequestClient>,
+ public ProxyResolverFactory::Request {
+ public:
+ Job(ProxyResolverFactoryMojo* factory,
+ const scoped_refptr<net::ProxyResolverScriptData>& pac_script,
+ std::unique_ptr<net::ProxyResolver>* resolver,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<net::ProxyResolverErrorObserver> error_observer)
+ : ClientMixin<proxy_resolver::mojom::ProxyResolverFactoryRequestClient>(
+ factory->host_resolver_,
+ error_observer.get(),
+ factory->net_log_,
+ net::NetLogWithSource()),
+ factory_(factory),
+ resolver_(resolver),
+ callback_(callback),
+ binding_(this),
+ error_observer_(std::move(error_observer)) {
+ proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr client;
+ binding_.Bind(mojo::MakeRequest(&client));
+ factory_->mojo_proxy_factory_->CreateResolver(
+ base::UTF16ToUTF8(pac_script->utf16()),
+ mojo::MakeRequest(&resolver_ptr_), std::move(client));
+ resolver_ptr_.set_connection_error_handler(
+ base::Bind(&ProxyResolverFactoryMojo::Job::OnConnectionError,
+ base::Unretained(this)));
+ binding_.set_connection_error_handler(
+ base::Bind(&ProxyResolverFactoryMojo::Job::OnConnectionError,
+ base::Unretained(this)));
+ }
+
+ void OnConnectionError() { ReportResult(net::ERR_PAC_SCRIPT_TERMINATED); }
+
+ private:
+ void ReportResult(int32_t error) override {
+ resolver_ptr_.set_connection_error_handler(base::Closure());
+ binding_.set_connection_error_handler(base::Closure());
+ if (error == net::OK) {
+ resolver_->reset(new ProxyResolverMojo(
+ std::move(resolver_ptr_), factory_->host_resolver_,
+ std::move(error_observer_), factory_->net_log_));
+ }
+ callback_.Run(error);
+ }
+
+ ProxyResolverFactoryMojo* const factory_;
+ std::unique_ptr<net::ProxyResolver>* resolver_;
+ const net::CompletionCallback callback_;
+ proxy_resolver::mojom::ProxyResolverPtr resolver_ptr_;
+ mojo::Binding<proxy_resolver::mojom::ProxyResolverFactoryRequestClient>
+ binding_;
+ std::unique_ptr<net::ProxyResolverErrorObserver> error_observer_;
+};
+
+ProxyResolverFactoryMojo::ProxyResolverFactoryMojo(
+ proxy_resolver::mojom::ProxyResolverFactoryPtr mojo_proxy_factory,
+ net::HostResolver* host_resolver,
+ const base::Callback<std::unique_ptr<net::ProxyResolverErrorObserver>()>&
+ error_observer_factory,
+ net::NetLog* net_log)
+ : ProxyResolverFactory(true),
+ mojo_proxy_factory_(std::move(mojo_proxy_factory)),
+ host_resolver_(host_resolver),
+ error_observer_factory_(error_observer_factory),
+ net_log_(net_log),
+ weak_ptr_factory_(this) {}
+
+ProxyResolverFactoryMojo::~ProxyResolverFactoryMojo() = default;
+
+int ProxyResolverFactoryMojo::CreateProxyResolver(
+ const scoped_refptr<net::ProxyResolverScriptData>& pac_script,
+ std::unique_ptr<net::ProxyResolver>* resolver,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<net::ProxyResolverFactory::Request>* request) {
+ DCHECK(resolver);
+ DCHECK(request);
+ if (pac_script->type() !=
+ net::ProxyResolverScriptData::TYPE_SCRIPT_CONTENTS ||
+ pac_script->utf16().empty()) {
+ return net::ERR_PAC_SCRIPT_FAILED;
+ }
+ request->reset(new Job(this, pac_script, resolver, callback,
+ error_observer_factory_.is_null()
+ ? nullptr
+ : error_observer_factory_.Run()));
+ return net::ERR_IO_PENDING;
+}
+
+} // namespace network
diff --git a/chromium/services/network/proxy_resolver_factory_mojo.h b/chromium/services/network/proxy_resolver_factory_mojo.h
new file mode 100644
index 00000000000..f3c86f5c04e
--- /dev/null
+++ b/chromium/services/network/proxy_resolver_factory_mojo.h
@@ -0,0 +1,64 @@
+// Copyright 2015 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 SERVICES_NETWORK_PROXY_RESOLVER_FACTORY_MOJO_H_
+#define SERVICES_NETWORK_PROXY_RESOLVER_FACTORY_MOJO_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "net/base/completion_callback.h"
+#include "net/proxy_resolution/proxy_resolver_factory.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+
+namespace net {
+class HostResolver;
+class NetLog;
+class ProxyResolverErrorObserver;
+class ProxyResolverScriptData;
+} // namespace net
+
+namespace network {
+
+// Implementation of ProxyResolverFactory that connects to a Mojo service to
+// create implementations of a Mojo proxy resolver to back a ProxyResolverMojo.
+class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolverFactoryMojo
+ : public net::ProxyResolverFactory {
+ public:
+ ProxyResolverFactoryMojo(
+ proxy_resolver::mojom::ProxyResolverFactoryPtr mojo_proxy_factory,
+ net::HostResolver* host_resolver,
+ const base::Callback<std::unique_ptr<net::ProxyResolverErrorObserver>()>&
+ error_observer_factory,
+ net::NetLog* net_log);
+ ~ProxyResolverFactoryMojo() override;
+
+ // ProxyResolverFactory override.
+ int CreateProxyResolver(
+ const scoped_refptr<net::ProxyResolverScriptData>& pac_script,
+ std::unique_ptr<net::ProxyResolver>* resolver,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<Request>* request) override;
+
+ private:
+ class Job;
+
+ proxy_resolver::mojom::ProxyResolverFactoryPtr mojo_proxy_factory_;
+ net::HostResolver* const host_resolver_;
+ const base::Callback<std::unique_ptr<net::ProxyResolverErrorObserver>()>
+ error_observer_factory_;
+ net::NetLog* const net_log_;
+
+ base::WeakPtrFactory<ProxyResolverFactoryMojo> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolverFactoryMojo);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PROXY_RESOLVER_FACTORY_MOJO_H_
diff --git a/chromium/services/network/proxy_resolver_factory_mojo_unittest.cc b/chromium/services/network/proxy_resolver_factory_mojo_unittest.cc
new file mode 100644
index 00000000000..fbc7ef34626
--- /dev/null
+++ b/chromium/services/network/proxy_resolver_factory_mojo_unittest.cc
@@ -0,0 +1,916 @@
+// Copyright 2015 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/network/proxy_resolver_factory_mojo.h"
+
+#include <list>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/containers/queue.h"
+#include "base/memory/ptr_util.h"
+#include "base/run_loop.h"
+#include "base/stl_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/values.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "net/base/load_states.h"
+#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
+#include "net/dns/host_resolver.h"
+#include "net/log/net_log_event_type.h"
+#include "net/log/net_log_with_source.h"
+#include "net/log/test_net_log.h"
+#include "net/proxy_resolution/pac_file_data.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolver.h"
+#include "net/proxy_resolution/proxy_resolver_error_observer.h"
+#include "net/proxy_resolution/proxy_resolver_factory.h"
+#include "net/test/event_waiter.h"
+#include "net/test/gtest_util.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+using net::test::IsError;
+using net::test::IsOk;
+
+namespace network {
+
+namespace {
+
+const char kScriptData[] = "FooBarBaz";
+const char kExampleUrl[] = "http://www.example.com";
+
+struct CreateProxyResolverAction {
+ enum Action {
+ COMPLETE,
+ DROP_CLIENT,
+ DROP_RESOLVER,
+ DROP_BOTH,
+ WAIT_FOR_CLIENT_DISCONNECT,
+ MAKE_DNS_REQUEST,
+ };
+
+ static CreateProxyResolverAction ReturnResult(
+ const std::string& expected_pac_script,
+ net::Error error) {
+ CreateProxyResolverAction result;
+ result.expected_pac_script = expected_pac_script;
+ result.error = error;
+ return result;
+ }
+
+ static CreateProxyResolverAction DropClient(
+ const std::string& expected_pac_script) {
+ CreateProxyResolverAction result;
+ result.expected_pac_script = expected_pac_script;
+ result.action = DROP_CLIENT;
+ return result;
+ }
+
+ static CreateProxyResolverAction DropResolver(
+ const std::string& expected_pac_script) {
+ CreateProxyResolverAction result;
+ result.expected_pac_script = expected_pac_script;
+ result.action = DROP_RESOLVER;
+ return result;
+ }
+
+ static CreateProxyResolverAction DropBoth(
+ const std::string& expected_pac_script) {
+ CreateProxyResolverAction result;
+ result.expected_pac_script = expected_pac_script;
+ result.action = DROP_BOTH;
+ return result;
+ }
+
+ static CreateProxyResolverAction WaitForClientDisconnect(
+ const std::string& expected_pac_script) {
+ CreateProxyResolverAction result;
+ result.expected_pac_script = expected_pac_script;
+ result.action = WAIT_FOR_CLIENT_DISCONNECT;
+ return result;
+ }
+
+ static CreateProxyResolverAction MakeDnsRequest(
+ const std::string& expected_pac_script) {
+ CreateProxyResolverAction result;
+ result.expected_pac_script = expected_pac_script;
+ result.action = MAKE_DNS_REQUEST;
+ return result;
+ }
+
+ std::string expected_pac_script;
+ Action action = COMPLETE;
+ net::Error error = net::OK;
+};
+
+struct GetProxyForUrlAction {
+ enum Action {
+ COMPLETE,
+ // Drop the request by closing the reply channel.
+ DROP,
+ // Disconnect the service.
+ DISCONNECT,
+ // Wait for the client pipe to be disconnected.
+ WAIT_FOR_CLIENT_DISCONNECT,
+ // Make a DNS request.
+ MAKE_DNS_REQUEST,
+ };
+
+ GetProxyForUrlAction() {}
+ GetProxyForUrlAction(const GetProxyForUrlAction& other) = default;
+
+ static GetProxyForUrlAction ReturnError(const GURL& url, net::Error error) {
+ GetProxyForUrlAction result;
+ result.expected_url = url;
+ result.error = error;
+ return result;
+ }
+
+ static GetProxyForUrlAction ReturnServers(const GURL& url,
+ const net::ProxyInfo& proxy_info) {
+ GetProxyForUrlAction result;
+ result.expected_url = url;
+ result.proxy_info = proxy_info;
+ return result;
+ }
+
+ static GetProxyForUrlAction DropRequest(const GURL& url) {
+ GetProxyForUrlAction result;
+ result.expected_url = url;
+ result.action = DROP;
+ return result;
+ }
+
+ static GetProxyForUrlAction Disconnect(const GURL& url) {
+ GetProxyForUrlAction result;
+ result.expected_url = url;
+ result.action = DISCONNECT;
+ return result;
+ }
+
+ static GetProxyForUrlAction WaitForClientDisconnect(const GURL& url) {
+ GetProxyForUrlAction result;
+ result.expected_url = url;
+ result.action = WAIT_FOR_CLIENT_DISCONNECT;
+ return result;
+ }
+
+ static GetProxyForUrlAction MakeDnsRequest(const GURL& url) {
+ GetProxyForUrlAction result;
+ result.expected_url = url;
+ result.action = MAKE_DNS_REQUEST;
+ return result;
+ }
+
+ Action action = COMPLETE;
+ net::Error error = net::OK;
+ net::ProxyInfo proxy_info;
+ GURL expected_url;
+};
+
+class MockMojoProxyResolver : public proxy_resolver::mojom::ProxyResolver {
+ public:
+ MockMojoProxyResolver();
+ ~MockMojoProxyResolver() override;
+
+ void AddGetProxyAction(GetProxyForUrlAction action);
+
+ void WaitForNextRequest();
+
+ void ClearBlockedClients();
+
+ void AddConnection(
+ mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver> req);
+
+ private:
+ // Overridden from proxy_resolver::mojom::ProxyResolver:
+ void GetProxyForUrl(
+ const GURL& url,
+ proxy_resolver::mojom::ProxyResolverRequestClientPtr client) override;
+
+ void WakeWaiter();
+
+ std::string pac_script_data_;
+
+ base::queue<GetProxyForUrlAction> get_proxy_actions_;
+
+ base::Closure quit_closure_;
+
+ std::vector<
+ std::unique_ptr<proxy_resolver::mojom::ProxyResolverRequestClientPtr>>
+ blocked_clients_;
+ mojo::Binding<proxy_resolver::mojom::ProxyResolver> binding_;
+};
+
+MockMojoProxyResolver::~MockMojoProxyResolver() {
+ EXPECT_TRUE(get_proxy_actions_.empty())
+ << "Actions remaining: " << get_proxy_actions_.size();
+}
+
+MockMojoProxyResolver::MockMojoProxyResolver() : binding_(this) {}
+
+void MockMojoProxyResolver::AddGetProxyAction(GetProxyForUrlAction action) {
+ get_proxy_actions_.push(action);
+}
+
+void MockMojoProxyResolver::WaitForNextRequest() {
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+}
+
+void MockMojoProxyResolver::WakeWaiter() {
+ if (!quit_closure_.is_null())
+ quit_closure_.Run();
+ quit_closure_.Reset();
+}
+
+void MockMojoProxyResolver::ClearBlockedClients() {
+ blocked_clients_.clear();
+}
+
+void MockMojoProxyResolver::AddConnection(
+ mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver> req) {
+ if (binding_.is_bound())
+ binding_.Close();
+ binding_.Bind(std::move(req));
+}
+
+void MockMojoProxyResolver::GetProxyForUrl(
+ const GURL& url,
+ proxy_resolver::mojom::ProxyResolverRequestClientPtr client) {
+ ASSERT_FALSE(get_proxy_actions_.empty());
+ GetProxyForUrlAction action = get_proxy_actions_.front();
+ get_proxy_actions_.pop();
+
+ EXPECT_EQ(action.expected_url, url);
+ client->Alert(url.spec());
+ client->OnError(12345, url.spec());
+ switch (action.action) {
+ case GetProxyForUrlAction::COMPLETE: {
+ client->ReportResult(action.error, action.proxy_info);
+ break;
+ }
+ case GetProxyForUrlAction::DROP: {
+ client.reset();
+ break;
+ }
+ case GetProxyForUrlAction::DISCONNECT: {
+ binding_.Close();
+ break;
+ }
+ case GetProxyForUrlAction::WAIT_FOR_CLIENT_DISCONNECT: {
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ client.set_connection_error_handler(run_loop.QuitClosure());
+ run_loop.Run();
+ ASSERT_TRUE(client.encountered_error());
+ break;
+ }
+ case GetProxyForUrlAction::MAKE_DNS_REQUEST: {
+ auto request = std::make_unique<net::HostResolver::RequestInfo>(
+ net::HostPortPair(url.spec(), 12345));
+ net::interfaces::HostResolverRequestClientPtr dns_client;
+ mojo::MakeRequest(&dns_client);
+ client->ResolveDns(std::move(request), std::move(dns_client));
+ blocked_clients_.push_back(
+ std::make_unique<
+ proxy_resolver::mojom::ProxyResolverRequestClientPtr>(
+ std::move(client)));
+ break;
+ }
+ }
+ WakeWaiter();
+}
+
+class Request {
+ public:
+ Request(net::ProxyResolver* resolver, const GURL& url);
+
+ int Resolve();
+ void Cancel();
+ int WaitForResult();
+
+ const net::ProxyInfo& results() const { return results_; }
+ net::LoadState load_state() { return request_->GetLoadState(); }
+ net::BoundTestNetLog& net_log() { return net_log_; }
+ const net::TestCompletionCallback& callback() const { return callback_; }
+
+ private:
+ net::ProxyResolver* resolver_;
+ const GURL url_;
+ net::ProxyInfo results_;
+ std::unique_ptr<net::ProxyResolver::Request> request_;
+ int error_;
+ net::TestCompletionCallback callback_;
+ net::BoundTestNetLog net_log_;
+};
+
+Request::Request(net::ProxyResolver* resolver, const GURL& url)
+ : resolver_(resolver), url_(url), error_(0) {}
+
+int Request::Resolve() {
+ error_ = resolver_->GetProxyForURL(url_, &results_, callback_.callback(),
+ &request_, net_log_.bound());
+ return error_;
+}
+
+void Request::Cancel() {
+ request_.reset();
+}
+
+int Request::WaitForResult() {
+ error_ = callback_.WaitForResult();
+ return error_;
+}
+
+class MockMojoProxyResolverFactory
+ : public proxy_resolver::mojom::ProxyResolverFactory {
+ public:
+ MockMojoProxyResolverFactory(
+ MockMojoProxyResolver* resolver,
+ mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolverFactory> req);
+ ~MockMojoProxyResolverFactory() override;
+
+ void AddCreateProxyResolverAction(CreateProxyResolverAction action);
+
+ void WaitForNextRequest();
+
+ void ClearBlockedClients();
+
+ private:
+ // Overridden from proxy_resolver::mojom::ProxyResolver:
+ void CreateResolver(
+ const std::string& pac_url,
+ mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver> request,
+ proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr client)
+ override;
+
+ void WakeWaiter();
+
+ MockMojoProxyResolver* resolver_;
+ base::queue<CreateProxyResolverAction> create_resolver_actions_;
+
+ base::Closure quit_closure_;
+
+ std::vector<std::unique_ptr<
+ proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr>>
+ blocked_clients_;
+ std::vector<std::unique_ptr<
+ mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver>>>
+ blocked_resolver_requests_;
+ mojo::Binding<proxy_resolver::mojom::ProxyResolverFactory> binding_;
+};
+
+MockMojoProxyResolverFactory::MockMojoProxyResolverFactory(
+ MockMojoProxyResolver* resolver,
+ mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolverFactory> req)
+ : resolver_(resolver), binding_(this, std::move(req)) {}
+
+MockMojoProxyResolverFactory::~MockMojoProxyResolverFactory() {
+ EXPECT_TRUE(create_resolver_actions_.empty())
+ << "Actions remaining: " << create_resolver_actions_.size();
+}
+
+void MockMojoProxyResolverFactory::AddCreateProxyResolverAction(
+ CreateProxyResolverAction action) {
+ create_resolver_actions_.push(action);
+}
+
+void MockMojoProxyResolverFactory::WaitForNextRequest() {
+ base::RunLoop run_loop;
+ quit_closure_ = run_loop.QuitClosure();
+ run_loop.Run();
+}
+
+void MockMojoProxyResolverFactory::WakeWaiter() {
+ if (!quit_closure_.is_null())
+ quit_closure_.Run();
+ quit_closure_.Reset();
+}
+
+void MockMojoProxyResolverFactory::ClearBlockedClients() {
+ blocked_clients_.clear();
+}
+
+void MockMojoProxyResolverFactory::CreateResolver(
+ const std::string& pac_script,
+ mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver> request,
+ proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr client) {
+ ASSERT_FALSE(create_resolver_actions_.empty());
+ CreateProxyResolverAction action = create_resolver_actions_.front();
+ create_resolver_actions_.pop();
+
+ EXPECT_EQ(action.expected_pac_script, pac_script);
+ client->Alert(pac_script);
+ client->OnError(12345, pac_script);
+ switch (action.action) {
+ case CreateProxyResolverAction::COMPLETE: {
+ if (action.error == net::OK)
+ resolver_->AddConnection(std::move(request));
+ client->ReportResult(action.error);
+ break;
+ }
+ case CreateProxyResolverAction::DROP_CLIENT: {
+ // Save |request| so its pipe isn't closed.
+ blocked_resolver_requests_.push_back(
+ std::make_unique<
+ mojo::InterfaceRequest<proxy_resolver::mojom::ProxyResolver>>(
+ std::move(request)));
+ break;
+ }
+ case CreateProxyResolverAction::DROP_RESOLVER: {
+ // Save |client| so its pipe isn't closed.
+ blocked_clients_.push_back(
+ std::make_unique<
+ proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr>(
+ std::move(client)));
+ break;
+ }
+ case CreateProxyResolverAction::DROP_BOTH: {
+ // Both |request| and |client| will be closed.
+ break;
+ }
+ case CreateProxyResolverAction::WAIT_FOR_CLIENT_DISCONNECT: {
+ base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+ client.set_connection_error_handler(run_loop.QuitClosure());
+ run_loop.Run();
+ ASSERT_TRUE(client.encountered_error());
+ break;
+ }
+ case CreateProxyResolverAction::MAKE_DNS_REQUEST: {
+ auto request = std::make_unique<net::HostResolver::RequestInfo>(
+ net::HostPortPair(pac_script, 12345));
+ net::interfaces::HostResolverRequestClientPtr dns_client;
+ mojo::MakeRequest(&dns_client);
+ client->ResolveDns(std::move(request), std::move(dns_client));
+ blocked_clients_.push_back(
+ std::make_unique<
+ proxy_resolver::mojom::ProxyResolverFactoryRequestClientPtr>(
+ std::move(client)));
+ break;
+ }
+ }
+ WakeWaiter();
+}
+
+void DeleteResolverFactoryRequestCallback(
+ std::unique_ptr<net::ProxyResolverFactory::Request>* request,
+ const net::CompletionCallback& callback,
+ int result) {
+ ASSERT_TRUE(request);
+ EXPECT_TRUE(request->get());
+ request->reset();
+ callback.Run(result);
+}
+
+class MockHostResolver : public net::HostResolver {
+ public:
+ enum Event {
+ DNS_REQUEST,
+ };
+
+ // net::HostResolver overrides.
+ int Resolve(const RequestInfo& info,
+ net::RequestPriority priority,
+ net::AddressList* addresses,
+ const net::CompletionCallback& callback,
+ std::unique_ptr<Request>* request,
+ const net::NetLogWithSource& source_net_log) override {
+ waiter_.NotifyEvent(DNS_REQUEST);
+ return net::ERR_IO_PENDING;
+ }
+
+ int ResolveFromCache(const RequestInfo& info,
+ net::AddressList* addresses,
+ const net::NetLogWithSource& source_net_log) override {
+ return net::ERR_DNS_CACHE_MISS;
+ }
+
+ int ResolveStaleFromCache(
+ const RequestInfo& info,
+ net::AddressList* addresses,
+ net::HostCache::EntryStaleness* stale_info,
+ const net::NetLogWithSource& source_net_log) override {
+ return net::ERR_DNS_CACHE_MISS;
+ }
+
+ net::HostCache* GetHostCache() override { return nullptr; }
+
+ bool HasCached(base::StringPiece hostname,
+ net::HostCache::Entry::Source* source_out,
+ net::HostCache::EntryStaleness* stale_out) const override {
+ return false;
+ }
+
+ net::EventWaiter<Event>& waiter() { return waiter_; }
+
+ private:
+ net::EventWaiter<Event> waiter_;
+};
+
+void CheckCapturedNetLogEntries(const std::string& expected_string,
+ const net::TestNetLogEntry::List& entries) {
+ ASSERT_EQ(2u, entries.size());
+ EXPECT_EQ(net::NetLogEventType::PAC_JAVASCRIPT_ALERT, entries[0].type);
+ std::string message;
+ ASSERT_TRUE(entries[0].GetStringValue("message", &message));
+ EXPECT_EQ(expected_string, message);
+ ASSERT_FALSE(entries[0].params->HasKey("line_number"));
+ message.clear();
+ EXPECT_EQ(net::NetLogEventType::PAC_JAVASCRIPT_ERROR, entries[1].type);
+ ASSERT_TRUE(entries[1].GetStringValue("message", &message));
+ EXPECT_EQ(expected_string, message);
+ int line_number = 0;
+ ASSERT_TRUE(entries[1].GetIntegerValue("line_number", &line_number));
+ EXPECT_EQ(12345, line_number);
+}
+
+} // namespace
+
+class ProxyResolverFactoryMojoTest : public testing::Test {
+ public:
+ void SetUp() override {
+ proxy_resolver::mojom::ProxyResolverFactoryPtr factory_ptr;
+ mock_proxy_resolver_factory_.reset(new MockMojoProxyResolverFactory(
+ &mock_proxy_resolver_, mojo::MakeRequest(&factory_ptr)));
+ proxy_resolver_factory_mojo_.reset(new ProxyResolverFactoryMojo(
+ std::move(factory_ptr), &host_resolver_,
+ base::Callback<std::unique_ptr<net::ProxyResolverErrorObserver>()>(),
+ &net_log_));
+ }
+
+ std::unique_ptr<Request> MakeRequest(const GURL& url) {
+ return std::make_unique<Request>(proxy_resolver_mojo_.get(), url);
+ }
+
+ net::ProxyInfo ProxyServersFromPacString(const std::string& pac_string) {
+ net::ProxyInfo proxy_info;
+ proxy_info.UsePacString(pac_string);
+ return proxy_info;
+ }
+
+ void CreateProxyResolver() {
+ mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
+ CreateProxyResolverAction::ReturnResult(kScriptData, net::OK));
+ net::TestCompletionCallback callback;
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(kScriptData));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ ASSERT_EQ(
+ net::OK,
+ callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request)));
+ EXPECT_TRUE(request);
+ ASSERT_TRUE(proxy_resolver_mojo_);
+ }
+
+ void DeleteProxyResolverCallback(const net::CompletionCallback& callback,
+ int result) {
+ proxy_resolver_mojo_.reset();
+ callback.Run(result);
+ }
+
+ base::test::ScopedTaskEnvironment task_environment_;
+ MockHostResolver host_resolver_;
+ net::TestNetLog net_log_;
+ std::unique_ptr<MockMojoProxyResolverFactory> mock_proxy_resolver_factory_;
+ std::unique_ptr<net::ProxyResolverFactory> proxy_resolver_factory_mojo_;
+
+ MockMojoProxyResolver mock_proxy_resolver_;
+ std::unique_ptr<net::ProxyResolver> proxy_resolver_mojo_;
+};
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver) {
+ CreateProxyResolver();
+ net::TestNetLogEntry::List entries;
+ net_log_.GetEntries(&entries);
+ CheckCapturedNetLogEntries(kScriptData, entries);
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Empty) {
+ net::TestCompletionCallback callback;
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(""));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ EXPECT_EQ(
+ net::ERR_PAC_SCRIPT_FAILED,
+ callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request)));
+ EXPECT_FALSE(request);
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Url) {
+ net::TestCompletionCallback callback;
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromURL(GURL(kExampleUrl)));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ EXPECT_EQ(
+ net::ERR_PAC_SCRIPT_FAILED,
+ callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request)));
+ EXPECT_FALSE(request);
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Failed) {
+ mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
+ CreateProxyResolverAction::ReturnResult(kScriptData,
+ net::ERR_PAC_STATUS_NOT_OK));
+
+ net::TestCompletionCallback callback;
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(kScriptData));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ EXPECT_EQ(
+ net::ERR_PAC_STATUS_NOT_OK,
+ callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request)));
+ EXPECT_TRUE(request);
+
+ // A second attempt succeeds.
+ CreateProxyResolver();
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_BothDisconnected) {
+ mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
+ CreateProxyResolverAction::DropBoth(kScriptData));
+
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(kScriptData));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ net::TestCompletionCallback callback;
+ EXPECT_EQ(
+ net::ERR_PAC_SCRIPT_TERMINATED,
+ callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request)));
+ EXPECT_TRUE(request);
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_ClientDisconnected) {
+ mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
+ CreateProxyResolverAction::DropClient(kScriptData));
+
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(kScriptData));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ net::TestCompletionCallback callback;
+ EXPECT_EQ(
+ net::ERR_PAC_SCRIPT_TERMINATED,
+ callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request)));
+ EXPECT_TRUE(request);
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_ResolverDisconnected) {
+ mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
+ CreateProxyResolverAction::DropResolver(kScriptData));
+
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(kScriptData));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ net::TestCompletionCallback callback;
+ EXPECT_EQ(
+ net::ERR_PAC_SCRIPT_TERMINATED,
+ callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request)));
+ EXPECT_TRUE(request);
+}
+
+TEST_F(ProxyResolverFactoryMojoTest,
+ CreateProxyResolver_ResolverDisconnected_DeleteRequestInCallback) {
+ mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
+ CreateProxyResolverAction::DropResolver(kScriptData));
+
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(kScriptData));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ net::TestCompletionCallback callback;
+ EXPECT_EQ(
+ net::ERR_PAC_SCRIPT_TERMINATED,
+ callback.GetResult(proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_,
+ base::Bind(&DeleteResolverFactoryRequestCallback, &request,
+ callback.callback()),
+ &request)));
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_Cancel) {
+ mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
+ CreateProxyResolverAction::WaitForClientDisconnect(kScriptData));
+
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(kScriptData));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ net::TestCompletionCallback callback;
+ EXPECT_EQ(
+ net::ERR_IO_PENDING,
+ proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request));
+ ASSERT_TRUE(request);
+ request.reset();
+
+ // The Mojo request is still made.
+ mock_proxy_resolver_factory_->WaitForNextRequest();
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, CreateProxyResolver_DnsRequest) {
+ mock_proxy_resolver_factory_->AddCreateProxyResolverAction(
+ CreateProxyResolverAction::MakeDnsRequest(kScriptData));
+
+ scoped_refptr<net::ProxyResolverScriptData> pac_script(
+ net::ProxyResolverScriptData::FromUTF8(kScriptData));
+ std::unique_ptr<net::ProxyResolverFactory::Request> request;
+ net::TestCompletionCallback callback;
+ EXPECT_EQ(
+ net::ERR_IO_PENDING,
+ proxy_resolver_factory_mojo_->CreateProxyResolver(
+ pac_script, &proxy_resolver_mojo_, callback.callback(), &request));
+ ASSERT_TRUE(request);
+ host_resolver_.waiter().WaitForEvent(MockHostResolver::DNS_REQUEST);
+ mock_proxy_resolver_factory_->ClearBlockedClients();
+ callback.WaitForResult();
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL) {
+ const GURL url(kExampleUrl);
+ mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers(
+ url, ProxyServersFromPacString("DIRECT")));
+ CreateProxyResolver();
+ net_log_.Clear();
+
+ std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsOk());
+
+ EXPECT_EQ("DIRECT", request->results().ToPacString());
+
+ net::TestNetLogEntry::List entries;
+ net_log_.GetEntries(&entries);
+ CheckCapturedNetLogEntries(url.spec(), entries);
+ entries.clear();
+ request->net_log().GetEntries(&entries);
+ CheckCapturedNetLogEntries(url.spec(), entries);
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_MultipleResults) {
+ static const char kPacString[] =
+ "PROXY foo1:80;DIRECT;SOCKS foo2:1234;"
+ "SOCKS5 foo3:1080;HTTPS foo4:443;QUIC foo6:8888";
+ mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers(
+ GURL(kExampleUrl), ProxyServersFromPacString(kPacString)));
+ CreateProxyResolver();
+
+ std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsOk());
+
+ EXPECT_EQ(kPacString, request->results().ToPacString());
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Error) {
+ mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnError(
+ GURL(kExampleUrl), net::ERR_UNEXPECTED));
+ CreateProxyResolver();
+
+ std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(), IsError(net::ERR_UNEXPECTED));
+
+ EXPECT_TRUE(request->results().is_empty());
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Cancel) {
+ mock_proxy_resolver_.AddGetProxyAction(
+ GetProxyForUrlAction::WaitForClientDisconnect(GURL(kExampleUrl)));
+ CreateProxyResolver();
+
+ std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
+ request->Cancel();
+ EXPECT_FALSE(request->callback().have_result());
+
+ // The Mojo request is still made.
+ mock_proxy_resolver_.WaitForNextRequest();
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_MultipleRequests) {
+ mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers(
+ GURL(kExampleUrl), ProxyServersFromPacString("DIRECT")));
+ mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers(
+ GURL("https://www.chromium.org"),
+ ProxyServersFromPacString("HTTPS foo:443")));
+ CreateProxyResolver();
+
+ std::unique_ptr<Request> request1(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request1->Resolve(), IsError(net::ERR_IO_PENDING));
+ std::unique_ptr<Request> request2(
+ MakeRequest(GURL("https://www.chromium.org")));
+ EXPECT_THAT(request2->Resolve(), IsError(net::ERR_IO_PENDING));
+
+ EXPECT_THAT(request1->WaitForResult(), IsOk());
+ EXPECT_THAT(request2->WaitForResult(), IsOk());
+
+ EXPECT_EQ("DIRECT", request1->results().ToPacString());
+ EXPECT_EQ("HTTPS foo:443", request2->results().ToPacString());
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_Disconnect) {
+ mock_proxy_resolver_.AddGetProxyAction(
+ GetProxyForUrlAction::Disconnect(GURL(kExampleUrl)));
+ CreateProxyResolver();
+ {
+ std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
+ EXPECT_THAT(request->WaitForResult(),
+ IsError(net::ERR_PAC_SCRIPT_TERMINATED));
+ EXPECT_TRUE(request->results().is_empty());
+ }
+
+ // Run Watcher::OnHandleReady() tasks posted by Watcher::CallOnHandleReady().
+ base::RunLoop().RunUntilIdle();
+
+ {
+ // Calling GetProxyForURL after a disconnect should fail.
+ std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request->Resolve(), IsError(net::ERR_PAC_SCRIPT_TERMINATED));
+ }
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_ClientClosed) {
+ mock_proxy_resolver_.AddGetProxyAction(
+ GetProxyForUrlAction::DropRequest(GURL(kExampleUrl)));
+ CreateProxyResolver();
+
+ std::unique_ptr<Request> request1(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request1->Resolve(), IsError(net::ERR_IO_PENDING));
+
+ EXPECT_THAT(request1->WaitForResult(),
+ IsError(net::ERR_PAC_SCRIPT_TERMINATED));
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DeleteInCallback) {
+ mock_proxy_resolver_.AddGetProxyAction(GetProxyForUrlAction::ReturnServers(
+ GURL(kExampleUrl), ProxyServersFromPacString("DIRECT")));
+ CreateProxyResolver();
+
+ net::ProxyInfo results;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::ProxyResolver::Request> request;
+ net::NetLogWithSource net_log;
+ EXPECT_EQ(
+ net::OK,
+ callback.GetResult(proxy_resolver_mojo_->GetProxyForURL(
+ GURL(kExampleUrl), &results,
+ base::Bind(&ProxyResolverFactoryMojoTest::DeleteProxyResolverCallback,
+ base::Unretained(this), callback.callback()),
+ &request, net_log)));
+}
+
+TEST_F(ProxyResolverFactoryMojoTest,
+ GetProxyForURL_DeleteInCallbackFromDisconnect) {
+ mock_proxy_resolver_.AddGetProxyAction(
+ GetProxyForUrlAction::Disconnect(GURL(kExampleUrl)));
+ CreateProxyResolver();
+
+ net::ProxyInfo results;
+ net::TestCompletionCallback callback;
+ std::unique_ptr<net::ProxyResolver::Request> request;
+ net::NetLogWithSource net_log;
+ EXPECT_EQ(
+ net::ERR_PAC_SCRIPT_TERMINATED,
+ callback.GetResult(proxy_resolver_mojo_->GetProxyForURL(
+ GURL(kExampleUrl), &results,
+ base::Bind(&ProxyResolverFactoryMojoTest::DeleteProxyResolverCallback,
+ base::Unretained(this), callback.callback()),
+ &request, net_log)));
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, GetProxyForURL_DnsRequest) {
+ mock_proxy_resolver_.AddGetProxyAction(
+ GetProxyForUrlAction::MakeDnsRequest(GURL(kExampleUrl)));
+ CreateProxyResolver();
+
+ std::unique_ptr<Request> request(MakeRequest(GURL(kExampleUrl)));
+ EXPECT_THAT(request->Resolve(), IsError(net::ERR_IO_PENDING));
+ EXPECT_EQ(net::LOAD_STATE_RESOLVING_PROXY_FOR_URL, request->load_state());
+
+ host_resolver_.waiter().WaitForEvent(MockHostResolver::DNS_REQUEST);
+ EXPECT_EQ(net::LOAD_STATE_RESOLVING_HOST_IN_PROXY_SCRIPT,
+ request->load_state());
+ mock_proxy_resolver_.ClearBlockedClients();
+ request->WaitForResult();
+}
+
+TEST_F(ProxyResolverFactoryMojoTest, DeleteResolver) {
+ CreateProxyResolver();
+ proxy_resolver_mojo_.reset();
+}
+} // namespace network
diff --git a/chromium/services/network/public/cpp/proxy_resolving_client_socket.cc b/chromium/services/network/proxy_resolving_client_socket.cc
index 444c5f30612..a08647f8bf2 100644
--- a/chromium/services/network/public/cpp/proxy_resolving_client_socket.cc
+++ b/chromium/services/network/proxy_resolving_client_socket.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/proxy_resolving_client_socket.h"
+#include "services/network/proxy_resolving_client_socket.h"
#include <stdint.h>
#include <string>
@@ -14,6 +14,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/io_buffer.h"
#include "net/base/ip_address.h"
+#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_controller.h"
#include "net/http/http_network_session.h"
@@ -23,82 +24,23 @@
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool_manager.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "net/url_request/url_request_context.h"
-#include "net/url_request/url_request_context_getter.h"
namespace network {
ProxyResolvingClientSocket::ProxyResolvingClientSocket(
- net::ClientSocketFactory* socket_factory,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
+ net::HttpNetworkSession* network_session,
const net::SSLConfig& ssl_config,
const GURL& url)
- : ssl_config_(ssl_config),
- proxy_resolve_request_(NULL),
+ : network_session_(network_session),
+ ssl_config_(ssl_config),
+ proxy_resolve_request_(nullptr),
url_(url),
- net_log_(net::NetLogWithSource::Make(
- request_context_getter->GetURLRequestContext()->net_log(),
- net::NetLogSourceType::SOCKET)),
+ net_log_(net::NetLogWithSource::Make(network_session_->net_log(),
+ net::NetLogSourceType::SOCKET)),
weak_factory_(this) {
- DCHECK(request_context_getter.get());
- net::URLRequestContext* request_context =
- request_context_getter->GetURLRequestContext();
- DCHECK(request_context);
// TODO(xunjieli): Handle invalid URLs more gracefully (at mojo API layer
// or when the request is created).
DCHECK(url_.is_valid());
-
- // TODO(xunjieli): https://crbug.com/793066. Avoid creating one context per
- // socket.
- net::HttpNetworkSession::Context session_context;
- session_context.client_socket_factory = socket_factory;
- session_context.host_resolver = request_context->host_resolver();
- session_context.cert_verifier = request_context->cert_verifier();
- session_context.transport_security_state =
- request_context->transport_security_state();
- session_context.cert_transparency_verifier =
- request_context->cert_transparency_verifier();
- session_context.ct_policy_enforcer = request_context->ct_policy_enforcer();
- // TODO(rkn): This is NULL because ChannelIDService is not thread safe.
- // TODO(mmenke): The above comment makes no sense, as not a single one of
- // these classes is thread safe. Figure out if the comment's wrong, or if this
- // entire class is badly broken.
- session_context.channel_id_service = NULL;
- session_context.proxy_service = request_context->proxy_service();
- session_context.ssl_config_service = request_context->ssl_config_service();
- session_context.http_auth_handler_factory =
- request_context->http_auth_handler_factory();
- session_context.http_server_properties =
- request_context->http_server_properties();
- session_context.net_log = request_context->net_log();
-
- const net::HttpNetworkSession::Params* reference_params =
- request_context->GetNetworkSessionParams();
- net::HttpNetworkSession::Params session_params;
- if (reference_params) {
- // TODO(mmenke): Just copying specific parameters seems highly regression
- // prone. Should have a better way to do this.
- session_params.host_mapping_rules = reference_params->host_mapping_rules;
- session_params.ignore_certificate_errors =
- reference_params->ignore_certificate_errors;
- session_params.testing_fixed_http_port =
- reference_params->testing_fixed_http_port;
- session_params.testing_fixed_https_port =
- reference_params->testing_fixed_https_port;
- session_params.enable_http2 = reference_params->enable_http2;
- session_params.enable_http2_alternative_service =
- reference_params->enable_http2_alternative_service;
- }
-
- network_session_.reset(
- new net::HttpNetworkSession(session_params, session_context));
-
- net::HttpAuthCache* other_auth_cache =
- request_context->http_transaction_factory()
- ->GetSession()
- ->http_auth_cache();
- DCHECK(other_auth_cache);
- network_session_->http_auth_cache()->UpdateAllFrom(*other_auth_cache);
}
ProxyResolvingClientSocket::~ProxyResolvingClientSocket() {
@@ -144,7 +86,7 @@ int ProxyResolvingClientSocket::Connect(
// TODO(xunjieli): Having a null ProxyDelegate is bad. Figure out how to
// interact with the new interface for proxy delegate.
// https://crbug.com/793071.
- int net_error = network_session_->proxy_service()->ResolveProxy(
+ int net_error = network_session_->proxy_resolution_service()->ResolveProxy(
url_, "POST", &proxy_info_,
base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxy,
base::Unretained(this)),
@@ -164,8 +106,9 @@ int ProxyResolvingClientSocket::Connect(
void ProxyResolvingClientSocket::Disconnect() {
CloseTransportSocket();
if (proxy_resolve_request_) {
- network_session_->proxy_service()->CancelRequest(proxy_resolve_request_);
- proxy_resolve_request_ = NULL;
+ network_session_->proxy_resolution_service()->CancelRequest(
+ proxy_resolve_request_);
+ proxy_resolve_request_ = nullptr;
}
user_connect_callback_.Reset();
}
@@ -258,7 +201,7 @@ void ProxyResolvingClientSocket::ApplySocketTag(const net::SocketTag& tag) {
}
void ProxyResolvingClientSocket::ConnectToProxy(int net_error) {
- proxy_resolve_request_ = NULL;
+ proxy_resolve_request_ = nullptr;
DCHECK_NE(net_error, net::ERR_IO_PENDING);
if (net_error == net::OK) {
@@ -286,9 +229,14 @@ void ProxyResolvingClientSocket::ConnectToProxy(int net_error) {
transport_.reset(new net::ClientSocketHandle);
// Now that the proxy is resolved, issue a socket connect.
net::HostPortPair host_port_pair = net::HostPortPair::FromURL(url_);
+ // Ignore socket limit set by socket pool for this type of socket.
+ int request_load_flags = net::LOAD_IGNORE_LIMITS;
+ net::RequestPriority request_priority = net::MAXIMUM_PRIORITY;
+
net_error = net::InitSocketHandleForRawConnect(
- host_port_pair, network_session_.get(), proxy_info_, ssl_config_,
- ssl_config_, net::PRIVACY_MODE_DISABLED, net_log_, transport_.get(),
+ host_port_pair, network_session_, request_load_flags, request_priority,
+ proxy_info_, ssl_config_, ssl_config_, net::PRIVACY_MODE_DISABLED,
+ net_log_, transport_.get(),
base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxyDone,
base::Unretained(this)));
if (net_error != net::ERR_IO_PENDING) {
@@ -312,7 +260,8 @@ void ProxyResolvingClientSocket::ConnectToProxyDone(int net_error) {
}
CloseTransportSocket();
} else {
- network_session_->proxy_service()->ReportSuccess(proxy_info_, NULL);
+ network_session_->proxy_resolution_service()->ReportSuccess(proxy_info_,
+ nullptr);
}
base::ResetAndReturn(&user_connect_callback_).Run(net_error);
}
@@ -384,32 +333,19 @@ int ProxyResolvingClientSocket::ReconsiderProxyAfterError(int error) {
proxy_info_.proxy_server().host_port_pair());
}
- int rv = network_session_->proxy_service()->ReconsiderProxyAfterError(
- url_, std::string(), error, &proxy_info_,
- base::BindRepeating(&ProxyResolvingClientSocket::ConnectToProxy,
- base::Unretained(this)),
- &proxy_resolve_request_, NULL, net_log_);
- if (rv == net::OK || rv == net::ERR_IO_PENDING) {
- CloseTransportSocket();
- } else {
- // If ReconsiderProxyAfterError() failed synchronously, it means
- // there was nothing left to fall-back to, so fail the transaction
- // with the last connection error we got.
- rv = error;
- }
+ // There was nothing left to fall-back to, so fail the transaction
+ // with the last connection error we got.
+ if (!proxy_info_.Fallback(error, net_log_))
+ return error;
- // We either have new proxy info or there was an error in falling back.
- // In both cases we want to post ConnectToProxy (in the error case
- // we might still want to fall back a direct connection).
- if (rv != net::ERR_IO_PENDING) {
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE, base::BindOnce(&ProxyResolvingClientSocket::ConnectToProxy,
- weak_factory_.GetWeakPtr(), rv));
- // Since we potentially have another try to go (trying the direct connect)
- // set the return code code to ERR_IO_PENDING.
- rv = net::ERR_IO_PENDING;
- }
- return rv;
+ CloseTransportSocket();
+
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&ProxyResolvingClientSocket::ConnectToProxy,
+ weak_factory_.GetWeakPtr(), net::OK));
+ // Since we potentially have another try to go, set the return code code to
+ // ERR_IO_PENDING.
+ return net::ERR_IO_PENDING;
}
} // namespace network
diff --git a/chromium/services/network/public/cpp/proxy_resolving_client_socket.h b/chromium/services/network/proxy_resolving_client_socket.h
index 8d6b0c9879c..8e9a95712c6 100644
--- a/chromium/services/network/public/cpp/proxy_resolving_client_socket.h
+++ b/chromium/services/network/proxy_resolving_client_socket.h
@@ -1,6 +1,7 @@
// 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 SERVICES_NETWORK_PROXY_RESOLVING_CLIENT_SOCKET_H_
#define SERVICES_NETWORK_PROXY_RESOLVING_CLIENT_SOCKET_H_
@@ -9,6 +10,7 @@
#include <memory>
#include "base/compiler_specific.h"
+#include "base/component_export.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
@@ -17,8 +19,8 @@
#include "net/base/host_port_pair.h"
#include "net/base/net_errors.h"
#include "net/log/net_log_with_source.h"
-#include "net/proxy/proxy_info.h"
-#include "net/proxy/proxy_service.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_service.h"
#include "net/socket/next_proto.h"
#include "net/socket/stream_socket.h"
#include "net/ssl/ssl_config_service.h"
@@ -26,10 +28,8 @@
#include "url/gurl.h"
namespace net {
-class ClientSocketFactory;
class ClientSocketHandle;
class HttpNetworkSession;
-class URLRequestContextGetter;
} // namespace net
namespace network {
@@ -41,23 +41,19 @@ namespace network {
// TODO(xunjieli): https://crbug.com/721401. This class should be private (i.e.
// moved out of services/network/public/cpp). The functionalities will be
// exposed only through a mojo interface.
-class ProxyResolvingClientSocket : public net::StreamSocket {
+class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolvingClientSocket
+ : public net::StreamSocket {
public:
- // Constructs a new ProxyResolvingClientSocket. |socket_factory| is the
- // ClientSocketFactory that will be used by the underlying HttpNetworkSession.
- // If |socket_factory| is nullptr, the default socket factory
- // (net::ClientSocketFactory::GetDefaultFactory()) will be used. |url|'s host
- // and port specify where a connection will be established to. The full URL
- // will be only used for proxy resolution. Caller doesn't need to explicitly
- // sanitize the url, any sensitive data (like embedded usernames and
- // passwords), and local data (i.e. reference fragment) will be sanitized by
- // net::ProxyService::ResolveProxyHelper() before the url is disclosed to the
- // proxy.
- ProxyResolvingClientSocket(
- net::ClientSocketFactory* socket_factory,
- const scoped_refptr<net::URLRequestContextGetter>& request_context_getter,
- const net::SSLConfig& ssl_config,
- const GURL& url);
+ // Constructs a new ProxyResolvingClientSocket. |url|'s host and port specify
+ // where a connection will be established to. The full URL will be only used
+ // for proxy resolution. Caller doesn't need to explicitly sanitize the url,
+ // any sensitive data (like embedded usernames and passwords), and local data
+ // (i.e. reference fragment) will be sanitized by
+ // net::ProxyResolutionService::ResolveProxyHelper() before the url is
+ // disclosed to the proxy. |network_session| must outlive |this|.
+ ProxyResolvingClientSocket(net::HttpNetworkSession* network_session,
+ const net::SSLConfig& ssl_config,
+ const GURL& url);
~ProxyResolvingClientSocket() override;
// net::StreamSocket implementation.
@@ -101,13 +97,13 @@ class ProxyResolvingClientSocket : public net::StreamSocket {
void CloseTransportSocket();
int ReconsiderProxyAfterError(int error);
- std::unique_ptr<net::HttpNetworkSession> network_session_;
+ net::HttpNetworkSession* network_session_;
// The transport socket.
std::unique_ptr<net::ClientSocketHandle> transport_;
const net::SSLConfig ssl_config_;
- net::ProxyService::Request* proxy_resolve_request_;
+ net::ProxyResolutionService::Request* proxy_resolve_request_;
net::ProxyInfo proxy_info_;
const GURL url_;
net::NetLogWithSource net_log_;
diff --git a/chromium/services/network/proxy_resolving_client_socket_factory.cc b/chromium/services/network/proxy_resolving_client_socket_factory.cc
new file mode 100644
index 00000000000..1652aaa2b19
--- /dev/null
+++ b/chromium/services/network/proxy_resolving_client_socket_factory.cc
@@ -0,0 +1,89 @@
+// Copyright 2018 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/network/proxy_resolving_client_socket_factory.h"
+
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "net/base/ip_address.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_transaction_factory.h"
+#include "net/url_request/url_request_context.h"
+#include "services/network/proxy_resolving_client_socket.h"
+
+namespace network {
+
+ProxyResolvingClientSocketFactory::ProxyResolvingClientSocketFactory(
+ net::ClientSocketFactory* socket_factory,
+ net::URLRequestContext* request_context)
+ : request_context_(request_context) {
+ DCHECK(request_context);
+
+ net::HttpNetworkSession::Context session_context;
+ session_context.client_socket_factory = socket_factory;
+ session_context.host_resolver = request_context->host_resolver();
+ session_context.cert_verifier = request_context->cert_verifier();
+ session_context.transport_security_state =
+ request_context->transport_security_state();
+ session_context.cert_transparency_verifier =
+ request_context->cert_transparency_verifier();
+ session_context.ct_policy_enforcer = request_context->ct_policy_enforcer();
+ // TODO(rkn): This is NULL because ChannelIDService is not thread safe.
+ // TODO(mmenke): The above comment makes no sense, as not a single one of
+ // these classes is thread safe. Figure out if the comment's wrong, or if this
+ // entire class is badly broken.
+ session_context.channel_id_service = NULL;
+ session_context.proxy_resolution_service =
+ request_context->proxy_resolution_service();
+ session_context.ssl_config_service = request_context->ssl_config_service();
+ session_context.http_auth_handler_factory =
+ request_context->http_auth_handler_factory();
+ session_context.http_server_properties =
+ request_context->http_server_properties();
+ session_context.net_log = request_context->net_log();
+
+ const net::HttpNetworkSession::Params* reference_params =
+ request_context->GetNetworkSessionParams();
+ net::HttpNetworkSession::Params session_params;
+ if (reference_params) {
+ // TODO(mmenke): Just copying specific parameters seems highly regression
+ // prone. Should have a better way to do this.
+ session_params.host_mapping_rules = reference_params->host_mapping_rules;
+ session_params.ignore_certificate_errors =
+ reference_params->ignore_certificate_errors;
+ session_params.testing_fixed_http_port =
+ reference_params->testing_fixed_http_port;
+ session_params.testing_fixed_https_port =
+ reference_params->testing_fixed_https_port;
+ session_params.enable_http2 = reference_params->enable_http2;
+ session_params.enable_http2_alternative_service =
+ reference_params->enable_http2_alternative_service;
+ }
+
+ network_session_ = std::make_unique<net::HttpNetworkSession>(session_params,
+ session_context);
+}
+
+ProxyResolvingClientSocketFactory::~ProxyResolvingClientSocketFactory() {}
+
+std::unique_ptr<ProxyResolvingClientSocket>
+ProxyResolvingClientSocketFactory::CreateSocket(
+ const net::SSLConfig& ssl_config,
+ const GURL& url) {
+ // |request_context|'s HttpAuthCache might have updates. For example, a user
+ // might have since entered proxy credentials. Clear the http auth of
+ // |network_session_| and copy over the data from |request_context|'s auth
+ // cache.
+ network_session_->http_auth_cache()->ClearEntriesAddedWithin(
+ base::Time::Now() - base::Time());
+ net::HttpAuthCache* other_auth_cache =
+ request_context_->http_transaction_factory()
+ ->GetSession()
+ ->http_auth_cache();
+ network_session_->http_auth_cache()->UpdateAllFrom(*other_auth_cache);
+ return std::make_unique<ProxyResolvingClientSocket>(network_session_.get(),
+ ssl_config, url);
+}
+
+} // namespace network
diff --git a/chromium/services/network/proxy_resolving_client_socket_factory.h b/chromium/services/network/proxy_resolving_client_socket_factory.h
new file mode 100644
index 00000000000..f722d06329f
--- /dev/null
+++ b/chromium/services/network/proxy_resolving_client_socket_factory.h
@@ -0,0 +1,56 @@
+// Copyright 2018 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 SERVICES_NETWORK_PROXY_RESOLVING_CLIENT_SOCKET_FACTORY_H_
+#define SERVICES_NETWORK_PROXY_RESOLVING_CLIENT_SOCKET_FACTORY_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "net/ssl/ssl_config.h"
+#include "url/gurl.h"
+
+namespace net {
+class ClientSocketFactory;
+class HttpNetworkSession;
+class URLRequestContext;
+} // namespace net
+
+namespace network {
+
+class ProxyResolvingClientSocket;
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) ProxyResolvingClientSocketFactory {
+ public:
+ // Constructs a new ProxyResolvingClientSocket. |socket_factory| is the
+ // ClientSocketFactory that will be used by the underlying HttpNetworkSession.
+ // If |socket_factory| is nullptr, the default socket factory
+ // (net::ClientSocketFactory::GetDefaultFactory()) will be used.
+ // |request_context| must outlive |this| and all sockets |this| creates.
+ ProxyResolvingClientSocketFactory(net::ClientSocketFactory* socket_factory,
+ net::URLRequestContext* request_context);
+ ~ProxyResolvingClientSocketFactory();
+
+ // Creates a socket. |url|'s host and port specify where a connection will be
+ // established to. The full URL will be only used for proxy resolution. Caller
+ // doesn't need to explicitly sanitize the url, any sensitive data (like
+ // embedded usernames and passwords), and local data (i.e. reference fragment)
+ // will be sanitized by net::ProxyService::ResolveProxyHelper() before the url
+ // is disclosed to the proxy.
+ std::unique_ptr<ProxyResolvingClientSocket> CreateSocket(
+ const net::SSLConfig& ssl_config,
+ const GURL& url);
+
+ private:
+ std::unique_ptr<net::HttpNetworkSession> network_session_;
+ net::URLRequestContext* request_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyResolvingClientSocketFactory);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PROXY_RESOLVING_CLIENT_SOCKET_FACTORY_H_
diff --git a/chromium/services/network/public/cpp/proxy_resolving_client_socket_unittest.cc b/chromium/services/network/proxy_resolving_client_socket_unittest.cc
index 5e372a87c04..27d3937dd37 100644
--- a/chromium/services/network/public/cpp/proxy_resolving_client_socket_unittest.cc
+++ b/chromium/services/network/proxy_resolving_client_socket_unittest.cc
@@ -2,7 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/proxy_resolving_client_socket.h"
+#include "services/network/proxy_resolving_client_socket.h"
+
+#include <string>
+#include <utility>
+#include <vector>
#include "base/compiler_specific.h"
#include "base/macros.h"
@@ -14,14 +18,15 @@
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/test_completion_callback.h"
#include "net/dns/mock_host_resolver.h"
-#include "net/proxy/mock_proxy_resolver.h"
-#include "net/proxy/proxy_config_service_fixed.h"
-#include "net/proxy/proxy_service.h"
+#include "net/proxy_resolution/mock_proxy_resolver.h"
+#include "net/proxy_resolution/proxy_config_service_fixed.h"
+#include "net/proxy_resolution/proxy_service.h"
+#include "net/socket/client_socket_pool_manager.h"
#include "net/socket/socket_test_util.h"
#include "net/test/gtest_util.h"
#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_test_util.h"
+#include "services/network/proxy_resolving_client_socket_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
@@ -30,10 +35,10 @@ namespace {
class TestURLRequestContextWithProxy : public net::TestURLRequestContext {
public:
- TestURLRequestContextWithProxy(const std::string& pac_result)
+ explicit TestURLRequestContextWithProxy(const std::string& pac_result)
: TestURLRequestContext(true) {
- context_storage_.set_proxy_service(
- net::ProxyService::CreateFixedFromPacResult(pac_result));
+ context_storage_.set_proxy_resolution_service(
+ net::ProxyResolutionService::CreateFixedFromPacResult(pac_result));
// net::MockHostResolver maps all hosts to localhost.
auto host_resolver = std::make_unique<net::MockHostResolver>();
context_storage_.set_host_resolver(std::move(host_resolver));
@@ -47,11 +52,7 @@ class TestURLRequestContextWithProxy : public net::TestURLRequestContext {
class ProxyResolvingClientSocketTest : public testing::Test {
protected:
ProxyResolvingClientSocketTest()
- : context_getter_with_proxy_(new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(),
- std::unique_ptr<net::TestURLRequestContext>(
- new TestURLRequestContextWithProxy(
- "PROXY bad:99; PROXY maybe:80; DIRECT")))) {}
+ : context_with_proxy_("PROXY bad:99; PROXY maybe:80; DIRECT") {}
~ProxyResolvingClientSocketTest() override {}
@@ -62,9 +63,49 @@ class ProxyResolvingClientSocketTest : public testing::Test {
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
- scoped_refptr<net::TestURLRequestContextGetter> context_getter_with_proxy_;
+ TestURLRequestContextWithProxy context_with_proxy_;
};
+// Tests that the global socket pool limit
+// (ClientSocketPoolManager::max_sockets_per_group) doesn't apply to this
+// type of sockets.
+TEST_F(ProxyResolvingClientSocketTest, SocketLimitNotApply) {
+ const int kNumSockets = net::ClientSocketPoolManager::max_sockets_per_group(
+ net::HttpNetworkSession::NORMAL_SOCKET_POOL) +
+ 10;
+ const GURL kDestination("https://example.com:443");
+ net::MockClientSocketFactory socket_factory;
+ net::MockWrite writes[] = {
+ net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
+ "Host: example.com:443\r\n"
+ "Proxy-Connection: keep-alive\r\n\r\n")};
+ net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 Success\r\n\r\n")};
+ std::vector<std::unique_ptr<net::StaticSocketDataProvider>> socket_data;
+ for (int i = 0; i < kNumSockets; ++i) {
+ socket_data.push_back(std::make_unique<net::StaticSocketDataProvider>(
+ reads, arraysize(reads), writes, arraysize(writes)));
+ socket_data[i]->set_connect_data(net::MockConnect(net::ASYNC, net::OK));
+ socket_factory.AddSocketDataProvider(socket_data[i].get());
+ }
+
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, &context_with_proxy_);
+ std::vector<std::unique_ptr<ProxyResolvingClientSocket>> sockets;
+ for (int i = 0; i < kNumSockets; ++i) {
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
+ net::TestCompletionCallback callback;
+ int status = socket->Connect(callback.callback());
+ EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
+ sockets.push_back(std::move(socket));
+ }
+ for (int i = 0; i < kNumSockets; ++i) {
+ EXPECT_TRUE(socket_data[i]->AllReadDataConsumed());
+ EXPECT_TRUE(socket_data[i]->AllWriteDataConsumed());
+ }
+}
+
TEST_F(ProxyResolvingClientSocketTest, ConnectError) {
const struct TestData {
// Whether the error is encountered synchronously as opposed to
@@ -77,17 +118,12 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectError) {
};
const GURL kDestination("https://example.com:443");
for (auto test : kTestCases) {
- scoped_refptr<net::URLRequestContextGetter> context_getter;
+ std::unique_ptr<net::URLRequestContext> context;
if (test.is_direct) {
- context_getter = new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(),
- std::unique_ptr<net::TestURLRequestContext>(
- new TestURLRequestContextWithProxy("DIRECT")));
+ context = std::make_unique<TestURLRequestContextWithProxy>("DIRECT");
} else {
- context_getter = new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(),
- std::unique_ptr<net::TestURLRequestContext>(
- new TestURLRequestContextWithProxy("PROXY myproxy.com:89")));
+ context = std::make_unique<TestURLRequestContextWithProxy>(
+ "PROXY myproxy.com:89");
}
net::MockClientSocketFactory socket_factory;
net::StaticSocketDataProvider socket_data;
@@ -95,10 +131,13 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectError) {
test.is_error_sync ? net::SYNCHRONOUS : net::ASYNC, net::ERR_FAILED));
socket_factory.AddSocketDataProvider(&socket_data);
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter, net::SSLConfig(), kDestination);
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, context.get());
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_EQ(net::ERR_IO_PENDING, status);
status = callback.WaitForResult();
if (test.is_direct) {
@@ -119,18 +158,12 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectToProxy) {
const int kDirectPort = 443;
for (bool is_direct : {true, false}) {
net::MockClientSocketFactory socket_factory;
- scoped_refptr<net::URLRequestContextGetter> context_getter;
+ std::unique_ptr<net::URLRequestContext> context;
if (is_direct) {
- context_getter = new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(),
- std::unique_ptr<net::TestURLRequestContext>(
- new TestURLRequestContextWithProxy("DIRECT")));
+ context = std::make_unique<TestURLRequestContextWithProxy>("DIRECT");
} else {
- context_getter = new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(),
- std::unique_ptr<net::TestURLRequestContext>(
- new TestURLRequestContextWithProxy(
- base::StringPrintf("PROXY myproxy.com:%d", kProxyPort))));
+ context = std::make_unique<TestURLRequestContextWithProxy>(
+ base::StringPrintf("PROXY myproxy.com:%d", kProxyPort));
}
net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 Success\r\n\r\n")};
net::MockWrite writes[] = {
@@ -145,21 +178,24 @@ TEST_F(ProxyResolvingClientSocketTest, ConnectToProxy) {
net::MockConnect(net::ASYNC, net::OK, remote_addr));
socket_factory.AddSocketDataProvider(&socket_data);
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter, net::SSLConfig(), kDestination);
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, context.get());
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_EQ(net::ERR_IO_PENDING, status);
status = callback.WaitForResult();
EXPECT_EQ(net::OK, status);
net::IPEndPoint actual_remote_addr;
- status = proxy_resolving_socket.GetPeerAddress(&actual_remote_addr);
+ status = socket->GetPeerAddress(&actual_remote_addr);
if (!is_direct) {
// ProxyResolvingClientSocket::GetPeerAddress() hides the ip of the
// proxy, so call private member to make sure address is correct.
EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, status);
- status = proxy_resolving_socket.transport_->socket()->GetPeerAddress(
- &actual_remote_addr);
+ status =
+ socket->transport_->socket()->GetPeerAddress(&actual_remote_addr);
}
EXPECT_EQ(net::OK, status);
EXPECT_EQ(remote_addr.ToString(), actual_remote_addr.ToString());
@@ -187,18 +223,12 @@ TEST_F(ProxyResolvingClientSocketTest, ReadWriteErrors) {
const int kProxyPort = 8009;
const int kDirectPort = 80;
for (auto test : kTestCases) {
- scoped_refptr<net::URLRequestContextGetter> context_getter;
+ std::unique_ptr<net::URLRequestContext> context;
if (test.is_direct) {
- context_getter = new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(),
- std::unique_ptr<net::TestURLRequestContext>(
- new TestURLRequestContextWithProxy("DIRECT")));
+ context = std::make_unique<TestURLRequestContextWithProxy>("DIRECT");
} else {
- context_getter = new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(),
- std::unique_ptr<net::TestURLRequestContext>(
- new TestURLRequestContextWithProxy(
- base::StringPrintf("PROXY myproxy.com:%d", kProxyPort))));
+ context = std::make_unique<TestURLRequestContextWithProxy>(
+ base::StringPrintf("PROXY myproxy.com:%d", kProxyPort));
}
std::vector<net::MockWrite> writes;
std::vector<net::MockRead> reads;
@@ -224,22 +254,24 @@ TEST_F(ProxyResolvingClientSocketTest, ReadWriteErrors) {
net::MockConnect(net::ASYNC, net::OK, remote_addr));
net::MockClientSocketFactory socket_factory;
socket_factory.AddSocketDataProvider(&socket_data);
-
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter, net::SSLConfig(), kDestination);
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, context.get());
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_EQ(net::ERR_IO_PENDING, status);
status = callback.WaitForResult();
EXPECT_EQ(net::OK, status);
net::IPEndPoint actual_remote_addr;
- status = proxy_resolving_socket.GetPeerAddress(&actual_remote_addr);
+ status = socket->GetPeerAddress(&actual_remote_addr);
if (!test.is_direct) {
// ProxyResolvingClientSocket::GetPeerAddress() hides the ip of the
// proxy, so call private member to make sure address is correct.
EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, status);
- status = proxy_resolving_socket.transport_->socket()->GetPeerAddress(
- &actual_remote_addr);
+ status =
+ socket->transport_->socket()->GetPeerAddress(&actual_remote_addr);
}
EXPECT_EQ(net::OK, status);
EXPECT_EQ(remote_addr.ToString(), actual_remote_addr.ToString());
@@ -251,10 +283,10 @@ TEST_F(ProxyResolvingClientSocketTest, ReadWriteErrors) {
scoped_refptr<net::IOBuffer> write_buffer(
new net::StringIOBuffer(test_data_string));
if (test.is_read_error) {
- read_write_result = proxy_resolving_socket.Read(
- read_buffer.get(), 10, read_write_callback.callback());
+ read_write_result =
+ socket->Read(read_buffer.get(), 10, read_write_callback.callback());
} else {
- read_write_result = proxy_resolving_socket.Write(
+ read_write_result = socket->Write(
write_buffer.get(), test_data_string.size(),
read_write_callback.callback(), TRAFFIC_ANNOTATION_FOR_TESTS);
}
@@ -287,20 +319,19 @@ TEST_F(ProxyResolvingClientSocketTest, ReportsBadProxies) {
socket_data2.set_connect_data(net::MockConnect(net::ASYNC, net::OK));
socket_factory.AddSocketDataProvider(&socket_data2);
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter_with_proxy_, net::SSLConfig(),
- kDestination);
-
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, &context_with_proxy_);
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_EQ(net::ERR_IO_PENDING, status);
status = callback.WaitForResult();
EXPECT_EQ(net::OK, status);
- net::URLRequestContext* context =
- context_getter_with_proxy_->GetURLRequestContext();
const net::ProxyRetryInfoMap& retry_info =
- context->proxy_service()->proxy_retry_info();
+ context_with_proxy_.proxy_resolution_service()->proxy_retry_info();
EXPECT_EQ(1u, retry_info.size());
net::ProxyRetryInfoMap::const_iterator iter = retry_info.find("bad:99");
@@ -343,8 +374,7 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Lookup) {
socket_factory.AddSocketDataProvider(&kSocketData2);
net::HttpAuthCache* auth_cache =
- context_getter_with_proxy_->GetURLRequestContext()
- ->http_transaction_factory()
+ context_with_proxy_.http_transaction_factory()
->GetSession()
->http_auth_cache();
@@ -358,12 +388,72 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Lookup) {
base::ASCIIToUTF16("password")),
std::string());
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter_with_proxy_, net::SSLConfig(),
- kDestination);
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, &context_with_proxy_);
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
+ net::TestCompletionCallback callback;
+ int status = socket->Connect(callback.callback());
+ EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
+}
+// Make sure that if HttpAuthCache is updated e.g through normal URLRequests,
+// ProxyResolvingClientSocketFactory uses the latest cache for creating new
+// sockets.
+TEST_F(ProxyResolvingClientSocketTest, FactoryUsesLatestHTTPAuthCache) {
+ net::MockClientSocketFactory socket_factory;
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, &context_with_proxy_);
+
+ // After creating |socket_factory|, updates the auth cache with credentials.
+ // New socket connections should pick up this change.
+ net::HttpAuthCache* auth_cache =
+ context_with_proxy_.http_transaction_factory()
+ ->GetSession()
+ ->http_auth_cache();
+
+ // We are adding these credentials at an empty path so that it won't be picked
+ // up by the preemptive authentication step and will only be picked up via
+ // origin + realm + scheme lookup.
+ auth_cache->Add(GURL("http://bad:99"), "test_realm",
+ net::HttpAuth::AUTH_SCHEME_BASIC,
+ "Basic realm=\"test_realm\"",
+ net::AuthCredentials(base::ASCIIToUTF16("user"),
+ base::ASCIIToUTF16("password")),
+ std::string());
+
+ const GURL kDestination("https://example.com:443");
+
+ // Initial connect without credentials. The server responds with a 407.
+ net::MockWrite kConnectWrites[] = {
+ net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
+ "Host: example.com:443\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "\r\n"),
+ net::MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
+ "Host: example.com:443\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Proxy-Authorization: Basic dXNlcjpwYXNzd29yZA==\r\n"
+ "\r\n")};
+ net::MockRead kConnectReads[] = {
+ net::MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"
+ "Proxy-Authenticate: Basic realm=\"test_realm\"\r\n"
+ "Proxy-Connection: keep-alive\r\n"
+ "Content-Length: 0\r\n"
+ "\r\n"),
+ net::MockRead("HTTP/1.1 200 Success\r\n\r\n")};
+
+ net::StaticSocketDataProvider kSocketData(
+ kConnectReads, arraysize(kConnectReads), kConnectWrites,
+ arraysize(kConnectWrites));
+ socket_factory.AddSocketDataProvider(&kSocketData);
+
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
}
@@ -387,8 +477,7 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Preemptive) {
socket_factory.AddSocketDataProvider(&kSocketData);
net::HttpAuthCache* auth_cache =
- context_getter_with_proxy_->GetURLRequestContext()
- ->http_transaction_factory()
+ context_with_proxy_.http_transaction_factory()
->GetSession()
->http_auth_cache();
@@ -399,12 +488,14 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_Preemptive) {
base::ASCIIToUTF16("password")),
"/");
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter_with_proxy_, net::SSLConfig(),
- kDestination);
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, &context_with_proxy_);
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_THAT(callback.GetResult(status), net::test::IsOk());
}
@@ -428,12 +519,14 @@ TEST_F(ProxyResolvingClientSocketTest, ReusesHTTPAuthCache_NoCredentials) {
arraysize(kConnectWrites));
socket_factory.AddSocketDataProvider(&kSocketData);
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter_with_proxy_, net::SSLConfig(),
- kDestination);
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, &context_with_proxy_);
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_THAT(callback.GetResult(status), net::ERR_PROXY_AUTH_REQUESTED);
}
@@ -450,22 +543,18 @@ TEST_F(ProxyResolvingClientSocketTest, URLSanitized) {
std::make_unique<net::MockAsyncProxyResolverFactory>(false);
net::MockAsyncProxyResolverFactory* proxy_resolver_factory_raw =
proxy_resolver_factory.get();
- net::ProxyService service(
+ net::ProxyResolutionService service(
std::make_unique<net::ProxyConfigServiceFixed>(proxy_config),
std::move(proxy_resolver_factory), nullptr);
- context->set_proxy_service(&service);
+ context->set_proxy_resolution_service(&service);
context->Init();
- scoped_refptr<net::TestURLRequestContextGetter> context_getter_with_proxy(
- new net::TestURLRequestContextGetter(base::ThreadTaskRunnerHandle::Get(),
- std::move(context)));
-
- net::MockClientSocketFactory socket_factory;
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter_with_proxy, net::SSLConfig(), url);
-
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ nullptr, context.get());
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(), url);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_EQ(net::ERR_IO_PENDING, status);
base::RunLoop().RunUntilIdle();
ASSERT_EQ(1u, proxy_resolver_factory_raw->pending_requests().size());
@@ -480,67 +569,18 @@ TEST_F(ProxyResolvingClientSocketTest, URLSanitized) {
resolver.pending_jobs()[0]->url());
}
-TEST_F(ProxyResolvingClientSocketTest, ProxyConfigChanged) {
- auto context = std::make_unique<net::TestURLRequestContext>(true);
- // Use direct connection.
- std::unique_ptr<net::ProxyService> proxy_service =
- net::ProxyService::CreateDirect();
- context->set_proxy_service(proxy_service.get());
- context->Init();
-
- scoped_refptr<net::TestURLRequestContextGetter> context_getter_with_proxy(
- new net::TestURLRequestContextGetter(base::ThreadTaskRunnerHandle::Get(),
- std::move(context)));
-
- net::MockClientSocketFactory socket_factory;
-
- // There should be two connection attempts because ProxyConfig has changed
- // midway through connect.
- net::StaticSocketDataProvider data_1;
- data_1.set_connect_data(
- net::MockConnect(net::SYNCHRONOUS, net::ERR_CONNECTION_REFUSED));
- socket_factory.AddSocketDataProvider(&data_1);
-
- net::StaticSocketDataProvider data_2;
- data_2.set_connect_data(net::MockConnect(net::SYNCHRONOUS, net::OK));
- socket_factory.AddSocketDataProvider(&data_2);
-
- GURL url("http://www.example.com");
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter_with_proxy, net::SSLConfig(), url);
-
- net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
- EXPECT_EQ(net::ERR_IO_PENDING, status);
-
- // Calling ForceReloadProxyConfig will cause the proxy configuration to
- // change. It will still be the direct connection but the configuration
- // version will be bumped. That is enough for the job controller to restart
- // the jobs.
- proxy_service->ForceReloadProxyConfig();
- EXPECT_EQ(net::OK, callback.WaitForResult());
- EXPECT_TRUE(data_1.AllReadDataConsumed());
- EXPECT_TRUE(data_1.AllWriteDataConsumed());
- EXPECT_TRUE(data_2.AllReadDataConsumed());
- EXPECT_TRUE(data_2.AllWriteDataConsumed());
-}
-
class ReconsiderProxyAfterErrorTest
: public testing::Test,
public testing::WithParamInterface<::testing::tuple<bool, int>> {
public:
ReconsiderProxyAfterErrorTest()
- : context_getter_with_proxy_(new net::TestURLRequestContextGetter(
- base::ThreadTaskRunnerHandle::Get(),
- std::unique_ptr<net::TestURLRequestContext>(
- new TestURLRequestContextWithProxy(
- "HTTPS badproxy:99; HTTPS badfallbackproxy:98; DIRECT")))) {
- }
+ : context_with_proxy_(
+ "HTTPS badproxy:99; HTTPS badfallbackproxy:98; DIRECT") {}
~ReconsiderProxyAfterErrorTest() override {}
base::test::ScopedTaskEnvironment scoped_task_environment_;
- scoped_refptr<net::TestURLRequestContextGetter> context_getter_with_proxy_;
+ TestURLRequestContextWithProxy context_with_proxy_;
};
// List of errors that are used in the proxy resolution tests.
@@ -568,11 +608,11 @@ TEST_P(ReconsiderProxyAfterErrorTest, ReconsiderProxyAfterError) {
net::IoMode io_mode =
::testing::get<0>(GetParam()) ? net::SYNCHRONOUS : net::ASYNC;
const int mock_error = ::testing::get<1>(GetParam());
- net::URLRequestContext* context =
- context_getter_with_proxy_->GetURLRequestContext();
// Before starting the test, verify that there are no proxies marked as bad.
- ASSERT_TRUE(context->proxy_service()->proxy_retry_info().empty())
+ ASSERT_TRUE(context_with_proxy_.proxy_resolution_service()
+ ->proxy_retry_info()
+ .empty())
<< mock_error;
net::MockClientSocketFactory socket_factory;
@@ -592,18 +632,19 @@ TEST_P(ReconsiderProxyAfterErrorTest, ReconsiderProxyAfterError) {
socket_factory.AddSocketDataProvider(&data3);
const GURL kDestination("https://example.com:443");
- ProxyResolvingClientSocket proxy_resolving_socket(
- &socket_factory, context_getter_with_proxy_, net::SSLConfig(),
- kDestination);
-
+ ProxyResolvingClientSocketFactory proxy_resolving_socket_factory(
+ &socket_factory, &context_with_proxy_);
+ std::unique_ptr<ProxyResolvingClientSocket> socket =
+ proxy_resolving_socket_factory.CreateSocket(net::SSLConfig(),
+ kDestination);
net::TestCompletionCallback callback;
- int status = proxy_resolving_socket.Connect(callback.callback());
+ int status = socket->Connect(callback.callback());
EXPECT_EQ(net::ERR_IO_PENDING, status);
status = callback.WaitForResult();
EXPECT_EQ(net::OK, status);
const net::ProxyRetryInfoMap& retry_info =
- context->proxy_service()->proxy_retry_info();
+ context_with_proxy_.proxy_resolution_service()->proxy_retry_info();
EXPECT_EQ(2u, retry_info.size()) << mock_error;
EXPECT_NE(retry_info.end(), retry_info.find("https://badproxy:99"));
EXPECT_NE(retry_info.end(), retry_info.find("https://badfallbackproxy:98"));
diff --git a/chromium/services/network/proxy_service_mojo.cc b/chromium/services/network/proxy_service_mojo.cc
new file mode 100644
index 00000000000..e3daa18b7d0
--- /dev/null
+++ b/chromium/services/network/proxy_service_mojo.cc
@@ -0,0 +1,50 @@
+// Copyright 2015 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/network/proxy_service_mojo.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/proxy_resolution/network_delegate_error_observer.h"
+#include "net/proxy_resolution/proxy_resolver_factory.h"
+#include "net/proxy_resolution/proxy_service.h"
+#include "services/network/proxy_resolver_factory_mojo.h"
+
+namespace network {
+
+std::unique_ptr<net::ProxyResolutionService> CreateProxyServiceUsingMojoFactory(
+ proxy_resolver::mojom::ProxyResolverFactoryPtr mojo_proxy_factory,
+ std::unique_ptr<net::ProxyConfigService> proxy_config_service,
+ std::unique_ptr<net::ProxyScriptFetcher> proxy_script_fetcher,
+ std::unique_ptr<net::DhcpProxyScriptFetcher> dhcp_proxy_script_fetcher,
+ net::HostResolver* host_resolver,
+ net::NetLog* net_log,
+ net::NetworkDelegate* network_delegate) {
+ DCHECK(proxy_config_service);
+ DCHECK(proxy_script_fetcher);
+ DCHECK(dhcp_proxy_script_fetcher);
+ DCHECK(host_resolver);
+
+ std::unique_ptr<net::ProxyResolutionService> proxy_resolution_service(
+ new net::ProxyResolutionService(
+ std::move(proxy_config_service),
+ std::make_unique<ProxyResolverFactoryMojo>(
+ std::move(mojo_proxy_factory), host_resolver,
+ base::Bind(&net::NetworkDelegateErrorObserver::Create,
+ network_delegate, base::ThreadTaskRunnerHandle::Get()),
+ net_log),
+ net_log));
+
+ // Configure fetchers to use for PAC script downloads and auto-detect.
+ proxy_resolution_service->SetProxyScriptFetchers(
+ std::move(proxy_script_fetcher), std::move(dhcp_proxy_script_fetcher));
+
+ return proxy_resolution_service;
+}
+
+} // namespace network
diff --git a/chromium/services/network/proxy_service_mojo.h b/chromium/services/network/proxy_service_mojo.h
new file mode 100644
index 00000000000..3930c02bb45
--- /dev/null
+++ b/chromium/services/network/proxy_service_mojo.h
@@ -0,0 +1,50 @@
+// Copyright 2015 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 SERVICES_NETWORK_PROXY_SERVICE_MOJO_H_
+#define SERVICES_NETWORK_PROXY_SERVICE_MOJO_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "net/proxy_resolution/dhcp_pac_file_fetcher.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+
+namespace net {
+class HostResolver;
+class NetLog;
+class NetworkDelegate;
+class ProxyConfigService;
+class ProxyScriptFetcher;
+class ProxyResolutionService;
+} // namespace net
+
+namespace network {
+
+// Creates a proxy service that uses |mojo_proxy_factory| to create and connect
+// to a Mojo proxy resolver service. This proxy service polls
+// |proxy_config_service| to notice when the proxy settings change.
+//
+// |proxy_script_fetcher| specifies the dependency to use for downloading
+// any PAC scripts.
+//
+// |dhcp_proxy_script_fetcher| specifies the dependency to use for attempting
+// to retrieve the most appropriate PAC script configured in DHCP.
+//
+// |host_resolver| points to the host resolving dependency the PAC script
+// should use for any DNS queries. It must remain valid throughout the
+// lifetime of the ProxyResolutionService.
+COMPONENT_EXPORT(NETWORK_SERVICE)
+std::unique_ptr<net::ProxyResolutionService> CreateProxyServiceUsingMojoFactory(
+ proxy_resolver::mojom::ProxyResolverFactoryPtr mojo_proxy_factory,
+ std::unique_ptr<net::ProxyConfigService> proxy_config_service,
+ std::unique_ptr<net::ProxyScriptFetcher> proxy_script_fetcher,
+ std::unique_ptr<net::DhcpProxyScriptFetcher> dhcp_proxy_script_fetcher,
+ net::HostResolver* host_resolver,
+ net::NetLog* net_log,
+ net::NetworkDelegate* network_delegate);
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PROXY_SERVICE_MOJO_H_
diff --git a/chromium/services/network/public/cpp/BUILD.gn b/chromium/services/network/public/cpp/BUILD.gn
index 3399f7f667c..caa39f59772 100644
--- a/chromium/services/network/public/cpp/BUILD.gn
+++ b/chromium/services/network/public/cpp/BUILD.gn
@@ -4,37 +4,56 @@
import("//mojo/public/tools/bindings/mojom.gni")
-static_library("cpp") {
+component("cpp") {
+ output_name = "network_cpp"
+
sources = [
"cors/cors.cc",
"cors/cors.h",
- "loader_util.cc",
- "loader_util.h",
- "mutable_network_traffic_annotation_tag_struct_traits.h",
- "mutable_partial_network_traffic_annotation_tag_struct_traits.h",
+ "cors/cors_legacy.cc",
+ "cors/cors_legacy.h",
+ "cors/cors_url_loader.cc",
+ "cors/cors_url_loader.h",
+ "cors/cors_url_loader_factory.cc",
+ "cors/cors_url_loader_factory.h",
+ "cors/preflight_cache.cc",
+ "cors/preflight_cache.h",
+ "cors/preflight_result.cc",
+ "cors/preflight_result.h",
+ "features.cc",
+ "features.h",
+ "mutable_network_traffic_annotation_tag_mojom_traits.h",
+ "mutable_partial_network_traffic_annotation_tag_mojom_traits.h",
"net_adapters.cc",
"net_adapters.h",
"network_switches.cc",
"network_switches.h",
- "proxy_resolving_client_socket.cc",
- "proxy_resolving_client_socket.h",
+ "simple_url_loader.cc",
+ "simple_url_loader.h",
+ "simple_url_loader_stream_consumer.h",
]
public_deps = [
- ":typemap_dependencies",
- "//services/network/public/interfaces",
+ ":cpp_base",
+ "//services/network/public/mojom",
"//url/ipc:url_ipc",
]
deps = [
"//base",
+ "//components/prefs",
"//ipc",
"//mojo/common",
"//net",
+ "//services/proxy_resolver/public/mojom",
]
+
+ defines = [ "IS_NETWORK_CPP_IMPL" ]
}
-static_library("typemap_dependencies") {
+component("cpp_base") {
+ output_name = "network_cpp_base"
+
sources = [
"cors/cors_error_status.cc",
"cors/cors_error_status.h",
@@ -44,8 +63,8 @@ static_library("typemap_dependencies") {
"http_raw_request_response_info.h",
"network_param_ipc_traits.cc",
"network_param_ipc_traits.h",
- "proxy_config_traits.cc",
- "proxy_config_traits.h",
+ "proxy_config_mojom_traits.cc",
+ "proxy_config_mojom_traits.h",
"resource_request.cc",
"resource_request.h",
"resource_request_body.cc",
@@ -56,20 +75,21 @@ static_library("typemap_dependencies") {
"resource_response_info.h",
"url_loader_completion_status.cc",
"url_loader_completion_status.h",
- "url_request_struct_traits.cc",
- "url_request_struct_traits.h",
+ "url_request_mojom_traits.cc",
+ "url_request_mojom_traits.h",
]
public_deps = [
- "//services/network/public/interfaces:data_pipe_interface",
+ "//services/network/public/mojom:data_pipe_interface",
"//url/ipc:url_ipc",
- "//url/mojo:url_mojom_gurl",
+ "//url/mojom:url_mojom_gurl",
]
deps = [
"//base",
"//ipc",
"//net",
- "//services/network/public/interfaces:interfaces_shared",
+ "//services/network/public/mojom:mojom_shared",
]
+ defines = [ "IS_NETWORK_CPP_BASE_IMPL" ]
}
mojom("test_interfaces") {
@@ -77,7 +97,7 @@ mojom("test_interfaces") {
"network_traits_test_service.mojom",
]
public_deps = [
- "//services/network/public/interfaces",
+ "//services/network/public/mojom",
]
}
@@ -86,11 +106,13 @@ source_set("tests") {
sources = [
"cors/cors_unittest.cc",
- "mutable_network_traffic_annotation_tag_struct_traits_unittest.cc",
- "mutable_partial_network_traffic_annotation_tag_struct_traits_unittest.cc",
- "network_struct_traits_unittest.cc",
- "proxy_config_traits_unittest.cc",
- "proxy_resolving_client_socket_unittest.cc",
+ "cors/preflight_cache_unittest.cc",
+ "cors/preflight_result_unittest.cc",
+ "mutable_network_traffic_annotation_tag_mojom_traits_unittest.cc",
+ "mutable_partial_network_traffic_annotation_tag_mojom_traits_unittest.cc",
+ "network_mojom_traits_unittest.cc",
+ "proxy_config_mojom_traits_unittest.cc",
+ "simple_url_loader_unittest.cc",
]
deps = [
":cpp",
@@ -99,6 +121,7 @@ source_set("tests") {
"//mojo/public/cpp/bindings",
"//net",
"//net:test_support",
+ "//services/network:network_service",
"//testing/gtest",
]
}
diff --git a/chromium/services/network/public/cpp/DEPS b/chromium/services/network/public/cpp/DEPS
index bdd71d84ef9..5fbe57aa45e 100644
--- a/chromium/services/network/public/cpp/DEPS
+++ b/chromium/services/network/public/cpp/DEPS
@@ -1,11 +1,19 @@
include_rules = [
# CORS related files will be included from Blink, and should use cors.mojom-shared.h.
# resource_request.h is an exception since it's not used by Blink.
- "-services/network/public/interfaces/cors.mojom.h",
+ "-services/network/public/mojom/cors.mojom.h",
]
specific_include_rules = {
"resource_request\.h": [
- "+services/network/public/interfaces/cors.mojom.h",
+ "+services/network/public/mojom/cors.mojom.h",
+ ],
+ ".*\.cc": [
+ # Prefs are used to create an independent file with a persisted key:value
+ # store for networking-related data (Like which servers support QUIC),
+ # rather than to store user preferences.
+ "+components/prefs",
+ "+services/network",
+ "+services/proxy_resolver/public/mojom",
],
}
diff --git a/chromium/services/network/public/cpp/OWNERS b/chromium/services/network/public/cpp/OWNERS
index 26c74167c79..2471a002053 100644
--- a/chromium/services/network/public/cpp/OWNERS
+++ b/chromium/services/network/public/cpp/OWNERS
@@ -2,7 +2,7 @@ per-file *.mojom=set noparent
per-file *.mojom=file://ipc/SECURITY_OWNERS
per-file *_ipc_traits*.*=set noparent
per-file *_ipc_traits*.*=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/network/public/cpp/cookie_manager.typemap b/chromium/services/network/public/cpp/cookie_manager.typemap
index 6c63abb66a6..079c275b80d 100644
--- a/chromium/services/network/public/cpp/cookie_manager.typemap
+++ b/chromium/services/network/public/cpp/cookie_manager.typemap
@@ -1,4 +1,4 @@
-mojom = "//services/network/public/interfaces/cookie_manager.mojom"
+mojom = "//services/network/public/mojom/cookie_manager.mojom"
public_headers = [
"//ipc/ipc_message_utils.h",
"//net/cookies/cookie_options.h",
@@ -6,9 +6,9 @@ public_headers = [
"//net/cookies/cookie_constants.h",
]
traits_headers =
- [ "//services/network/public/cpp/cookie_manager_struct_traits.h" ]
+ [ "//services/network/public/cpp/cookie_manager_mojom_traits.h" ]
sources = [
- "//services/network/public/cpp/cookie_manager_struct_traits.cc",
+ "//services/network/public/cpp/cookie_manager_mojom_traits.cc",
]
public_deps = [
"//net",
diff --git a/chromium/services/network/public/cpp/cookie_manager_struct_traits.cc b/chromium/services/network/public/cpp/cookie_manager_mojom_traits.cc
index aa0d1f358e7..19ae612f534 100644
--- a/chromium/services/network/public/cpp/cookie_manager_struct_traits.cc
+++ b/chromium/services/network/public/cpp/cookie_manager_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/cookie_manager_struct_traits.h"
+#include "services/network/public/cpp/cookie_manager_mojom_traits.h"
#include "mojo/common/time_struct_traits.h"
diff --git a/chromium/services/network/public/cpp/cookie_manager_struct_traits.h b/chromium/services/network/public/cpp/cookie_manager_mojom_traits.h
index e087b008e31..35ef412c2c7 100644
--- a/chromium/services/network/public/cpp/cookie_manager_struct_traits.h
+++ b/chromium/services/network/public/cpp/cookie_manager_mojom_traits.h
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_COOKIE_MANAGER_STRUCT_TRAITS_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_COOKIE_MANAGER_STRUCT_TRAITS_H_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_COOKIE_MANAGER_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_COOKIE_MANAGER_MOJOM_TRAITS_H_
#include "ipc/ipc_message_utils.h"
#include "mojo/public/cpp/bindings/enum_traits.h"
#include "net/cookies/canonical_cookie.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_options.h"
-#include "services/network/public/interfaces/cookie_manager.mojom.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
namespace mojo {
@@ -105,4 +105,4 @@ struct StructTraits<network::mojom::CanonicalCookieDataView,
} // namespace mojo
-#endif // SERVICES_NETWORK_PUBLIC_CPP_COOKIE_MANAGER_STRUCT_TRAITS_H_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_COOKIE_MANAGER_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/cors/cors.cc b/chromium/services/network/public/cpp/cors/cors.cc
index e79503d676b..d1c607ebdc0 100644
--- a/chromium/services/network/public/cpp/cors/cors.cc
+++ b/chromium/services/network/public/cpp/cors/cors.cc
@@ -4,8 +4,15 @@
#include "services/network/public/cpp/cors/cors.h"
+#include <algorithm>
+#include <vector>
+
+#include "base/strings/string_util.h"
+#include "net/base/mime_util.h"
+#include "net/http/http_request_headers.h"
#include "url/gurl.h"
#include "url/origin.h"
+#include "url/url_constants.h"
#include "url/url_util.h"
namespace {
@@ -13,6 +20,39 @@ namespace {
const char kAsterisk[] = "*";
const char kLowerCaseTrue[] = "true";
+// TODO(toyoshim): Consider to move following const variables to
+// //net/http/http_request_headers.
+const char kHeadMethod[] = "HEAD";
+const char kPostMethod[] = "POST";
+
+// TODO(toyoshim): Consider to move the following method to
+// //net/base/mime_util, and expose to Blink platform/network in order to
+// replace the existing equivalent method in HTTPParser.
+// We may prefer to implement a strict RFC2616 media-type
+// (https://tools.ietf.org/html/rfc2616#section-3.7) parser.
+std::string ExtractMIMETypeFromMediaType(const std::string& media_type) {
+ std::string::size_type semicolon = media_type.find(';');
+ std::string top_level_type;
+ std::string subtype;
+ if (net::ParseMimeTypeWithoutParameter(media_type.substr(0, semicolon),
+ &top_level_type, &subtype)) {
+ return top_level_type + "/" + subtype;
+ }
+ return std::string();
+}
+
+// url::Origin::Serialize() serializes all Origins with a 'file' scheme to
+// 'file://', but it isn't desirable for CORS check. Returns 'null' instead to
+// be aligned with HTTP Origin header calculation in Blink SecurityOrigin.
+// |allow_file_origin| is used to realize a behavior change that
+// the --allow-file-access-from-files command-line flag needs.
+// TODO(mkwst): Generalize and move to url/Origin.
+std::string Serialize(const url::Origin& origin, bool allow_file_origin) {
+ if (!allow_file_origin && origin.scheme() == url::kFileScheme)
+ return "null";
+ return origin.Serialize();
+}
+
} // namespace
namespace network {
@@ -24,7 +64,9 @@ namespace header_names {
const char kAccessControlAllowCredentials[] =
"Access-Control-Allow-Credentials";
const char kAccessControlAllowOrigin[] = "Access-Control-Allow-Origin";
-const char kAccessControlAllowSuborigin[] = "Access-Control-Allow-Suborigin";
+const char kAccessControlRequestExternal[] = "Access-Control-Request-External";
+const char kAccessControlRequestHeaders[] = "Access-Control-Request-Headers";
+const char kAccessControlRequestMethod[] = "Access-Control-Request-Method";
} // namespace header_names
@@ -33,24 +75,14 @@ base::Optional<mojom::CORSError> CheckAccess(
const GURL& response_url,
const int response_status_code,
const base::Optional<std::string>& allow_origin_header,
- const base::Optional<std::string>& allow_suborigin_header,
const base::Optional<std::string>& allow_credentials_header,
mojom::FetchCredentialsMode credentials_mode,
- const url::Origin& origin) {
+ const url::Origin& origin,
+ bool allow_file_origin) {
if (!response_status_code)
return mojom::CORSError::kInvalidResponse;
- // Check Suborigins, unless the Access-Control-Allow-Origin is '*', which
- // implies that all Suborigins are okay as well.
- bool allow_all_origins = allow_origin_header == kAsterisk;
- if (!origin.suborigin().empty() && !allow_all_origins) {
- if (allow_suborigin_header != kAsterisk &&
- allow_suborigin_header != origin.suborigin()) {
- return mojom::CORSError::kSubOriginMismatch;
- }
- }
-
- if (allow_all_origins) {
+ if (allow_origin_header == kAsterisk) {
// A wildcard Access-Control-Allow-Origin can not be used if credentials are
// to be sent, even with Access-Control-Allow-Credentials set to true.
// See https://fetch.spec.whatwg.org/#cors-protocol-and-credentials.
@@ -66,7 +98,7 @@ base::Optional<mojom::CORSError> CheckAccess(
return mojom::CORSError::kWildcardOriginNotAllowed;
} else if (!allow_origin_header) {
return mojom::CORSError::kMissingAllowOriginHeader;
- } else if (*allow_origin_header != origin.Serialize()) {
+ } else if (*allow_origin_header != Serialize(origin, allow_file_origin)) {
// We do not use url::Origin::IsSameOriginWith() here for two reasons below.
// 1. Allow "null" to match here. The latest spec does not have a clear
// information about this (https://fetch.spec.whatwg.org/#cors-check),
@@ -158,6 +190,91 @@ bool IsCORSEnabledRequestMode(mojom::FetchRequestMode mode) {
mode == mojom::FetchRequestMode::kCORSWithForcedPreflight;
}
+bool IsCORSSafelistedMethod(const std::string& method) {
+ // https://fetch.spec.whatwg.org/#cors-safelisted-method
+ // "A CORS-safelisted method is a method that is `GET`, `HEAD`, or `POST`."
+ static const std::set<std::string> safe_methods = {
+ net::HttpRequestHeaders::kGetMethod, kHeadMethod, kPostMethod};
+ return safe_methods.find(base::ToUpperASCII(method)) != safe_methods.end();
+}
+
+bool IsCORSSafelistedContentType(const std::string& media_type) {
+ static const std::set<std::string> safe_types = {
+ "application/x-www-form-urlencoded", "multipart/form-data", "text/plain"};
+ std::string mime_type =
+ base::ToLowerASCII(ExtractMIMETypeFromMediaType(media_type));
+ return safe_types.find(mime_type) != safe_types.end();
+}
+
+bool IsCORSSafelistedHeader(const std::string& name, const std::string& value) {
+ // https://fetch.spec.whatwg.org/#cors-safelisted-request-header
+ // "A CORS-safelisted header is a header whose name is either one of `Accept`,
+ // `Accept-Language`, and `Content-Language`, or whose name is
+ // `Content-Type` and value, once parsed, is one of
+ // `application/x-www-form-urlencoded`, `multipart/form-data`, and
+ // `text/plain`."
+ //
+ // Treat 'Save-Data' as a CORS-safelisted header, since it is added by Chrome
+ // when Data Saver feature is enabled. Treat inspector headers as a
+ // CORS-safelisted headers, since they are added by blink when the inspector
+ // is open.
+ //
+ // Treat 'Intervention' as a CORS-safelisted header, since it is added by
+ // Chrome when an intervention is (or may be) applied.
+ static const std::set<std::string> safe_names = {
+ "accept", "accept-language",
+ "content-language", "x-devtools-emulate-network-conditions-client-id",
+ "save-data", "intervention"};
+ std::string lower_name = base::ToLowerASCII(name);
+ if (safe_names.find(lower_name) != safe_names.end())
+ return true;
+
+ if (lower_name == "content-type")
+ return IsCORSSafelistedContentType(value);
+
+ return false;
+}
+
+bool IsForbiddenHeader(const std::string& name) {
+ // http://fetch.spec.whatwg.org/#forbidden-header-name
+ // "A forbidden header name is a header name that is one of:
+ // `Accept-Charset`, `Accept-Encoding`, `Access-Control-Request-Headers`,
+ // `Access-Control-Request-Method`, `Connection`, `Content-Length`,
+ // `Cookie`, `Cookie2`, `Date`, `DNT`, `Expect`, `Host`, `Keep-Alive`,
+ // `Origin`, `Referer`, `TE`, `Trailer`, `Transfer-Encoding`, `Upgrade`,
+ // `User-Agent`, `Via`
+ // or starts with `Proxy-` or `Sec-` (including when it is just `Proxy-` or
+ // `Sec-`)."
+ static const std::set<std::string> forbidden_names = {
+ "accept-charset",
+ "accept-encoding",
+ "access-control-request-headers",
+ "access-control-request-method",
+ "connection",
+ "content-length",
+ "cookie",
+ "cookie2",
+ "date",
+ "dnt",
+ "expect",
+ "host",
+ "keep-alive",
+ "origin",
+ "referer",
+ "te",
+ "trailer",
+ "transfer-encoding",
+ "upgrade",
+ "user-agent",
+ "via"};
+ const std::string lower_name = base::ToLowerASCII(name);
+ if (StartsWith(lower_name, "proxy-", base::CompareCase::SENSITIVE) ||
+ StartsWith(lower_name, "sec-", base::CompareCase::SENSITIVE)) {
+ return true;
+ }
+ return forbidden_names.find(lower_name) != forbidden_names.end();
+}
+
} // namespace cors
} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/cors.h b/chromium/services/network/public/cpp/cors/cors.h
index 4ce03e666d1..c4a58fb0697 100644
--- a/chromium/services/network/public/cpp/cors/cors.h
+++ b/chromium/services/network/public/cpp/cors/cors.h
@@ -7,9 +7,10 @@
#include <string>
+#include "base/component_export.h"
#include "base/optional.h"
-#include "services/network/public/interfaces/cors.mojom-shared.h"
-#include "services/network/public/interfaces/fetch_api.mojom-shared.h"
+#include "services/network/public/mojom/cors.mojom-shared.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
class GURL;
namespace url {
@@ -22,21 +23,29 @@ namespace cors {
namespace header_names {
+COMPONENT_EXPORT(NETWORK_CPP)
extern const char kAccessControlAllowCredentials[];
+COMPONENT_EXPORT(NETWORK_CPP)
extern const char kAccessControlAllowOrigin[];
-extern const char kAccessControlAllowSuborigin[];
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const char kAccessControlRequestExternal[];
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const char kAccessControlRequestHeaders[];
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const char kAccessControlRequestMethod[];
} // namespace header_names
// Performs a CORS access check on the response parameters.
+COMPONENT_EXPORT(NETWORK_CPP)
base::Optional<mojom::CORSError> CheckAccess(
const GURL& response_url,
const int response_status_code,
const base::Optional<std::string>& allow_origin_header,
- const base::Optional<std::string>& allow_suborigin_header,
const base::Optional<std::string>& allow_credentials_header,
network::mojom::FetchCredentialsMode credentials_mode,
- const url::Origin& origin);
+ const url::Origin& origin,
+ bool allow_file_origin = false);
// Given a redirected-to URL, checks if the location is allowed
// according to CORS. That is:
@@ -45,21 +54,38 @@ base::Optional<mojom::CORSError> CheckAccess(
// TODO(toyoshim): Remove |skip_scheme_check| that is used when customized
// scheme check runs in Blink side in the legacy mode.
// See https://crbug.com/800669.
+COMPONENT_EXPORT(NETWORK_CPP)
base::Optional<mojom::CORSError> CheckRedirectLocation(const GURL& redirect_url,
bool skip_scheme_check);
// Performs the required CORS checks on the response to a preflight request.
// Returns |kPreflightSuccess| if preflight response was successful.
+// TODO(toyoshim): Rename to CheckPreflightStatus.
+COMPONENT_EXPORT(NETWORK_CPP)
base::Optional<mojom::CORSError> CheckPreflight(const int status_code);
// Checks errors for the currently experimental "Access-Control-Allow-External:"
// header. Shares error conditions with standard preflight checking.
// See https://crbug.com/590714.
+COMPONENT_EXPORT(NETWORK_CPP)
base::Optional<mojom::CORSError> CheckExternalPreflight(
const base::Optional<std::string>& allow_external);
+COMPONENT_EXPORT(NETWORK_CPP)
bool IsCORSEnabledRequestMode(mojom::FetchRequestMode mode);
+// Checks safelisted request parameters.
+COMPONENT_EXPORT(NETWORK_CPP)
+bool IsCORSSafelistedMethod(const std::string& method);
+COMPONENT_EXPORT(NETWORK_CPP)
+bool IsCORSSafelistedContentType(const std::string& name);
+COMPONENT_EXPORT(NETWORK_CPP)
+bool IsCORSSafelistedHeader(const std::string& name, const std::string& value);
+
+// Checks forbidden header in the fetch spec.
+// See https://fetch.spec.whatwg.org/#forbidden-header-name.
+COMPONENT_EXPORT(NETWORK_CPP) bool IsForbiddenHeader(const std::string& name);
+
} // namespace cors
} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/cors_error_status.h b/chromium/services/network/public/cpp/cors/cors_error_status.h
index a8e3551a9ab..0a41734674c 100644
--- a/chromium/services/network/public/cpp/cors/cors_error_status.h
+++ b/chromium/services/network/public/cpp/cors/cors_error_status.h
@@ -5,13 +5,14 @@
#ifndef SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_ERROR_STATUS_H_
#define SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_ERROR_STATUS_H_
+#include "base/component_export.h"
#include "base/memory/scoped_refptr.h"
#include "net/http/http_response_headers.h"
-#include "services/network/public/interfaces/cors.mojom-shared.h"
+#include "services/network/public/mojom/cors.mojom-shared.h"
namespace network {
-struct CORSErrorStatus {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) CORSErrorStatus {
// This constructor is used by generated IPC serialization code.
// Should not use this explicitly.
// TODO(toyoshim, yhirano): Exploring a way to make this private, and allows
diff --git a/chromium/services/network/public/cpp/cors/cors_legacy.cc b/chromium/services/network/public/cpp/cors/cors_legacy.cc
new file mode 100644
index 00000000000..c6a815e9e86
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/cors_legacy.cc
@@ -0,0 +1,42 @@
+// Copyright 2018 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/network/public/cpp/cors/cors_legacy.h"
+
+#include <algorithm>
+#include <vector>
+
+#include "url/gurl.h"
+#include "url/origin.h"
+#include "url/url_util.h"
+
+namespace {
+
+std::vector<url::Origin>* secure_origins = nullptr;
+
+} // namespace
+
+namespace network {
+
+namespace cors {
+
+namespace legacy {
+
+void RegisterSecureOrigins(const std::vector<url::Origin>& origins) {
+ delete secure_origins;
+ secure_origins = new std::vector<url::Origin>(origins.size());
+ std::copy(origins.begin(), origins.end(), secure_origins->begin());
+}
+
+const std::vector<url::Origin>& GetSecureOrigins() {
+ if (!secure_origins)
+ secure_origins = new std::vector<url::Origin>;
+ return *secure_origins;
+}
+
+} // namespace legacy
+
+} // namespace cors
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/cors_legacy.h b/chromium/services/network/public/cpp/cors/cors_legacy.h
new file mode 100644
index 00000000000..526336864e3
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/cors_legacy.h
@@ -0,0 +1,41 @@
+// Copyright 2018 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 SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_LEGACY_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_LEGACY_H_
+
+#include <vector>
+
+#include "base/component_export.h"
+
+namespace url {
+class Origin;
+} // namespace url
+
+namespace network {
+namespace cors {
+
+// Functions in namespace legacy are for legacy code path. Pure Network
+// Service code should not use it. Since files in public/cpp/cors are shared
+// between Network Service and legacy code path in content, but Network Service
+// should not know content dependent concepts, we need to provide abstracted
+// interfaces to implement extra checks for the case code runs in content.
+//
+// TODO(toyoshim): Remove all functions after Network Service is enabled.
+namespace legacy {
+
+// Registers whitelisted secure origins for CORS checks in CORSURLLoader.
+COMPONENT_EXPORT(NETWORK_CPP)
+void RegisterSecureOrigins(const std::vector<url::Origin>& secure_origins);
+
+// Refers the registered whitelisted secure origins.
+COMPONENT_EXPORT(NETWORK_CPP)
+const std::vector<url::Origin>& GetSecureOrigins();
+
+} // namespace legacy
+
+} // namespace cors
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_LEGACY_H_
diff --git a/chromium/services/network/public/cpp/cors/cors_unittest.cc b/chromium/services/network/public/cpp/cors/cors_unittest.cc
index 6d7a5ab7bb9..14fafab5fe8 100644
--- a/chromium/services/network/public/cpp/cors/cors_unittest.cc
+++ b/chromium/services/network/public/cpp/cors/cors_unittest.cc
@@ -18,73 +18,12 @@ TEST_F(CORSTest, CheckAccessDetectsInvalidResponse) {
base::Optional<mojom::CORSError> error = cors::CheckAccess(
GURL(), 0 /* response_status_code */,
base::nullopt /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, url::Origin());
ASSERT_TRUE(error);
EXPECT_EQ(mojom::CORSError::kInvalidResponse, *error);
}
-// Tests if cors::CheckAccess detects kSubOriginMismatch error correctly.
-TEST_F(CORSTest, CheckAccessDetectsSubOriginMismatch) {
- const GURL response_url("http://example.com/data");
- const std::string suborigin("suborigin");
- const std::string serialized_origin("http-so://suborigin.example.com");
- const url::Origin origin = url::Origin::Create(GURL(serialized_origin));
- const int response_status_code = 200;
- const std::string allow_all_header("*");
-
- // Access-Control-Allow-Origin is '*'.
- base::Optional<mojom::CORSError> error1 =
- cors::CheckAccess(response_url, response_status_code,
- allow_all_header /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
- base::nullopt /* allow_credentials_header */,
- network::mojom::FetchCredentialsMode::kOmit, origin);
- EXPECT_FALSE(error1);
-
- // Access-Control-Allow-Origin matches the serialized origin, and
- // Access-Control-Allow-Suborigin is '*'.
- base::Optional<mojom::CORSError> error2 =
- cors::CheckAccess(response_url, response_status_code,
- serialized_origin /* allow_origin_header */,
- allow_all_header /* allow_suborigin_header */,
- base::nullopt /* allow_credentials_header */,
- network::mojom::FetchCredentialsMode::kOmit, origin);
- EXPECT_FALSE(error2);
-
- // Access-Control-Allow-Origin matches the serialized origin, and
- // Access-Control-Allow-Suborigin matches the suborigin.
- base::Optional<mojom::CORSError> error3 =
- cors::CheckAccess(response_url, response_status_code,
- serialized_origin /* allow_origin_header */,
- suborigin /* allow_suborigin_header */,
- base::nullopt /* allow_credentials_header */,
- network::mojom::FetchCredentialsMode::kOmit, origin);
- EXPECT_FALSE(error3);
-
- // Access-Control-Allow-Suborigin is required, but missed.
- base::Optional<mojom::CORSError> error4 =
- cors::CheckAccess(response_url, response_status_code,
- base::nullopt /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
- base::nullopt /* allow_credentials_header */,
- network::mojom::FetchCredentialsMode::kOmit, origin);
- ASSERT_TRUE(error4);
- EXPECT_EQ(mojom::CORSError::kSubOriginMismatch, *error4);
-
- // Even if the origin matches, suborigin should also match if |origin| has
- // suborigin.
- base::Optional<mojom::CORSError> error5 =
- cors::CheckAccess(response_url, response_status_code,
- serialized_origin /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
- base::nullopt /* allow_credentials_header */,
- network::mojom::FetchCredentialsMode::kOmit, origin);
- ASSERT_TRUE(error5);
- EXPECT_EQ(mojom::CORSError::kSubOriginMismatch, *error5);
-}
-
// Tests if cors::CheckAccess detects kWildcardOriginNotAllowed error correctly.
TEST_F(CORSTest, CheckAccessDetectsWildcardOriginNotAllowed) {
const GURL response_url("http://example.com/data");
@@ -96,7 +35,6 @@ TEST_F(CORSTest, CheckAccessDetectsWildcardOriginNotAllowed) {
base::Optional<mojom::CORSError> error1 =
cors::CheckAccess(response_url, response_status_code,
allow_all_header /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
EXPECT_FALSE(error1);
@@ -106,7 +44,6 @@ TEST_F(CORSTest, CheckAccessDetectsWildcardOriginNotAllowed) {
base::Optional<mojom::CORSError> error2 =
cors::CheckAccess(response_url, response_status_code,
allow_all_header /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kInclude, origin);
ASSERT_TRUE(error2);
@@ -123,7 +60,6 @@ TEST_F(CORSTest, CheckAccessDetectsMissingAllowOriginHeader) {
base::Optional<mojom::CORSError> error =
cors::CheckAccess(response_url, response_status_code,
base::nullopt /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error);
@@ -142,7 +78,6 @@ TEST_F(CORSTest, CheckAccessDetectsMultipleAllowOriginValues) {
base::Optional<mojom::CORSError> error1 = cors::CheckAccess(
response_url, response_status_code,
space_separated_multiple_origins /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error1);
@@ -153,7 +88,6 @@ TEST_F(CORSTest, CheckAccessDetectsMultipleAllowOriginValues) {
base::Optional<mojom::CORSError> error2 = cors::CheckAccess(
response_url, response_status_code,
comma_separated_multiple_origins /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error2);
@@ -169,7 +103,6 @@ TEST_F(CORSTest, CheckAccessDetectsInvalidAllowOriginValue) {
base::Optional<mojom::CORSError> error =
cors::CheckAccess(response_url, response_status_code,
std::string("invalid.origin") /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error);
@@ -185,7 +118,6 @@ TEST_F(CORSTest, CheckAccessDetectsAllowOriginMismatch) {
base::Optional<mojom::CORSError> error1 =
cors::CheckAccess(response_url, response_status_code,
origin.Serialize() /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_FALSE(error1);
@@ -193,7 +125,6 @@ TEST_F(CORSTest, CheckAccessDetectsAllowOriginMismatch) {
base::Optional<mojom::CORSError> error2 = cors::CheckAccess(
response_url, response_status_code,
std::string("http://not.google.com") /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, origin);
ASSERT_TRUE(error2);
@@ -206,7 +137,6 @@ TEST_F(CORSTest, CheckAccessDetectsAllowOriginMismatch) {
base::Optional<mojom::CORSError> error3 = cors::CheckAccess(
response_url, response_status_code, null_string /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kOmit, null_origin);
EXPECT_FALSE(error3);
@@ -222,7 +152,6 @@ TEST_F(CORSTest, CheckAccessDetectsDisallowCredentialsNotSetToTrue) {
base::Optional<mojom::CORSError> error1 =
cors::CheckAccess(response_url, response_status_code,
origin.Serialize() /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
std::string("true") /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kInclude, origin);
ASSERT_FALSE(error1);
@@ -230,7 +159,6 @@ TEST_F(CORSTest, CheckAccessDetectsDisallowCredentialsNotSetToTrue) {
base::Optional<mojom::CORSError> error2 =
cors::CheckAccess(response_url, response_status_code,
origin.Serialize() /* allow_origin_header */,
- base::nullopt /* allow_suborigin_header */,
base::nullopt /* allow_credentials_header */,
network::mojom::FetchCredentialsMode::kInclude, origin);
ASSERT_TRUE(error2);
@@ -297,6 +225,40 @@ TEST_F(CORSTest, CheckPreflightDetectsErrors) {
EXPECT_EQ(mojom::CORSError::kPreflightInvalidAllowExternal, *error3);
}
+TEST_F(CORSTest, CheckCORSSafelist) {
+ // Method check should be case-insensitive.
+ EXPECT_TRUE(cors::IsCORSSafelistedMethod("get"));
+ EXPECT_TRUE(cors::IsCORSSafelistedMethod("Get"));
+ EXPECT_TRUE(cors::IsCORSSafelistedMethod("GET"));
+ EXPECT_TRUE(cors::IsCORSSafelistedMethod("HEAD"));
+ EXPECT_TRUE(cors::IsCORSSafelistedMethod("POST"));
+ EXPECT_FALSE(cors::IsCORSSafelistedMethod("OPTIONS"));
+
+ // Content-Type check should be case-insensitive, and should ignore spaces and
+ // parameters such as charset after a semicolon.
+ EXPECT_TRUE(
+ cors::IsCORSSafelistedContentType("application/x-www-form-urlencoded"));
+ EXPECT_TRUE(cors::IsCORSSafelistedContentType("multipart/form-data"));
+ EXPECT_TRUE(cors::IsCORSSafelistedContentType("text/plain"));
+ EXPECT_TRUE(cors::IsCORSSafelistedContentType("TEXT/PLAIN"));
+ EXPECT_TRUE(cors::IsCORSSafelistedContentType("text/plain;charset=utf-8"));
+ EXPECT_TRUE(cors::IsCORSSafelistedContentType(" text/plain ;charset=utf-8"));
+ EXPECT_FALSE(cors::IsCORSSafelistedContentType("text/html"));
+
+ // Header check should be case-insensitive. Value must be considered only for
+ // Content-Type.
+ EXPECT_TRUE(cors::IsCORSSafelistedHeader("accept", "text/html"));
+ EXPECT_TRUE(cors::IsCORSSafelistedHeader("Accept-Language", "en"));
+ EXPECT_TRUE(cors::IsCORSSafelistedHeader("Content-Language", "ja"));
+ EXPECT_TRUE(cors::IsCORSSafelistedHeader(
+ "x-devtools-emulate-network-conditions-client-id", ""));
+ EXPECT_TRUE(cors::IsCORSSafelistedHeader("SAVE-DATA", ""));
+ EXPECT_TRUE(cors::IsCORSSafelistedHeader("Intervention", ""));
+ EXPECT_FALSE(cors::IsCORSSafelistedHeader("Cache-Control", ""));
+ EXPECT_TRUE(cors::IsCORSSafelistedHeader("Content-Type", "text/plain"));
+ EXPECT_FALSE(cors::IsCORSSafelistedHeader("Content-Type", "image/png"));
+}
+
} // namespace
} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/cors_url_loader.cc b/chromium/services/network/public/cpp/cors/cors_url_loader.cc
new file mode 100644
index 00000000000..30427e3dc69
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/cors_url_loader.cc
@@ -0,0 +1,237 @@
+// 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 "services/network/public/cpp/cors/cors_url_loader.h"
+
+#include "base/stl_util.h"
+#include "services/network/public/cpp/cors/cors.h"
+#include "services/network/public/cpp/cors/cors_legacy.h"
+#include "url/url_util.h"
+
+namespace network {
+
+namespace {
+
+bool IsOriginWhiteListedTrustworthy(const url::Origin& origin) {
+ if (origin.unique())
+ return false;
+
+ // Note: NoAccessSchemes are managed by per-process basis. This check is for
+ // use of network service disabled.
+ if (base::ContainsValue(url::GetNoAccessSchemes(), origin.scheme()))
+ return false;
+
+ return base::ContainsValue(cors::legacy::GetSecureOrigins(), origin);
+}
+
+bool CalculateCORSFlag(const ResourceRequest& request) {
+ if (request.fetch_request_mode == mojom::FetchRequestMode::kNavigate)
+ return false;
+ url::Origin url_origin = url::Origin::Create(request.url);
+ if (IsOriginWhiteListedTrustworthy(url_origin))
+ return false;
+ if (!request.request_initiator.has_value())
+ return true;
+ url::Origin security_origin(request.request_initiator.value());
+ return !security_origin.IsSameOriginWith(url_origin);
+}
+
+base::Optional<std::string> GetHeaderString(
+ const scoped_refptr<net::HttpResponseHeaders>& headers,
+ const std::string& header_name) {
+ std::string header_value;
+ if (!headers->GetNormalizedHeader(header_name, &header_value))
+ return base::nullopt;
+ return header_value;
+}
+
+} // namespace
+
+// TODO(toyoshim): At the moment this class simply forwards all calls to the
+// underlying network loader. Part of the effort to move CORS handling out of
+// Blink: http://crbug/736308.
+CORSURLLoader::CORSURLLoader(
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const ResourceRequest& resource_request,
+ mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ mojom::URLLoaderFactory* network_loader_factory)
+ : network_loader_factory_(network_loader_factory),
+ network_client_binding_(this),
+ forwarding_client_(std::move(client)),
+ security_origin_(
+ resource_request.request_initiator.value_or(url::Origin())),
+ last_response_url_(resource_request.url),
+ fetch_request_mode_(resource_request.fetch_request_mode),
+ fetch_credentials_mode_(resource_request.fetch_credentials_mode),
+ fetch_cors_flag_(CalculateCORSFlag(resource_request)) {
+ DCHECK(network_loader_factory_);
+
+ if (fetch_cors_flag_ &&
+ fetch_request_mode_ == mojom::FetchRequestMode::kSameOrigin) {
+ forwarding_client_->OnComplete(URLLoaderCompletionStatus(
+ CORSErrorStatus(mojom::CORSError::kDisallowedByMode)));
+ return;
+ }
+
+ // TODO(toyoshim): Needs some checks if the calculated fetch_cors_flag_
+ // is allowed in this request or not.
+
+ mojom::URLLoaderClientPtr network_client;
+ network_client_binding_.Bind(mojo::MakeRequest(&network_client));
+ // Binding |this| as an unretained pointer is safe because
+ // |network_client_binding_| shares this object's lifetime.
+ network_client_binding_.set_connection_error_handler(base::BindOnce(
+ &CORSURLLoader::OnUpstreamConnectionError, base::Unretained(this)));
+ network_loader_factory_->CreateLoaderAndStart(
+ mojo::MakeRequest(&network_loader_), routing_id, request_id, options,
+ resource_request, std::move(network_client), traffic_annotation);
+}
+
+CORSURLLoader::~CORSURLLoader() {}
+
+void CORSURLLoader::FollowRedirect() {
+ DCHECK(network_loader_);
+ DCHECK(is_waiting_follow_redirect_call_);
+ is_waiting_follow_redirect_call_ = false;
+ network_loader_->FollowRedirect();
+}
+
+void CORSURLLoader::ProceedWithResponse() {
+ NOTREACHED();
+}
+
+void CORSURLLoader::SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) {
+ // TODO(toyoshim): Should not be called during the redirect decisions, but
+ // Blink calls actually.
+ // DCHECK(!is_waiting_follow_redirect_call_);
+ if (network_loader_)
+ network_loader_->SetPriority(priority, intra_priority_value);
+}
+
+void CORSURLLoader::PauseReadingBodyFromNet() {
+ DCHECK(!is_waiting_follow_redirect_call_);
+ if (network_loader_)
+ network_loader_->PauseReadingBodyFromNet();
+}
+
+void CORSURLLoader::ResumeReadingBodyFromNet() {
+ DCHECK(!is_waiting_follow_redirect_call_);
+ if (network_loader_)
+ network_loader_->ResumeReadingBodyFromNet();
+}
+
+void CORSURLLoader::OnReceiveResponse(
+ const ResourceResponseHead& response_head,
+ const base::Optional<net::SSLInfo>& ssl_info,
+ mojom::DownloadedTempFilePtr downloaded_file) {
+ DCHECK(network_loader_);
+ DCHECK(forwarding_client_);
+ DCHECK(!is_waiting_follow_redirect_call_);
+ if (fetch_cors_flag_ && cors::IsCORSEnabledRequestMode(fetch_request_mode_)) {
+ // TODO(toyoshim): Reflect --allow-file-access-from-files flag.
+ base::Optional<mojom::CORSError> cors_error = cors::CheckAccess(
+ last_response_url_, response_head.headers->response_code(),
+ GetHeaderString(response_head.headers,
+ cors::header_names::kAccessControlAllowOrigin),
+ GetHeaderString(response_head.headers,
+ cors::header_names::kAccessControlAllowCredentials),
+ fetch_credentials_mode_, security_origin_);
+ if (cors_error) {
+ // TODO(toyoshim): Generate related_response_headers here.
+ CORSErrorStatus cors_error_status(*cors_error);
+ HandleComplete(URLLoaderCompletionStatus(cors_error_status));
+ return;
+ }
+ }
+ forwarding_client_->OnReceiveResponse(response_head, ssl_info,
+ std::move(downloaded_file));
+}
+
+void CORSURLLoader::OnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ const ResourceResponseHead& response_head) {
+ DCHECK(network_loader_);
+ DCHECK(forwarding_client_);
+ DCHECK(!is_waiting_follow_redirect_call_);
+
+ // TODO(toyoshim): Following code expects OnReceivedRedirect is invoked
+ // asynchronously, and |last_response_url_| and other methods should not be
+ // accessed until FollowRedirect() is called.
+ // We need to ensure callback behaviors once redirect implementation in this
+ // class is ready for testing.
+ is_waiting_follow_redirect_call_ = true;
+ last_response_url_ = redirect_info.new_url;
+ forwarding_client_->OnReceiveRedirect(redirect_info, response_head);
+}
+
+void CORSURLLoader::OnDataDownloaded(int64_t data_len,
+ int64_t encoded_data_len) {
+ DCHECK(network_loader_);
+ DCHECK(forwarding_client_);
+ DCHECK(!is_waiting_follow_redirect_call_);
+ forwarding_client_->OnDataDownloaded(data_len, encoded_data_len);
+}
+
+void CORSURLLoader::OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback ack_callback) {
+ DCHECK(network_loader_);
+ DCHECK(forwarding_client_);
+ DCHECK(!is_waiting_follow_redirect_call_);
+ forwarding_client_->OnUploadProgress(current_position, total_size,
+ std::move(ack_callback));
+}
+
+void CORSURLLoader::OnReceiveCachedMetadata(const std::vector<uint8_t>& data) {
+ DCHECK(network_loader_);
+ DCHECK(forwarding_client_);
+ DCHECK(!is_waiting_follow_redirect_call_);
+ forwarding_client_->OnReceiveCachedMetadata(data);
+}
+
+void CORSURLLoader::OnTransferSizeUpdated(int32_t transfer_size_diff) {
+ DCHECK(network_loader_);
+ DCHECK(forwarding_client_);
+ DCHECK(!is_waiting_follow_redirect_call_);
+ forwarding_client_->OnTransferSizeUpdated(transfer_size_diff);
+}
+
+void CORSURLLoader::OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) {
+ DCHECK(network_loader_);
+ DCHECK(forwarding_client_);
+ DCHECK(!is_waiting_follow_redirect_call_);
+ forwarding_client_->OnStartLoadingResponseBody(std::move(body));
+}
+
+void CORSURLLoader::OnComplete(const URLLoaderCompletionStatus& status) {
+ DCHECK(network_loader_);
+ DCHECK(forwarding_client_);
+ DCHECK(!is_waiting_follow_redirect_call_);
+ HandleComplete(status);
+}
+
+void CORSURLLoader::OnUpstreamConnectionError() {
+ // |network_client_binding_| has experienced a connection error and will no
+ // longer call any of the mojom::URLLoaderClient methods above. The client
+ // pipe to the downstream client is closed to inform it of this failure. The
+ // client should respond by closing its mojom::URLLoader pipe which will cause
+ // this object to be destroyed.
+ forwarding_client_.reset();
+}
+
+void CORSURLLoader::HandleComplete(const URLLoaderCompletionStatus& status) {
+ forwarding_client_->OnComplete(status);
+ forwarding_client_.reset();
+
+ // Close pipes to ignore possible subsequent callback invocations.
+ network_client_binding_.Close();
+ network_loader_.reset();
+}
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/cors_url_loader.h b/chromium/services/network/public/cpp/cors/cors_url_loader.h
new file mode 100644
index 00000000000..3c8efcd2ae8
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/cors_url_loader.h
@@ -0,0 +1,102 @@
+// 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 SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_URL_LOADER_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_URL_LOADER_H_
+
+#include "mojo/public/cpp/bindings/binding.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/fetch_api.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+namespace network {
+
+// Wrapper class that adds cross-origin resource sharing capabilities
+// (https://fetch.spec.whatwg.org/#http-cors-protocol), delegating requests as
+// well as potential preflight requests to the supplied
+// |network_loader_factory|. It is owned by the CORSURLLoaderFactory that
+// created it.
+class COMPONENT_EXPORT(NETWORK_CPP) CORSURLLoader
+ : public mojom::URLLoader,
+ public mojom::URLLoaderClient {
+ public:
+ // Assumes network_loader_factory outlives this loader.
+ CORSURLLoader(
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const ResourceRequest& resource_request,
+ mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ mojom::URLLoaderFactory* network_loader_factory);
+
+ ~CORSURLLoader() override;
+
+ // mojom::URLLoader overrides:
+ void FollowRedirect() override;
+ void ProceedWithResponse() override;
+ void SetPriority(net::RequestPriority priority,
+ int intra_priority_value) override;
+ void PauseReadingBodyFromNet() override;
+ void ResumeReadingBodyFromNet() override;
+
+ // mojom::URLLoaderClient overrides:
+ void OnReceiveResponse(const ResourceResponseHead& head,
+ const base::Optional<net::SSLInfo>& ssl_info,
+ mojom::DownloadedTempFilePtr downloaded_file) override;
+ void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+ const ResourceResponseHead& head) override;
+ void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override;
+ void OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ base::OnceCallback<void()> callback) override;
+ void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
+ void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override;
+ void OnComplete(const URLLoaderCompletionStatus& status) override;
+
+ private:
+ // Called when there is a connection error on the upstream pipe used for the
+ // actual request.
+ void OnUpstreamConnectionError();
+
+ // Handles OnComplete() callback.
+ void HandleComplete(const URLLoaderCompletionStatus& status);
+
+ // This raw URLLoaderFactory pointer is shared with the CORSURLLoaderFactory
+ // that created and owns this object.
+ mojom::URLLoaderFactory* network_loader_factory_;
+
+ // For the actual request.
+ mojom::URLLoaderPtr network_loader_;
+ mojo::Binding<mojom::URLLoaderClient> network_client_binding_;
+
+ // To be a URLLoader for the client.
+ mojom::URLLoaderClientPtr forwarding_client_;
+
+ // Request initiator's origin.
+ url::Origin security_origin_;
+
+ // The last response URL, that is usually the requested URL, but can be
+ // different if redirects happen.
+ GURL last_response_url_;
+
+ // A flag to indicate that the instance is waiting for that forwarding_client_
+ // calls FollowRedirect.
+ bool is_waiting_follow_redirect_call_ = false;
+
+ // Corresponds to the Fetch spec, https://fetch.spec.whatwg.org/.
+ mojom::FetchRequestMode fetch_request_mode_;
+ mojom::FetchCredentialsMode fetch_credentials_mode_;
+ bool fetch_cors_flag_;
+
+ DISALLOW_COPY_AND_ASSIGN(CORSURLLoader);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_URL_LOADER_H_
diff --git a/chromium/services/network/public/cpp/cors/cors_url_loader_factory.cc b/chromium/services/network/public/cpp/cors/cors_url_loader_factory.cc
new file mode 100644
index 00000000000..18007f73042
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/cors_url_loader_factory.cc
@@ -0,0 +1,45 @@
+// Copyright 2018 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/network/public/cpp/cors/cors_url_loader_factory.h"
+
+#include "services/network/public/cpp/cors/cors_url_loader.h"
+#include "services/network/public/cpp/features.h"
+
+namespace network {
+
+CORSURLLoaderFactory::CORSURLLoaderFactory(
+ std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory)
+ : network_loader_factory_(std::move(network_loader_factory)) {}
+
+CORSURLLoaderFactory::~CORSURLLoaderFactory() = default;
+
+void CORSURLLoaderFactory::CreateLoaderAndStart(
+ mojom::URLLoaderRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const ResourceRequest& resource_request,
+ mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+ if (base::FeatureList::IsEnabled(features::kOutOfBlinkCORS)) {
+ loader_bindings_.AddBinding(
+ std::make_unique<CORSURLLoader>(routing_id, request_id, options,
+ resource_request, std::move(client),
+ traffic_annotation,
+ network_loader_factory_.get()),
+ std::move(request));
+ } else {
+ network_loader_factory_->CreateLoaderAndStart(
+ std::move(request), routing_id, request_id, options, resource_request,
+ std::move(client), traffic_annotation);
+ }
+}
+
+void CORSURLLoaderFactory::Clone(mojom::URLLoaderFactoryRequest request) {
+ // The cloned factories stop working when this factory is destructed.
+ bindings_.AddBinding(this, std::move(request));
+}
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/cors_url_loader_factory.h b/chromium/services/network/public/cpp/cors/cors_url_loader_factory.h
new file mode 100644
index 00000000000..57382dca419
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/cors_url_loader_factory.h
@@ -0,0 +1,54 @@
+// Copyright 2018 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 SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_URL_LOADER_FACTORY_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_URL_LOADER_FACTORY_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace network {
+
+struct ResourceRequest;
+
+// A factory class to create a URLLoader that supports CORS.
+// This class takes a network::mojom::URLLoaderFactory instance in the
+// constructor and owns it to make network requests for CORS preflight, and
+// actual network request.
+class COMPONENT_EXPORT(NETWORK_CPP) CORSURLLoaderFactory final
+ : public mojom::URLLoaderFactory {
+ public:
+ explicit CORSURLLoaderFactory(
+ std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory);
+ ~CORSURLLoaderFactory() override;
+
+ private:
+ // Implements mojom::URLLoaderFactory.
+ void CreateLoaderAndStart(mojom::URLLoaderRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const ResourceRequest& resource_request,
+ mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override;
+ void Clone(mojom::URLLoaderFactoryRequest request) override;
+
+ mojo::BindingSet<mojom::URLLoaderFactory> bindings_;
+
+ std::unique_ptr<mojom::URLLoaderFactory> network_loader_factory_;
+
+ // The factory owns the CORSURLLoader it creates.
+ mojo::StrongBindingSet<mojom::URLLoader> loader_bindings_;
+
+ DISALLOW_COPY_AND_ASSIGN(CORSURLLoaderFactory);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_URL_LOADER_FACTORY_H_
diff --git a/chromium/services/network/public/cpp/cors/preflight_cache.cc b/chromium/services/network/public/cpp/cors/preflight_cache.cc
new file mode 100644
index 00000000000..7fe92ba5934
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/preflight_cache.cc
@@ -0,0 +1,68 @@
+// Copyright 2018 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/network/public/cpp/cors/preflight_cache.h"
+
+#include "url/gurl.h"
+
+namespace network {
+
+namespace cors {
+
+PreflightCache::PreflightCache() = default;
+PreflightCache::~PreflightCache() = default;
+
+void PreflightCache::AppendEntry(
+ const std::string& origin,
+ const GURL& url,
+ std::unique_ptr<PreflightResult> preflight_result) {
+ DCHECK(preflight_result);
+ cache_[origin][url.spec()] = std::move(preflight_result);
+}
+
+bool PreflightCache::CheckIfRequestCanSkipPreflight(
+ const std::string& origin,
+ const GURL& url,
+ mojom::FetchCredentialsMode credentials_mode,
+ const std::string& method,
+ const net::HttpRequestHeaders& request_headers) {
+ // Either |origin| or |url| are not in cache.
+ auto cache_per_origin = cache_.find(origin);
+ if (cache_per_origin == cache_.end())
+ return false;
+
+ auto cache_entry = cache_per_origin->second.find(url.spec());
+ if (cache_entry == cache_per_origin->second.end())
+ return false;
+
+ // Both |origin| and |url| are in cache. Check if the entry is still valid and
+ // sufficient to skip CORS-preflight.
+ if (cache_entry->second->EnsureAllowedRequest(credentials_mode, method,
+ request_headers)) {
+ return true;
+ }
+
+ // The cache entry is either stale or not sufficient. Remove the item from the
+ // cache.
+ cache_per_origin->second.erase(url.spec());
+ if (cache_per_origin->second.empty())
+ cache_.erase(cache_per_origin);
+
+ return false;
+}
+
+size_t PreflightCache::CountOriginsForTesting() const {
+ return cache_.size();
+}
+
+size_t PreflightCache::CountEntriesForTesting() const {
+ size_t entries = 0;
+ for (auto const& cache_per_origin : cache_)
+ entries += cache_per_origin.second.size();
+ return entries;
+}
+
+} // namespace cors
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/preflight_cache.h b/chromium/services/network/public/cpp/cors/preflight_cache.h
new file mode 100644
index 00000000000..26873dd9b2b
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/preflight_cache.h
@@ -0,0 +1,66 @@
+// Copyright 2018 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 SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_CACHE_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_CACHE_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "net/http/http_request_headers.h"
+#include "services/network/public/cpp/cors/preflight_result.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+
+class GURL;
+
+namespace network {
+
+namespace cors {
+
+// A class to implement CORS-preflight cache that is defined in the fetch spec,
+// https://fetch.spec.whatwg.org/#concept-cache.
+class COMPONENT_EXPORT(NETWORK_CPP) PreflightCache final {
+ public:
+ PreflightCache();
+ ~PreflightCache();
+
+ // Appends new |preflight_result| entry to the cache for a specified |origin|
+ // and |url|.
+ void AppendEntry(const std::string& origin,
+ const GURL& url,
+ std::unique_ptr<PreflightResult> preflight_result);
+
+ // Consults with cached results, and decides if we can skip CORS-preflight or
+ // not.
+ bool CheckIfRequestCanSkipPreflight(
+ const std::string& origin,
+ const GURL& url,
+ mojom::FetchCredentialsMode credentials_mode,
+ const std::string& method,
+ const net::HttpRequestHeaders& headers);
+
+ // Counts cached origins for testing.
+ size_t CountOriginsForTesting() const;
+
+ // Counts cached entries for testing.
+ size_t CountEntriesForTesting() const;
+
+ private:
+ // A map for caching. The outer map takes an origin to find a per-origin
+ // cache map, and the inner map takes an URL to find a cached entry.
+ std::map<std::string /* origin */,
+ std::map<std::string /* url */, std::unique_ptr<PreflightResult>>>
+ cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreflightCache);
+};
+
+} // namespace cors
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_CACHE_H_
diff --git a/chromium/services/network/public/cpp/cors/preflight_cache_unittest.cc b/chromium/services/network/public/cpp/cors/preflight_cache_unittest.cc
new file mode 100644
index 00000000000..2ad111bbeaa
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/preflight_cache_unittest.cc
@@ -0,0 +1,116 @@
+// Copyright 2018 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/network/public/cpp/cors/preflight_cache.h"
+
+#include "base/test/simple_test_tick_clock.h"
+#include "base/time/time.h"
+#include "net/http/http_request_headers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace network {
+
+namespace cors {
+
+namespace {
+
+class PreflightCacheTest : public testing::Test {
+ public:
+ PreflightCacheTest() = default;
+
+ protected:
+ size_t CountOrigins() const { return cache_.CountOriginsForTesting(); }
+ size_t CountEntries() const { return cache_.CountEntriesForTesting(); }
+ PreflightCache* cache() { return &cache_; }
+
+ void AppendEntry(const std::string& origin, const GURL& url) {
+ std::unique_ptr<PreflightResult> result = PreflightResult::Create(
+ mojom::FetchCredentialsMode::kInclude, std::string("POST"),
+ base::nullopt, std::string("5"), nullptr);
+ cache_.AppendEntry(origin, url, std::move(result));
+ }
+
+ bool CheckEntryAndRefreshCache(const std::string& origin, const GURL& url) {
+ return cache_.CheckIfRequestCanSkipPreflight(
+ origin, url, network::mojom::FetchCredentialsMode::kInclude, "POST",
+ net::HttpRequestHeaders());
+ }
+
+ void Advance(int seconds) {
+ clock_.Advance(base::TimeDelta::FromSeconds(seconds));
+ }
+
+ private:
+ // testing::Test implementation.
+ void SetUp() override { PreflightResult::SetTickClockForTesting(&clock_); }
+ void TearDown() override { PreflightResult::SetTickClockForTesting(nullptr); }
+
+ PreflightCache cache_;
+ base::SimpleTestTickClock clock_;
+};
+
+TEST_F(PreflightCacheTest, CacheSize) {
+ const std::string origin("null");
+ const std::string other_origin("http://www.other.com:80");
+ const GURL url("http://www.test.com/A");
+ const GURL other_url("http://www.test.com/B");
+
+ EXPECT_EQ(0u, CountOrigins());
+ EXPECT_EQ(0u, CountEntries());
+
+ AppendEntry(origin, url);
+
+ EXPECT_EQ(1u, CountOrigins());
+ EXPECT_EQ(1u, CountEntries());
+
+ AppendEntry(origin, other_url);
+
+ EXPECT_EQ(1u, CountOrigins());
+ EXPECT_EQ(2u, CountEntries());
+
+ AppendEntry(other_origin, url);
+
+ EXPECT_EQ(2u, CountOrigins());
+ EXPECT_EQ(3u, CountEntries());
+}
+
+TEST_F(PreflightCacheTest, CacheTimeout) {
+ const std::string origin("null");
+ const GURL url("http://www.test.com/A");
+ const GURL other_url("http://www.test.com/B");
+
+ EXPECT_EQ(0u, CountOrigins());
+ EXPECT_EQ(0u, CountEntries());
+
+ AppendEntry(origin, url);
+ AppendEntry(origin, other_url);
+
+ EXPECT_EQ(1u, CountOrigins());
+ EXPECT_EQ(2u, CountEntries());
+
+ // Cache entry should still be valid.
+ EXPECT_TRUE(CheckEntryAndRefreshCache(origin, url));
+
+ // Advance time by ten seconds.
+ Advance(10);
+
+ // Cache entry should now be expired.
+ EXPECT_FALSE(CheckEntryAndRefreshCache(origin, url));
+
+ EXPECT_EQ(1u, CountOrigins());
+ EXPECT_EQ(1u, CountEntries());
+
+ // Cache entry should be expired.
+ EXPECT_FALSE(CheckEntryAndRefreshCache(origin, other_url));
+
+ EXPECT_EQ(0u, CountOrigins());
+ EXPECT_EQ(0u, CountEntries());
+}
+
+} // namespace
+
+} // namespace cors
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/preflight_result.cc b/chromium/services/network/public/cpp/cors/preflight_result.cc
new file mode 100644
index 00000000000..63e30ad8a71
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/preflight_result.cc
@@ -0,0 +1,212 @@
+// Copyright 2018 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/network/public/cpp/cors/preflight_result.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/time/default_tick_clock.h"
+#include "base/time/tick_clock.h"
+#include "base/time/time.h"
+#include "net/http/http_request_headers.h"
+#include "services/network/public/cpp/cors/cors.h"
+
+namespace network {
+
+namespace cors {
+
+namespace {
+
+// Timeout values below are at the discretion of the user agent.
+
+// Default cache expiry time for an entry that does not have
+// Access-Control-Max-Age header in its CORS-preflight response.
+constexpr base::TimeDelta kDefaultTimeout = base::TimeDelta::FromSeconds(5);
+
+// Maximum cache expiry time. Even if a CORS-preflight response contains
+// Access-Control-Max-Age header that specifies a longer expiry time, this
+// maximum time is applied.
+//
+// Note: Should be short enough to minimize the risk of using a poisoned cache
+// after switching to a secure network.
+// TODO(toyoshim): Consider to invalidate all entries when network configuration
+// is changed. See also discussion at https://crbug.com/131368.
+constexpr base::TimeDelta kMaxTimeout = base::TimeDelta::FromSeconds(600);
+
+// Holds TickClock instance to overwrite TimeTicks::Now() for testing.
+base::TickClock* tick_clock_for_testing = nullptr;
+
+base::TimeTicks Now() {
+ if (tick_clock_for_testing)
+ return tick_clock_for_testing->NowTicks();
+ return base::TimeTicks::Now();
+}
+
+bool ParseAccessControlMaxAge(const base::Optional<std::string>& max_age,
+ base::TimeDelta* expiry_delta) {
+ DCHECK(expiry_delta);
+
+ if (!max_age)
+ return false;
+
+ uint64_t delta;
+ if (!base::StringToUint64(*max_age, &delta))
+ return false;
+
+ *expiry_delta = base::TimeDelta::FromSeconds(delta);
+ if (*expiry_delta > kMaxTimeout)
+ *expiry_delta = kMaxTimeout;
+ return true;
+}
+
+// At this moment, this function always succeeds.
+bool ParseAccessControlAllowList(const base::Optional<std::string>& string,
+ base::flat_set<std::string>* set,
+ bool insert_in_lower_case) {
+ DCHECK(set);
+
+ if (!string)
+ return true;
+
+ for (const auto& value : base::SplitString(
+ *string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY)) {
+ // TODO(toyoshim): Strict ABNF header field checks want to be applied, e.g.
+ // strict VCHAR check of RFC-7230.
+ set->insert(insert_in_lower_case ? base::ToLowerASCII(value) : value);
+ }
+ return true;
+}
+
+} // namespace
+
+// static
+void PreflightResult::SetTickClockForTesting(base::TickClock* tick_clock) {
+ tick_clock_for_testing = tick_clock;
+}
+
+// static
+std::unique_ptr<PreflightResult> PreflightResult::Create(
+ const mojom::FetchCredentialsMode credentials_mode,
+ const base::Optional<std::string>& allow_methods_header,
+ const base::Optional<std::string>& allow_headers_header,
+ const base::Optional<std::string>& max_age_header,
+ base::Optional<mojom::CORSError>* detected_error) {
+ std::unique_ptr<PreflightResult> result =
+ base::WrapUnique(new PreflightResult(credentials_mode));
+ base::Optional<mojom::CORSError> error =
+ result->Parse(allow_methods_header, allow_headers_header, max_age_header);
+ if (error) {
+ if (detected_error)
+ *detected_error = error;
+ return nullptr;
+ }
+ return result;
+}
+
+PreflightResult::PreflightResult(
+ const mojom::FetchCredentialsMode credentials_mode)
+ : credentials_(credentials_mode == mojom::FetchCredentialsMode::kInclude) {}
+
+PreflightResult::~PreflightResult() = default;
+
+base::Optional<mojom::CORSError>
+PreflightResult::EnsureAllowedCrossOriginMethod(
+ const std::string& method) const {
+ // Request method is normalized to upper case, and comparison is performed in
+ // case-sensitive way, that means access control header should provide an
+ // upper case method list.
+ const std::string normalized_method = base::ToUpperASCII(method);
+ if (methods_.find(normalized_method) != methods_.end() ||
+ IsCORSSafelistedMethod(normalized_method)) {
+ return base::nullopt;
+ }
+
+ if (!credentials_ && methods_.find("*") != methods_.end())
+ return base::nullopt;
+
+ return mojom::CORSError::kMethodDisallowedByPreflightResponse;
+}
+
+base::Optional<mojom::CORSError>
+PreflightResult::EnsureAllowedCrossOriginHeaders(
+ const net::HttpRequestHeaders& headers,
+ std::string* detected_header) const {
+ if (!credentials_ && headers_.find("*") != headers_.end())
+ return base::nullopt;
+
+ for (const auto& header : headers.GetHeaderVector()) {
+ // Header list check is performed in case-insensitive way. Here, we have a
+ // parsed header list set in lower case, and search each header in lower
+ // case.
+ const std::string key = base::ToLowerASCII(header.key);
+ if (headers_.find(key) == headers_.end() &&
+ !IsCORSSafelistedHeader(key, header.value)) {
+ // Forbidden headers are forbidden to be used by JavaScript, and checked
+ // beforehand. But user-agents may add these headers internally, and it's
+ // fine.
+ if (IsForbiddenHeader(key))
+ continue;
+ if (detected_header)
+ *detected_header = header.key;
+ return mojom::CORSError::kHeaderDisallowedByPreflightResponse;
+ }
+ }
+ return base::nullopt;
+}
+
+bool PreflightResult::EnsureAllowedRequest(
+ mojom::FetchCredentialsMode credentials_mode,
+ const std::string& method,
+ const net::HttpRequestHeaders& headers) const {
+ if (absolute_expiry_time_ <= Now())
+ return false;
+
+ if (!credentials_ &&
+ credentials_mode == mojom::FetchCredentialsMode::kInclude) {
+ return false;
+ }
+
+ if (EnsureAllowedCrossOriginMethod(method))
+ return false;
+
+ if (EnsureAllowedCrossOriginHeaders(headers, nullptr))
+ return false;
+
+ return true;
+}
+
+base::Optional<mojom::CORSError> PreflightResult::Parse(
+ const base::Optional<std::string>& allow_methods_header,
+ const base::Optional<std::string>& allow_headers_header,
+ const base::Optional<std::string>& max_age_header) {
+ DCHECK(methods_.empty());
+ DCHECK(headers_.empty());
+
+ // Keeps parsed method case for case-sensitive search.
+ if (!ParseAccessControlAllowList(allow_methods_header, &methods_, false))
+ return mojom::CORSError::kInvalidAllowMethodsPreflightResponse;
+
+ // Holds parsed headers in lower case for case-insensitive search.
+ if (!ParseAccessControlAllowList(allow_headers_header, &headers_, true))
+ return mojom::CORSError::kInvalidAllowHeadersPreflightResponse;
+
+ base::TimeDelta expiry_delta;
+ if (max_age_header) {
+ // Set expiry_delta to 0 on invalid Access-Control-Max-Age headers so to
+ // invalidate the entry immediately. CORS-preflight response should be still
+ // usable for the request that initiates the CORS-preflight.
+ if (!ParseAccessControlMaxAge(max_age_header, &expiry_delta))
+ expiry_delta = base::TimeDelta();
+ } else {
+ expiry_delta = kDefaultTimeout;
+ }
+ absolute_expiry_time_ = Now() + expiry_delta;
+
+ return base::nullopt;
+}
+
+} // namespace cors
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/cors/preflight_result.h b/chromium/services/network/public/cpp/cors/preflight_result.h
new file mode 100644
index 00000000000..52b30fdf1a2
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/preflight_result.h
@@ -0,0 +1,100 @@
+// Copyright 2018 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 SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_RESULT_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_RESULT_H_
+
+#include <memory>
+#include <string>
+
+#include "base/component_export.h"
+#include "base/containers/flat_set.h"
+#include "base/optional.h"
+#include "services/network/public/mojom/cors.mojom-shared.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+
+namespace base {
+class TickClock;
+} // namespace base
+
+namespace net {
+class HttpRequestHeaders;
+} // namespace net
+
+namespace network {
+
+namespace cors {
+
+// Holds CORS-preflight request results, and provides access check methods.
+// Each instance can be cached by CORS-preflight cache.
+// See https://fetch.spec.whatwg.org/#concept-cache.
+class COMPONENT_EXPORT(NETWORK_CPP) PreflightResult final {
+ public:
+ static void SetTickClockForTesting(base::TickClock* tick_clock);
+
+ // Creates a PreflightResult instance from a CORS-preflight result. Returns
+ // nullptr and |detected_error| is populated with the failed reason if the
+ // passed parameters contain an invalid entry, and the pointer is valid.
+ static std::unique_ptr<PreflightResult> Create(
+ const mojom::FetchCredentialsMode credentials_mode,
+ const base::Optional<std::string>& allow_methods_header,
+ const base::Optional<std::string>& allow_headers_header,
+ const base::Optional<std::string>& max_age_header,
+ base::Optional<mojom::CORSError>* detected_error);
+ ~PreflightResult();
+
+ // Checks if the given |method| is allowed by the CORS-preflight response.
+ base::Optional<mojom::CORSError> EnsureAllowedCrossOriginMethod(
+ const std::string& method) const;
+
+ // Checks if the given all |headers| are allowed by the CORS-preflight
+ // response. |detected_header| indicates the disallowed header name if the
+ // pointer is valid.
+ // This does not reject when the headers contain forbidden headers
+ // (https://fetch.spec.whatwg.org/#forbidden-header-name) because they may be
+ // added by the user agent. They must be checked separately and rejected for
+ // JavaScript-initiated requests.
+ base::Optional<mojom::CORSError> EnsureAllowedCrossOriginHeaders(
+ const net::HttpRequestHeaders& headers,
+ std::string* detected_header) const;
+
+ // Checks if the given combination of |credentials_mode|, |method|, and
+ // |headers| is allowed by the CORS-preflight response.
+ // This also does not reject the forbidden headers as
+ // EnsureAllowCrossOriginHeaders does not.
+ bool EnsureAllowedRequest(mojom::FetchCredentialsMode credentials_mode,
+ const std::string& method,
+ const net::HttpRequestHeaders& headers) const;
+
+ // Refers the cache expiry time.
+ base::TimeTicks absolute_expiry_time() const { return absolute_expiry_time_; }
+
+ protected:
+ explicit PreflightResult(const mojom::FetchCredentialsMode credentials_mode);
+
+ base::Optional<mojom::CORSError> Parse(
+ const base::Optional<std::string>& allow_methods_header,
+ const base::Optional<std::string>& allow_headers_header,
+ const base::Optional<std::string>& max_age_header);
+
+ private:
+ // Holds an absolute time when the result should be expired in the
+ // CORS-preflight cache.
+ base::TimeTicks absolute_expiry_time_;
+
+ // Corresponds to the fields of the CORS-preflight cache with the same name in
+ // the fetch spec.
+ // |headers_| holds strings in lower case for case-insensitive search.
+ bool credentials_;
+ base::flat_set<std::string> methods_;
+ base::flat_set<std::string> headers_;
+
+ DISALLOW_COPY_AND_ASSIGN(PreflightResult);
+};
+
+} // namespace cors
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_CORS_PREFLIGHT_RESULT_H_
diff --git a/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc b/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc
new file mode 100644
index 00000000000..a0395df3aab
--- /dev/null
+++ b/chromium/services/network/public/cpp/cors/preflight_result_unittest.cc
@@ -0,0 +1,245 @@
+// Copyright 2018 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/network/public/cpp/cors/preflight_result.h"
+
+#include "base/test/simple_test_tick_clock.h"
+#include "base/time/time.h"
+#include "net/http/http_request_headers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace cors {
+
+namespace {
+
+using PreflightResultTest = ::testing::Test;
+
+struct TestCase {
+ const std::string allow_methods;
+ const std::string allow_headers;
+ const mojom::FetchCredentialsMode cache_credentials_mode;
+
+ const std::string request_method;
+ const std::string request_headers;
+ const mojom::FetchCredentialsMode request_credentials_mode;
+
+ const base::Optional<mojom::CORSError> expected_result;
+};
+
+const TestCase method_cases[] = {
+ // Found in the preflight response.
+ {"OPTIONS", "", mojom::FetchCredentialsMode::kOmit, "OPTIONS", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"GET", "", mojom::FetchCredentialsMode::kOmit, "GET", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"HEAD", "", mojom::FetchCredentialsMode::kOmit, "HEAD", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"POST", "", mojom::FetchCredentialsMode::kOmit, "POST", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"PUT", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"DELETE", "", mojom::FetchCredentialsMode::kOmit, "DELETE", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+
+ // Found in the safe list.
+ {"", "", mojom::FetchCredentialsMode::kOmit, "GET", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"", "", mojom::FetchCredentialsMode::kOmit, "HEAD", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"", "", mojom::FetchCredentialsMode::kOmit, "POST", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+
+ // By '*'.
+ {"*", "", mojom::FetchCredentialsMode::kOmit, "OPTIONS", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+
+ // Cache allowing multiple methods.
+ {"GET, PUT, DELETE", "", mojom::FetchCredentialsMode::kOmit, "GET", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"GET, PUT, DELETE", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"GET, PUT, DELETE", "", mojom::FetchCredentialsMode::kOmit, "DELETE", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+
+ // Not found in the preflight response and the safe lit.
+ {"", "", mojom::FetchCredentialsMode::kOmit, "OPTIONS", "",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kMethodDisallowedByPreflightResponse},
+ {"", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kMethodDisallowedByPreflightResponse},
+ {"", "", mojom::FetchCredentialsMode::kOmit, "DELETE", "",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kMethodDisallowedByPreflightResponse},
+ {"GET", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kMethodDisallowedByPreflightResponse},
+ {"GET, POST, DELETE", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kMethodDisallowedByPreflightResponse},
+
+ // Request method is normalized to upper-case, but allowed methods is not.
+ // Comparison is in case-sensitive, that means allowed methods should be in
+ // upper case.
+ {"put", "", mojom::FetchCredentialsMode::kOmit, "PUT", "",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kMethodDisallowedByPreflightResponse},
+ {"put", "", mojom::FetchCredentialsMode::kOmit, "put", "",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kMethodDisallowedByPreflightResponse},
+ {"PUT", "", mojom::FetchCredentialsMode::kOmit, "put", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ // ... But, GET is always allowed by the safe list.
+ {"get", "", mojom::FetchCredentialsMode::kOmit, "GET", "",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+};
+
+const TestCase header_cases[] = {
+ // Found in the preflight response.
+ {"GET", "X-MY-HEADER", mojom::FetchCredentialsMode::kOmit, "GET",
+ "X-MY-HEADER:t", mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"GET", "X-MY-HEADER, Y-MY-HEADER", mojom::FetchCredentialsMode::kOmit,
+ "GET", "X-MY-HEADER:t\r\nY-MY-HEADER:t",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"GET", "x-my-header, Y-MY-HEADER", mojom::FetchCredentialsMode::kOmit,
+ "GET", "X-MY-HEADER:t\r\ny-my-header:t",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+
+ // Found in the safe list.
+ {"GET", "", mojom::FetchCredentialsMode::kOmit, "GET", "Accept:*/*",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+
+ // By '*'.
+ {"GET", "*", mojom::FetchCredentialsMode::kOmit, "GET", "xyzzy:t",
+ mojom::FetchCredentialsMode::kOmit, base::nullopt},
+ {"GET", "*", mojom::FetchCredentialsMode::kInclude, "GET", "xyzzy:t",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kHeaderDisallowedByPreflightResponse},
+
+ // Forbidden headers can pass.
+ {"GET", "", mojom::FetchCredentialsMode::kOmit, "GET",
+ "Host: www.google.com", mojom::FetchCredentialsMode::kOmit, base::nullopt},
+
+ // Not found in the preflight response and the safe list.
+ {"GET", "", mojom::FetchCredentialsMode::kOmit, "GET", "X-MY-HEADER:t",
+ mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kHeaderDisallowedByPreflightResponse},
+ {"GET", "X-SOME-OTHER-HEADER", mojom::FetchCredentialsMode::kOmit, "GET",
+ "X-MY-HEADER:t", mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kHeaderDisallowedByPreflightResponse},
+ {"GET", "X-MY-HEADER", mojom::FetchCredentialsMode::kOmit, "GET",
+ "X-MY-HEADER:t\r\nY-MY-HEADER:t", mojom::FetchCredentialsMode::kOmit,
+ mojom::CORSError::kHeaderDisallowedByPreflightResponse},
+};
+
+TEST_F(PreflightResultTest, MaxAge) {
+ std::unique_ptr<base::SimpleTestTickClock> tick_clock =
+ std::make_unique<base::SimpleTestTickClock>();
+ PreflightResult::SetTickClockForTesting(tick_clock.get());
+
+ std::unique_ptr<PreflightResult> result1 =
+ PreflightResult::Create(mojom::FetchCredentialsMode::kOmit, base::nullopt,
+ base::nullopt, std::string("573"), nullptr);
+ EXPECT_EQ(base::TimeTicks() + base::TimeDelta::FromSeconds(573),
+ result1->absolute_expiry_time());
+
+ // Negative values are invalid. The preflight result itself can be usable, but
+ // should not cache such results. PreflightResult expresses it as a result
+ // with 'Access-Control-Max-Age: 0'.
+ std::unique_ptr<PreflightResult> result2 =
+ PreflightResult::Create(mojom::FetchCredentialsMode::kOmit, base::nullopt,
+ base::nullopt, std::string("-765"), nullptr);
+ EXPECT_EQ(base::TimeTicks(), result2->absolute_expiry_time());
+
+ PreflightResult::SetTickClockForTesting(nullptr);
+};
+
+TEST_F(PreflightResultTest, EnsureMethods) {
+ for (const auto& test : method_cases) {
+ std::unique_ptr<PreflightResult> result =
+ PreflightResult::Create(test.cache_credentials_mode, test.allow_methods,
+ test.allow_headers, base::nullopt, nullptr);
+ ASSERT_TRUE(result);
+ EXPECT_EQ(test.expected_result,
+ result->EnsureAllowedCrossOriginMethod(test.request_method));
+ }
+}
+
+TEST_F(PreflightResultTest, EnsureHeaders) {
+ for (const auto& test : header_cases) {
+ std::unique_ptr<PreflightResult> result =
+ PreflightResult::Create(test.cache_credentials_mode, test.allow_methods,
+ test.allow_headers, base::nullopt, nullptr);
+ ASSERT_TRUE(result);
+ net::HttpRequestHeaders headers;
+ headers.AddHeadersFromString(test.request_headers);
+ EXPECT_EQ(test.expected_result,
+ result->EnsureAllowedCrossOriginHeaders(headers, nullptr));
+ }
+}
+
+TEST_F(PreflightResultTest, EnsureRequest) {
+ for (const auto& test : method_cases) {
+ std::unique_ptr<PreflightResult> result =
+ PreflightResult::Create(test.cache_credentials_mode, test.allow_methods,
+ test.allow_headers, base::nullopt, nullptr);
+ ASSERT_TRUE(result);
+ net::HttpRequestHeaders headers;
+ if (!test.request_headers.empty())
+ headers.AddHeadersFromString(test.request_headers);
+ EXPECT_EQ(test.expected_result == base::nullopt,
+ result->EnsureAllowedRequest(test.request_credentials_mode,
+ test.request_method, headers));
+ }
+
+ for (const auto& test : header_cases) {
+ std::unique_ptr<PreflightResult> result =
+ PreflightResult::Create(test.cache_credentials_mode, test.allow_methods,
+ test.allow_headers, base::nullopt, nullptr);
+ ASSERT_TRUE(result);
+ net::HttpRequestHeaders headers;
+ if (!test.request_headers.empty())
+ headers.AddHeadersFromString(test.request_headers);
+ EXPECT_EQ(test.expected_result == base::nullopt,
+ result->EnsureAllowedRequest(test.request_credentials_mode,
+ test.request_method, headers));
+ }
+
+ struct {
+ const mojom::FetchCredentialsMode cache_credentials_mode;
+ const mojom::FetchCredentialsMode request_credentials_mode;
+ const bool expected_result;
+ } credentials_cases[] = {
+ // Different credential modes.
+ {mojom::FetchCredentialsMode::kInclude,
+ mojom::FetchCredentialsMode::kOmit, true},
+ {mojom::FetchCredentialsMode::kInclude,
+ mojom::FetchCredentialsMode::kInclude, true},
+
+ // Credential mode mismatch.
+ {mojom::FetchCredentialsMode::kOmit, mojom::FetchCredentialsMode::kOmit,
+ true},
+ {mojom::FetchCredentialsMode::kOmit,
+ mojom::FetchCredentialsMode::kInclude, false},
+ };
+
+ for (const auto& test : credentials_cases) {
+ std::unique_ptr<PreflightResult> result =
+ PreflightResult::Create(test.cache_credentials_mode, std::string("GET"),
+ base::nullopt, base::nullopt, nullptr);
+ ASSERT_TRUE(result);
+ net::HttpRequestHeaders headers;
+ EXPECT_EQ(test.expected_result,
+ result->EnsureAllowedRequest(test.request_credentials_mode, "GET",
+ headers));
+ }
+}
+
+} // namespace
+
+} // namespace cors
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/cors_error_status.typemap b/chromium/services/network/public/cpp/cors_error_status.typemap
index efda7cda3ad..235ccc9c0f5 100644
--- a/chromium/services/network/public/cpp/cors_error_status.typemap
+++ b/chromium/services/network/public/cpp/cors_error_status.typemap
@@ -2,13 +2,13 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/url_loader.mojom"
+mojom = "//services/network/public/mojom/url_loader.mojom"
public_headers = [ "//services/network/public/cpp/cors/cors_error_status.h" ]
traits_headers = [ "//services/network/public/cpp/network_param_ipc_traits.h" ]
deps = [
"//net",
]
public_deps = [
- "//services/network/public/cpp:typemap_dependencies",
+ "//services/network/public/cpp:cpp_base",
]
type_mappings = [ "network.mojom.CORSErrorStatus=network::CORSErrorStatus" ]
diff --git a/chromium/services/network/public/cpp/data_element.cc b/chromium/services/network/public/cpp/data_element.cc
index cdec1cfd291..a9e8ba2f1cd 100644
--- a/chromium/services/network/public/cpp/data_element.cc
+++ b/chromium/services/network/public/cpp/data_element.cc
@@ -13,6 +13,8 @@
namespace network {
+const uint64_t DataElement::kUnknownSize;
+
DataElement::DataElement()
: type_(TYPE_UNKNOWN),
bytes_(NULL),
@@ -58,24 +60,6 @@ void DataElement::SetToBlobRange(const std::string& blob_uuid,
length_ = length;
}
-void DataElement::SetToFileSystemUrlRange(
- const GURL& filesystem_url,
- uint64_t offset,
- uint64_t length,
- const base::Time& expected_modification_time) {
- type_ = TYPE_FILE_FILESYSTEM;
- filesystem_url_ = filesystem_url;
- offset_ = offset;
- length_ = length;
- expected_modification_time_ = expected_modification_time;
-}
-
-void DataElement::SetToDiskCacheEntryRange(uint64_t offset, uint64_t length) {
- type_ = TYPE_DISK_CACHE_ENTRY;
- offset_ = offset;
- length_ = length;
-}
-
void DataElement::SetToDataPipe(mojom::DataPipeGetterPtr data_pipe_getter) {
type_ = TYPE_DATA_PIPE;
data_pipe_getter_ = std::move(data_pipe_getter);
@@ -114,15 +98,6 @@ void PrintTo(const DataElement& x, std::ostream* os) {
case DataElement::TYPE_BLOB:
*os << "TYPE_BLOB, uuid: " << x.blob_uuid();
break;
- case DataElement::TYPE_FILE_FILESYSTEM:
- *os << "TYPE_FILE_FILESYSTEM, filesystem_url: " << x.filesystem_url();
- break;
- case DataElement::TYPE_DISK_CACHE_ENTRY:
- *os << "TYPE_DISK_CACHE_ENTRY";
- break;
- case DataElement::TYPE_BYTES_DESCRIPTION:
- *os << "TYPE_BYTES_DESCRIPTION";
- break;
case DataElement::TYPE_DATA_PIPE:
*os << "TYPE_DATA_PIPE";
break;
@@ -148,14 +123,6 @@ bool operator==(const DataElement& a, const DataElement& b) {
a.expected_modification_time() == b.expected_modification_time();
case DataElement::TYPE_BLOB:
return a.blob_uuid() == b.blob_uuid();
- case DataElement::TYPE_FILE_FILESYSTEM:
- return a.filesystem_url() == b.filesystem_url();
- case DataElement::TYPE_DISK_CACHE_ENTRY:
- // We compare only length and offset; we trust the entry itself was
- // compared at some higher level such as in BlobDataItem.
- return true;
- case DataElement::TYPE_BYTES_DESCRIPTION:
- return true;
case DataElement::TYPE_DATA_PIPE:
return false;
case DataElement::TYPE_UNKNOWN:
diff --git a/chromium/services/network/public/cpp/data_element.h b/chromium/services/network/public/cpp/data_element.h
index 4dbfa5e919f..6dcd9b43467 100644
--- a/chromium/services/network/public/cpp/data_element.h
+++ b/chromium/services/network/public/cpp/data_element.h
@@ -14,20 +14,21 @@
#include <string>
#include <vector>
+#include "base/component_export.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "mojo/public/cpp/system/data_pipe.h"
-#include "services/network/public/interfaces/data_pipe_getter.mojom.h"
+#include "services/network/public/mojom/data_pipe_getter.mojom.h"
#include "url/gurl.h"
namespace network {
// Represents a base Web data element. This could be either one of
// bytes, file or blob data.
-class DataElement {
+class COMPONENT_EXPORT(NETWORK_CPP_BASE) DataElement {
public:
static const uint64_t kUnknownSize = std::numeric_limits<uint64_t>::max();
@@ -38,14 +39,8 @@ class DataElement {
TYPE_DATA_PIPE,
TYPE_RAW_FILE,
- // Only used for Blob:
- TYPE_BYTES_DESCRIPTION,
- TYPE_DISK_CACHE_ENTRY, // Only used by CacheStorage
- TYPE_FILE_FILESYSTEM,
-
- // Commonly used for Blob, and also for Upload when Network Service is
- // disabled:
- TYPE_BLOB, // Used old IPC codepath only.
+ // Used for Upload when Network Service is disabled:
+ TYPE_BLOB,
TYPE_FILE,
// Commonly used in every case:
@@ -64,7 +59,6 @@ class DataElement {
const char* bytes() const { return bytes_ ? bytes_ : buf_.data(); }
const base::FilePath& path() const { return path_; }
const base::File& file() const { return file_; }
- const GURL& filesystem_url() const { return filesystem_url_; }
const std::string& blob_uuid() const { return blob_uuid_; }
const mojom::DataPipeGetterPtr& data_pipe() const {
return data_pipe_getter_;
@@ -106,12 +100,6 @@ class DataElement {
length_ = buf_.size();
}
- void SetToBytesDescription(size_t bytes_len) {
- type_ = TYPE_BYTES_DESCRIPTION;
- bytes_ = nullptr;
- length_ = bytes_len;
- }
-
// Sets TYPE_BYTES data. This does NOT copy the given data and the caller
// should make sure the data is alive when this element is accessed.
// You cannot use AppendBytes with this method.
@@ -163,15 +151,6 @@ class DataElement {
uint64_t offset,
uint64_t length);
- // Sets TYPE_FILE_FILESYSTEM with range.
- void SetToFileSystemUrlRange(const GURL& filesystem_url,
- uint64_t offset,
- uint64_t length,
- const base::Time& expected_modification_time);
-
- // Sets to TYPE_DISK_CACHE_ENTRY with range.
- void SetToDiskCacheEntryRange(uint64_t offset, uint64_t length);
-
// Sets TYPE_DATA_PIPE data.
void SetToDataPipe(mojom::DataPipeGetterPtr data_pipe_getter);
@@ -190,7 +169,6 @@ class DataElement {
const char* bytes_; // For TYPE_BYTES.
base::FilePath path_; // For TYPE_FILE and TYPE_RAW_FILE.
base::File file_; // For TYPE_RAW_FILE.
- GURL filesystem_url_; // For TYPE_FILE_FILESYSTEM.
std::string blob_uuid_; // For TYPE_BLOB.
mojom::DataPipeGetterPtr data_pipe_getter_; // For TYPE_DATA_PIPE.
uint64_t offset_;
@@ -198,7 +176,9 @@ class DataElement {
base::Time expected_modification_time_;
};
+COMPONENT_EXPORT(NETWORK_CPP_BASE)
bool operator==(const DataElement& a, const DataElement& b);
+COMPONENT_EXPORT(NETWORK_CPP_BASE)
bool operator!=(const DataElement& a, const DataElement& b);
} // namespace network
diff --git a/chromium/services/network/public/cpp/features.cc b/chromium/services/network/public/cpp/features.cc
new file mode 100644
index 00000000000..fbfa6aeffcb
--- /dev/null
+++ b/chromium/services/network/public/cpp/features.cc
@@ -0,0 +1,27 @@
+// Copyright 2018 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/network/public/cpp/features.h"
+
+namespace network {
+namespace features {
+
+const base::Feature kNetworkErrorLogging{"NetworkErrorLogging",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+// Enables the network service.
+const base::Feature kNetworkService{"NetworkService",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Out of Blink CORS
+const base::Feature kOutOfBlinkCORS{"OutOfBlinkCORS",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Port some content::ResourceScheduler functionalities to renderer.
+const base::Feature kRendererSideResourceScheduler{
+ "RendererSideResourceScheduler", base::FEATURE_DISABLED_BY_DEFAULT};
+
+const base::Feature kReporting{"Reporting", base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace features
+} // namespace network
diff --git a/chromium/services/network/public/cpp/features.h b/chromium/services/network/public/cpp/features.h
new file mode 100644
index 00000000000..718b6eaabb2
--- /dev/null
+++ b/chromium/services/network/public/cpp/features.h
@@ -0,0 +1,28 @@
+// Copyright 2018 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 SERVICES_NETWORK_PUBLIC_CPP_FEATURES_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_FEATURES_H_
+
+#include "base/component_export.h"
+#include "base/feature_list.h"
+
+namespace network {
+namespace features {
+
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kNetworkErrorLogging;
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kNetworkService;
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kOutOfBlinkCORS;
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kRendererSideResourceScheduler;
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const base::Feature kReporting;
+
+} // namespace features
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_FEATURES_H_
diff --git a/chromium/services/network/public/cpp/http_raw_request_response_info.h b/chromium/services/network/public/cpp/http_raw_request_response_info.h
index 7a78e2e5432..0a313473d26 100644
--- a/chromium/services/network/public/cpp/http_raw_request_response_info.h
+++ b/chromium/services/network/public/cpp/http_raw_request_response_info.h
@@ -10,6 +10,7 @@
#include <string>
#include <vector>
+#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "base/strings/string_split.h"
@@ -17,9 +18,9 @@ namespace network {
// Note: when modifying this structure, also update DeepCopy in
// http_raw_request_response_info.cc.
-struct HttpRawRequestResponseInfo
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) HttpRawRequestResponseInfo
: base::RefCounted<HttpRawRequestResponseInfo> {
- typedef base::StringPairs HeadersVector;
+ using HeadersVector = base::StringPairs;
HttpRawRequestResponseInfo();
diff --git a/chromium/services/network/public/cpp/http_request_headers.typemap b/chromium/services/network/public/cpp/http_request_headers.typemap
index ada2ad3000d..e82dc584ed1 100644
--- a/chromium/services/network/public/cpp/http_request_headers.typemap
+++ b/chromium/services/network/public/cpp/http_request_headers.typemap
@@ -2,15 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/http_request_headers.mojom"
+mojom = "//services/network/public/mojom/http_request_headers.mojom"
public_headers = [
"//net/http/http_request_headers.h",
- "//services/network/public/cpp/http_request_headers_struct_traits.h",
+ "//services/network/public/cpp/http_request_headers_mojom_traits.h",
]
traits_headers =
- [ "//services/network/public/cpp/http_request_headers_struct_traits.h" ]
+ [ "//services/network/public/cpp/http_request_headers_mojom_traits.h" ]
sources = [
- "//services/network/public/cpp/http_request_headers_struct_traits.cc",
+ "//services/network/public/cpp/http_request_headers_mojom_traits.cc",
]
public_deps = [
"//net",
diff --git a/chromium/services/network/public/cpp/http_request_headers_struct_traits.cc b/chromium/services/network/public/cpp/http_request_headers_mojom_traits.cc
index 5debd751aa9..d6b2987bcc2 100644
--- a/chromium/services/network/public/cpp/http_request_headers_struct_traits.cc
+++ b/chromium/services/network/public/cpp/http_request_headers_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/http_request_headers_struct_traits.h"
+#include "services/network/public/cpp/http_request_headers_mojom_traits.h"
#include "net/http/http_util.h"
diff --git a/chromium/services/network/public/cpp/http_request_headers_struct_traits.h b/chromium/services/network/public/cpp/http_request_headers_mojom_traits.h
index 07b17356c3f..a565914574e 100644
--- a/chromium/services/network/public/cpp/http_request_headers_struct_traits.h
+++ b/chromium/services/network/public/cpp/http_request_headers_mojom_traits.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_STRUCT_TRAITS_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_STRUCT_TRAITS_H_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_MOJOM_TRAITS_H_
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "net/http/http_request_headers.h"
-#include "services/network/public/interfaces/http_request_headers.mojom.h"
+#include "services/network/public/mojom/http_request_headers.mojom.h"
namespace mojo {
@@ -39,4 +39,4 @@ struct StructTraits<network::mojom::HttpRequestHeadersDataView,
} // namespace mojo
-#endif // SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_STRUCT_TRAITS_H_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_HTTP_REQUEST_HEADERS_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag.typemap b/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag.typemap
index 3b72b6549a3..5752893d6dc 100644
--- a/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag.typemap
+++ b/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag.typemap
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/mutable_network_traffic_annotation_tag.mojom"
+mojom = "//services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom"
public_headers = [ "//net/traffic_annotation/network_traffic_annotation.h" ]
traits_headers = [ "//services/network/public/cpp/" +
- "mutable_network_traffic_annotation_tag_struct_traits.h" ]
+ "mutable_network_traffic_annotation_tag_mojom_traits.h" ]
deps = [
"//net:traffic_annotation",
]
diff --git a/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_struct_traits.h b/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_mojom_traits.h
index c6c36bb6fc7..848601fc371 100644
--- a/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_struct_traits.h
+++ b/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_mojom_traits.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_NETWORK_TRAFFIC_ANNOTATION_TAG_STRUCT_TRAITS_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_NETWORK_TRAFFIC_ANNOTATION_TAG_STRUCT_TRAITS_H_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_NETWORK_TRAFFIC_ANNOTATION_TAG_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_NETWORK_TRAFFIC_ANNOTATION_TAG_MOJOM_TRAITS_H_
#include "mojo/common/common_custom_types_struct_traits.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/interfaces/mutable_network_traffic_annotation_tag.mojom.h"
+#include "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom.h"
namespace mojo {
@@ -28,4 +28,4 @@ struct StructTraits<network::mojom::MutableNetworkTrafficAnnotationTagDataView,
} // namespace mojo
-#endif // SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_NETWORK_TRAFFIC_ANNOTATION_TAG_STRUCT_TRAITS_H_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_NETWORK_TRAFFIC_ANNOTATION_TAG_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_struct_traits_unittest.cc b/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_mojom_traits_unittest.cc
index ac5a6293919..001af6acf61 100644
--- a/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_struct_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/mutable_network_traffic_annotation_tag_mojom_traits_unittest.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/mutable_network_traffic_annotation_tag_struct_traits.h"
+#include "services/network/public/cpp/mutable_network_traffic_annotation_tag_mojom_traits.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/network/public/interfaces/mutable_network_traffic_annotation_tag.mojom.h"
+#include "services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
diff --git a/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag.typemap b/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag.typemap
index d1a3154f57a..0a8f6176d1c 100644
--- a/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag.typemap
+++ b/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag.typemap
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/mutable_partial_network_traffic_annotation_tag.mojom"
+mojom = "//services/network/public/mojom/mutable_partial_network_traffic_annotation_tag.mojom"
public_headers = [ "//net/traffic_annotation/network_traffic_annotation.h" ]
traits_headers =
[ "//services/network/public/cpp/" +
- "mutable_partial_network_traffic_annotation_tag_struct_traits.h" ]
+ "mutable_partial_network_traffic_annotation_tag_mojom_traits.h" ]
deps = [
"//net:traffic_annotation",
]
diff --git a/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_struct_traits.h b/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_mojom_traits.h
index 09a552c0b99..96d144e1f11 100644
--- a/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_struct_traits.h
+++ b/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_mojom_traits.h
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_PARTIAL_NETWORK_TRAFFIC_ANNOTATION_TAG_STRUCT_TRAITS_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_PARTIAL_NETWORK_TRAFFIC_ANNOTATION_TAG_STRUCT_TRAITS_H_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_PARTIAL_NETWORK_TRAFFIC_ANNOTATION_TAG_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_PARTIAL_NETWORK_TRAFFIC_ANNOTATION_TAG_MOJOM_TRAITS_H_
#include "mojo/common/common_custom_types_struct_traits.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/interfaces/mutable_partial_network_traffic_annotation_tag.mojom.h"
+#include "services/network/public/mojom/mutable_partial_network_traffic_annotation_tag.mojom.h"
namespace mojo {
@@ -42,4 +42,4 @@ struct StructTraits<
} // namespace mojo
-#endif // SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_PARTIAL_NETWORK_TRAFFIC_ANNOTATION_TAG_STRUCT_TRAITS_H_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_MUTABLE_PARTIAL_NETWORK_TRAFFIC_ANNOTATION_TAG_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_struct_traits_unittest.cc b/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_mojom_traits_unittest.cc
index 096ed718fc7..1201a37df58 100644
--- a/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_struct_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_mojom_traits_unittest.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_struct_traits.h"
+#include "services/network/public/cpp/mutable_partial_network_traffic_annotation_tag_mojom_traits.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/network/public/interfaces/mutable_partial_network_traffic_annotation_tag.mojom.h"
+#include "services/network/public/mojom/mutable_partial_network_traffic_annotation_tag.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace network {
diff --git a/chromium/services/network/public/cpp/net_adapters.h b/chromium/services/network/public/cpp/net_adapters.h
index 1008a6432eb..cb19f83e865 100644
--- a/chromium/services/network/public/cpp/net_adapters.h
+++ b/chromium/services/network/public/cpp/net_adapters.h
@@ -2,11 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_NET_ADAPTERS_
-#define SERVICES_NETWORK_PUBLIC_CPP_NET_ADAPTERS_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_NET_ADAPTERS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_NET_ADAPTERS_H_
#include <stdint.h>
+#include "base/component_export.h"
#include "base/macros.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/io_buffer.h"
@@ -25,7 +26,7 @@ namespace network {
// of the Mojo pipe, which in turn is kept alive by the IOBuffer. This allows
// the request to potentially outlive the object managing the translation.
// Mojo side of a Net -> Mojo copy. The buffer is allocated by Mojo.
-class NetToMojoPendingBuffer
+class COMPONENT_EXPORT(NETWORK_CPP) NetToMojoPendingBuffer
: public base::RefCountedThreadSafe<NetToMojoPendingBuffer> {
public:
// Begins a two-phase write to the data pipe.
@@ -58,7 +59,8 @@ class NetToMojoPendingBuffer
// Net side of a Net -> Mojo copy. The data will be read from the network and
// copied into the buffer associated with the pending mojo write.
-class NetToMojoIOBuffer : public net::WrappedIOBuffer {
+class COMPONENT_EXPORT(NETWORK_CPP) NetToMojoIOBuffer
+ : public net::WrappedIOBuffer {
public:
// If |offset| is specified then the memory buffer passed to the Net layer
// will be offset by that many bytes.
@@ -71,7 +73,7 @@ class NetToMojoIOBuffer : public net::WrappedIOBuffer {
DISALLOW_COPY_AND_ASSIGN(NetToMojoIOBuffer);
};
-class MojoToNetPendingBuffer
+class COMPONENT_EXPORT(NETWORK_CPP) MojoToNetPendingBuffer
: public base::RefCountedThreadSafe<MojoToNetPendingBuffer> {
public:
// Starts reading from Mojo.
@@ -117,7 +119,8 @@ class MojoToNetPendingBuffer
// Net side of a Mojo -> Net copy. The data will already be in the
// MojoToNetPendingBuffer's buffer.
-class MojoToNetIOBuffer : public net::WrappedIOBuffer {
+class COMPONENT_EXPORT(NETWORK_CPP) MojoToNetIOBuffer
+ : public net::WrappedIOBuffer {
public:
// |bytes_to_be_read| contains the number of bytes expected to be read by
// the consumer.
@@ -133,4 +136,4 @@ class MojoToNetIOBuffer : public net::WrappedIOBuffer {
} // namespace network
-#endif // SERVICES_NETWORK_PUBLIC_CPP_NET_ADAPTERS_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_NET_ADAPTERS_H_
diff --git a/chromium/services/network/public/cpp/network_struct_traits_unittest.cc b/chromium/services/network/public/cpp/network_mojom_traits_unittest.cc
index 2acaf6c5d36..beef24dc37a 100644
--- a/chromium/services/network/public/cpp/network_struct_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/network_mojom_traits_unittest.cc
@@ -5,7 +5,7 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/string_util.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/network/public/cpp/http_request_headers_struct_traits.h"
+#include "services/network/public/cpp/http_request_headers_mojom_traits.h"
#include "services/network/public/cpp/network_traits_test_service.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/network/public/cpp/network_param.typemap b/chromium/services/network/public/cpp/network_param.typemap
index 6fb311f1274..e674db3716d 100644
--- a/chromium/services/network/public/cpp/network_param.typemap
+++ b/chromium/services/network/public/cpp/network_param.typemap
@@ -2,12 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/url_loader.mojom"
+mojom = "//services/network/public/mojom/url_loader.mojom"
public_headers = [
+ "//net/base/auth.h",
"//net/base/host_port_pair.h",
"//net/cert/cert_verify_result.h",
"//net/cert/x509_certificate.h",
"//net/http/http_request_headers.h",
+ "//net/ssl/ssl_cert_request_info.h",
"//net/ssl/ssl_info.h",
]
traits_headers = [ "//services/network/public/cpp/network_param_ipc_traits.h" ]
@@ -15,8 +17,11 @@ public_deps = [
"//net",
]
type_mappings = [
+ "network.mojom.AuthChallengeInfo=scoped_refptr<net::AuthChallengeInfo>[nullable_is_same_type]",
+ "network.mojom.AuthCredentials=net::AuthCredentials",
"network.mojom.CertVerifyResult=net::CertVerifyResult",
"network.mojom.HostPortPair=net::HostPortPair",
+ "network.mojom.SSLCertRequestInfo=scoped_refptr<net::SSLCertRequestInfo>[nullable_is_same_type]",
"network.mojom.SSLInfo=net::SSLInfo",
"network.mojom.X509Certificate=scoped_refptr<net::X509Certificate>[nullable_is_same_type]",
]
diff --git a/chromium/services/network/public/cpp/network_param_ipc_traits.cc b/chromium/services/network/public/cpp/network_param_ipc_traits.cc
index 12058b01841..36a4c9f2b5e 100644
--- a/chromium/services/network/public/cpp/network_param_ipc_traits.cc
+++ b/chromium/services/network/public/cpp/network_param_ipc_traits.cc
@@ -12,6 +12,67 @@
namespace IPC {
+void ParamTraits<scoped_refptr<net::AuthChallengeInfo>>::Write(
+ base::Pickle* m,
+ const param_type& p) {
+ WriteParam(m, p != nullptr);
+ if (p) {
+ WriteParam(m, p->is_proxy);
+ WriteParam(m, p->challenger);
+ WriteParam(m, p->scheme);
+ WriteParam(m, p->realm);
+ }
+}
+
+bool ParamTraits<scoped_refptr<net::AuthChallengeInfo>>::Read(
+ const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ bool has_object;
+ if (!ReadParam(m, iter, &has_object))
+ return false;
+ if (!has_object) {
+ *r = nullptr;
+ return true;
+ }
+ *r = new net::AuthChallengeInfo();
+ return ReadParam(m, iter, &(*r)->is_proxy) &&
+ ReadParam(m, iter, &(*r)->challenger) &&
+ ReadParam(m, iter, &(*r)->scheme) && ReadParam(m, iter, &(*r)->realm);
+}
+
+void ParamTraits<scoped_refptr<net::AuthChallengeInfo>>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("<AuthChallengeInfo>");
+}
+
+void ParamTraits<net::AuthCredentials>::Write(base::Pickle* m,
+ const param_type& p) {
+ WriteParam(m, p.username());
+ WriteParam(m, p.password());
+}
+
+bool ParamTraits<net::AuthCredentials>::Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ base::string16 username;
+ bool read_username = ReadParam(m, iter, &username);
+ base::string16 password;
+ bool read_password = ReadParam(m, iter, &password);
+
+ if (!read_username || !read_password)
+ return false;
+
+ r->Set(username, password);
+ return true;
+}
+
+void ParamTraits<net::AuthCredentials>::Log(const param_type& p,
+ std::string* l) {
+ l->append("<AuthCredentials>");
+}
+
void ParamTraits<net::CertVerifyResult>::Write(base::Pickle* m,
const param_type& p) {
WriteParam(m, p.verified_cert);
@@ -24,7 +85,6 @@ void ParamTraits<net::CertVerifyResult>::Write(base::Pickle* m,
WriteParam(m, p.public_key_hashes);
WriteParam(m, p.is_issued_by_known_root);
WriteParam(m, p.is_issued_by_additional_trust_anchor);
- WriteParam(m, p.common_name_fallback_used);
WriteParam(m, p.ocsp_result);
}
@@ -39,7 +99,6 @@ bool ParamTraits<net::CertVerifyResult>::Read(const base::Pickle* m,
ReadParam(m, iter, &r->public_key_hashes) &&
ReadParam(m, iter, &r->is_issued_by_known_root) &&
ReadParam(m, iter, &r->is_issued_by_additional_trust_anchor) &&
- ReadParam(m, iter, &r->common_name_fallback_used) &&
ReadParam(m, iter, &r->ocsp_result);
}
@@ -162,6 +221,42 @@ void ParamTraits<net::OCSPVerifyResult>::Log(const param_type& p,
l->append("<OCSPVerifyResult>");
}
+void ParamTraits<scoped_refptr<net::SSLCertRequestInfo>>::Write(
+ base::Pickle* m,
+ const param_type& p) {
+ WriteParam(m, p != nullptr);
+ if (p) {
+ WriteParam(m, p->host_and_port);
+ WriteParam(m, p->is_proxy);
+ WriteParam(m, p->cert_authorities);
+ WriteParam(m, p->cert_key_types);
+ }
+}
+
+bool ParamTraits<scoped_refptr<net::SSLCertRequestInfo>>::Read(
+ const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r) {
+ bool has_object;
+ if (!ReadParam(m, iter, &has_object))
+ return false;
+ if (!has_object) {
+ *r = nullptr;
+ return true;
+ }
+ *r = new net::SSLCertRequestInfo();
+ return ReadParam(m, iter, &(*r)->host_and_port) &&
+ ReadParam(m, iter, &(*r)->is_proxy) &&
+ ReadParam(m, iter, &(*r)->cert_authorities) &&
+ ReadParam(m, iter, &(*r)->cert_key_types);
+}
+
+void ParamTraits<scoped_refptr<net::SSLCertRequestInfo>>::Log(
+ const param_type& p,
+ std::string* l) {
+ l->append("<SSLCertRequestInfo>");
+}
+
void ParamTraits<net::SSLInfo>::Write(base::Pickle* m, const param_type& p) {
WriteParam(m, p.is_valid());
if (!p.is_valid())
@@ -423,10 +518,6 @@ void ParamTraits<network::DataElement>::Write(base::Pickle* m,
m->WriteData(p.bytes(), static_cast<int>(p.length()));
break;
}
- case network::DataElement::TYPE_BYTES_DESCRIPTION: {
- WriteParam(m, p.length());
- break;
- }
case network::DataElement::TYPE_FILE: {
WriteParam(m, p.path());
WriteParam(m, p.offset());
@@ -444,23 +535,12 @@ void ParamTraits<network::DataElement>::Write(base::Pickle* m,
WriteParam(m, p.expected_modification_time());
break;
}
- case network::DataElement::TYPE_FILE_FILESYSTEM: {
- WriteParam(m, p.filesystem_url());
- WriteParam(m, p.offset());
- WriteParam(m, p.length());
- WriteParam(m, p.expected_modification_time());
- break;
- }
case network::DataElement::TYPE_BLOB: {
WriteParam(m, p.blob_uuid());
WriteParam(m, p.offset());
WriteParam(m, p.length());
break;
}
- case network::DataElement::TYPE_DISK_CACHE_ENTRY: {
- NOTREACHED() << "Can't be sent by IPC.";
- break;
- }
case network::DataElement::TYPE_DATA_PIPE: {
WriteParam(m,
const_cast<network::mojom::DataPipeGetterPtr&>(p.data_pipe())
@@ -491,13 +571,6 @@ bool ParamTraits<network::DataElement>::Read(const base::Pickle* m,
r->SetToBytes(data, len);
return true;
}
- case network::DataElement::TYPE_BYTES_DESCRIPTION: {
- uint64_t length;
- if (!ReadParam(m, iter, &length))
- return false;
- r->SetToBytesDescription(length);
- return true;
- }
case network::DataElement::TYPE_FILE: {
base::FilePath file_path;
uint64_t offset, length;
@@ -535,22 +608,6 @@ bool ParamTraits<network::DataElement>::Read(const base::Pickle* m,
expected_modification_time);
return true;
}
- case network::DataElement::TYPE_FILE_FILESYSTEM: {
- GURL file_system_url;
- uint64_t offset, length;
- base::Time expected_modification_time;
- if (!ReadParam(m, iter, &file_system_url))
- return false;
- if (!ReadParam(m, iter, &offset))
- return false;
- if (!ReadParam(m, iter, &length))
- return false;
- if (!ReadParam(m, iter, &expected_modification_time))
- return false;
- r->SetToFileSystemUrlRange(file_system_url, offset, length,
- expected_modification_time);
- return true;
- }
case network::DataElement::TYPE_BLOB: {
std::string blob_uuid;
uint64_t offset, length;
@@ -563,10 +620,6 @@ bool ParamTraits<network::DataElement>::Read(const base::Pickle* m,
r->SetToBlobRange(blob_uuid, offset, length);
return true;
}
- case network::DataElement::TYPE_DISK_CACHE_ENTRY: {
- NOTREACHED() << "Can't be sent by IPC.";
- return false;
- }
case network::DataElement::TYPE_DATA_PIPE: {
network::mojom::DataPipeGetterPtr data_pipe_getter;
mojo::MessagePipeHandle message_pipe;
@@ -637,7 +690,6 @@ void ParamTraits<url::Origin>::Write(base::Pickle* m, const url::Origin& p) {
WriteParam(m, p.scheme());
WriteParam(m, p.host());
WriteParam(m, p.port());
- WriteParam(m, p.suborigin());
}
bool ParamTraits<url::Origin>::Read(const base::Pickle* m,
@@ -647,17 +699,15 @@ bool ParamTraits<url::Origin>::Read(const base::Pickle* m,
std::string scheme;
std::string host;
uint16_t port;
- std::string suborigin;
if (!ReadParam(m, iter, &unique) || !ReadParam(m, iter, &scheme) ||
- !ReadParam(m, iter, &host) || !ReadParam(m, iter, &port) ||
- !ReadParam(m, iter, &suborigin)) {
+ !ReadParam(m, iter, &host) || !ReadParam(m, iter, &port)) {
*p = url::Origin();
return false;
}
*p = unique ? url::Origin()
: url::Origin::UnsafelyCreateOriginWithoutNormalization(
- scheme, host, port, suborigin);
+ scheme, host, port);
// If a unique origin was created, but the unique flag wasn't set, then
// the values provided to 'UnsafelyCreateOriginWithoutNormalization' were
diff --git a/chromium/services/network/public/cpp/network_param_ipc_traits.h b/chromium/services/network/public/cpp/network_param_ipc_traits.h
index 34181bbe834..fad598145bb 100644
--- a/chromium/services/network/public/cpp/network_param_ipc_traits.h
+++ b/chromium/services/network/public/cpp/network_param_ipc_traits.h
@@ -7,17 +7,21 @@
#include <string>
+#include "base/component_export.h"
#include "base/pickle.h"
#include "ipc/ipc_param_traits.h"
#include "ipc/param_traits_macros.h"
+#include "net/base/auth.h"
#include "net/base/host_port_pair.h"
#include "net/base/request_priority.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/ct_policy_status.h"
#include "net/cert/signed_certificate_timestamp.h"
#include "net/cert/signed_certificate_timestamp_and_status.h"
+#include "net/cert/x509_certificate.h"
#include "net/http/http_request_headers.h"
#include "net/nqe/effective_connection_type.h"
+#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_info.h"
#include "net/url_request/redirect_info.h"
#include "services/network/public/cpp/resource_request.h"
@@ -25,22 +29,17 @@
#include "services/network/public/cpp/resource_response.h"
#include "services/network/public/cpp/resource_response_info.h"
#include "services/network/public/cpp/url_loader_completion_status.h"
-#include "services/network/public/interfaces/cors.mojom-shared.h"
-#include "services/network/public/interfaces/fetch_api.mojom-shared.h"
-#include "services/network/public/interfaces/request_context_frame_type.mojom-shared.h"
+#include "services/network/public/mojom/cors.mojom-shared.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+#include "services/network/public/mojom/request_context_frame_type.mojom-shared.h"
#include "url/ipc/url_param_traits.h"
#include "url/origin.h"
#ifndef INTERNAL_SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_IPC_TRAITS_H_
#define INTERNAL_SERVICES_NETWORK_PUBLIC_CPP_NETWORK_PARAM_IPC_TRAITS_H_
-// services/network/public/cpp is currently packaged as a static library,
-// so there's no need for export defines; it's linked directly into whatever
-// other components need it.
-// This redefinition is present for the IPC macros below, including in the
-// included header files.
#undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT COMPONENT_EXPORT(NETWORK_CPP_BASE)
namespace network {
struct HttpRawRequestResponseInfo;
@@ -49,7 +48,28 @@ struct HttpRawRequestResponseInfo;
namespace IPC {
template <>
-struct ParamTraits<net::CertVerifyResult> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ ParamTraits<scoped_refptr<net::AuthChallengeInfo>> {
+ typedef scoped_refptr<net::AuthChallengeInfo> param_type;
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::AuthCredentials> {
+ typedef net::AuthCredentials param_type;
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::CertVerifyResult> {
typedef net::CertVerifyResult param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -59,7 +79,7 @@ struct ParamTraits<net::CertVerifyResult> {
};
template <>
-struct ParamTraits<net::HashValue> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::HashValue> {
typedef net::HashValue param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -69,7 +89,7 @@ struct ParamTraits<net::HashValue> {
};
template <>
-struct ParamTraits<net::HostPortPair> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::HostPortPair> {
typedef net::HostPortPair param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -79,7 +99,7 @@ struct ParamTraits<net::HostPortPair> {
};
template <>
-struct ParamTraits<net::HttpRequestHeaders> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::HttpRequestHeaders> {
typedef net::HttpRequestHeaders param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -89,7 +109,7 @@ struct ParamTraits<net::HttpRequestHeaders> {
};
template <>
-struct ParamTraits<net::OCSPVerifyResult> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::OCSPVerifyResult> {
typedef net::OCSPVerifyResult param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -99,7 +119,18 @@ struct ParamTraits<net::OCSPVerifyResult> {
};
template <>
-struct ParamTraits<net::SSLInfo> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ ParamTraits<scoped_refptr<net::SSLCertRequestInfo>> {
+ typedef scoped_refptr<net::SSLCertRequestInfo> param_type;
+ static void Write(base::Pickle* m, const param_type& p);
+ static bool Read(const base::Pickle* m,
+ base::PickleIterator* iter,
+ param_type* r);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template <>
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::SSLInfo> {
typedef net::SSLInfo param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -109,7 +140,8 @@ struct ParamTraits<net::SSLInfo> {
};
template <>
-struct ParamTraits<scoped_refptr<net::ct::SignedCertificateTimestamp>> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ ParamTraits<scoped_refptr<net::ct::SignedCertificateTimestamp>> {
typedef scoped_refptr<net::ct::SignedCertificateTimestamp> param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -119,7 +151,8 @@ struct ParamTraits<scoped_refptr<net::ct::SignedCertificateTimestamp>> {
};
template <>
-struct ParamTraits<scoped_refptr<network::HttpRawRequestResponseInfo>> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ ParamTraits<scoped_refptr<network::HttpRawRequestResponseInfo>> {
typedef scoped_refptr<network::HttpRawRequestResponseInfo> param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -129,7 +162,8 @@ struct ParamTraits<scoped_refptr<network::HttpRawRequestResponseInfo>> {
};
template <>
-struct ParamTraits<scoped_refptr<net::HttpResponseHeaders>> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ ParamTraits<scoped_refptr<net::HttpResponseHeaders>> {
typedef scoped_refptr<net::HttpResponseHeaders> param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -139,7 +173,8 @@ struct ParamTraits<scoped_refptr<net::HttpResponseHeaders>> {
};
template <>
-struct ParamTraits<scoped_refptr<net::X509Certificate>> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ ParamTraits<scoped_refptr<net::X509Certificate>> {
typedef scoped_refptr<net::X509Certificate> param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -149,7 +184,7 @@ struct ParamTraits<scoped_refptr<net::X509Certificate>> {
};
template <>
-struct ParamTraits<net::LoadTimingInfo> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<net::LoadTimingInfo> {
typedef net::LoadTimingInfo param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -159,7 +194,7 @@ struct ParamTraits<net::LoadTimingInfo> {
};
template <>
-struct ParamTraits<network::DataElement> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<network::DataElement> {
typedef network::DataElement param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -169,7 +204,8 @@ struct ParamTraits<network::DataElement> {
};
template <>
-struct ParamTraits<scoped_refptr<network::ResourceRequestBody>> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ ParamTraits<scoped_refptr<network::ResourceRequestBody>> {
typedef scoped_refptr<network::ResourceRequestBody> param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -179,7 +215,7 @@ struct ParamTraits<scoped_refptr<network::ResourceRequestBody>> {
};
template <>
-struct ParamTraits<url::Origin> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ParamTraits<url::Origin> {
typedef url::Origin param_type;
static void Write(base::Pickle* m, const param_type& p);
static bool Read(const base::Pickle* m,
@@ -202,6 +238,10 @@ IPC_ENUM_TRAITS_MAX_VALUE(net::OCSPRevocationStatus,
IPC_ENUM_TRAITS_MAX_VALUE(net::ct::SCTVerifyStatus, net::ct::SCT_STATUS_MAX)
IPC_ENUM_TRAITS_MAX_VALUE(net::RequestPriority, net::MAXIMUM_PRIORITY)
+
+IPC_ENUM_TRAITS_MAX_VALUE(net::SSLClientCertType,
+ net::SSLClientCertType::CLIENT_CERT_INVALID_TYPE)
+
IPC_ENUM_TRAITS_MAX_VALUE(net::SSLInfo::HandshakeType,
net::SSLInfo::HANDSHAKE_FULL)
IPC_ENUM_TRAITS_MAX_VALUE(net::TokenBindingParam, net::TB_PARAM_ECDSAP256)
@@ -284,7 +324,7 @@ IPC_STRUCT_TRAITS_BEGIN(network::ResourceRequest)
IPC_STRUCT_TRAITS_MEMBER(should_reset_appcache)
IPC_STRUCT_TRAITS_MEMBER(service_worker_provider_id)
IPC_STRUCT_TRAITS_MEMBER(originated_from_service_worker)
- IPC_STRUCT_TRAITS_MEMBER(service_worker_mode)
+ IPC_STRUCT_TRAITS_MEMBER(skip_service_worker)
IPC_STRUCT_TRAITS_MEMBER(fetch_request_mode)
IPC_STRUCT_TRAITS_MEMBER(fetch_credentials_mode)
IPC_STRUCT_TRAITS_MEMBER(fetch_redirect_mode)
@@ -309,7 +349,6 @@ IPC_STRUCT_TRAITS_BEGIN(network::ResourceRequest)
IPC_STRUCT_TRAITS_MEMBER(previews_state)
IPC_STRUCT_TRAITS_MEMBER(resource_body_stream_url)
IPC_STRUCT_TRAITS_MEMBER(initiated_in_secure_context)
- IPC_STRUCT_TRAITS_MEMBER(download_to_network_cache_only)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(network::ResourceResponseInfo)
@@ -318,8 +357,8 @@ IPC_STRUCT_TRAITS_BEGIN(network::ResourceResponseInfo)
IPC_STRUCT_TRAITS_MEMBER(headers)
IPC_STRUCT_TRAITS_MEMBER(mime_type)
IPC_STRUCT_TRAITS_MEMBER(charset)
+ IPC_STRUCT_TRAITS_MEMBER(ct_policy_compliance)
IPC_STRUCT_TRAITS_MEMBER(is_legacy_symantec_cert)
- IPC_STRUCT_TRAITS_MEMBER(cert_validity_start)
IPC_STRUCT_TRAITS_MEMBER(content_length)
IPC_STRUCT_TRAITS_MEMBER(encoded_data_length)
IPC_STRUCT_TRAITS_MEMBER(encoded_body_length)
diff --git a/chromium/services/network/public/cpp/network_switches.cc b/chromium/services/network/public/cpp/network_switches.cc
index acb3964c35d..efed4b7e1a0 100644
--- a/chromium/services/network/public/cpp/network_switches.cc
+++ b/chromium/services/network/public/cpp/network_switches.cc
@@ -8,6 +8,28 @@ namespace network {
namespace switches {
+// These mappings only apply to the host resolver.
+const char kHostResolverRules[] = "host-resolver-rules";
+
+// A set of public key hashes for which to ignore certificate-related errors.
+//
+// If the certificate chain presented by the server does not validate, and one
+// or more certificates have public key hashes that match a key from this list,
+// the error is ignored.
+//
+// The switch value must a be a comma-separated list of Base64-encoded SHA-256
+// SPKI Fingerprints (RFC 7469, Section 2.4).
+//
+// This switch has no effect unless --user-data-dir (as defined by the content
+// embedder) is also present.
+const char kIgnoreCertificateErrorsSPKIList[] =
+ "ignore-certificate-errors-spki-list";
+
+// Enables saving net log events to a file. If a value is given, it used as the
+// path the the file, otherwise the file is named netlog.json and placed in the
+// user data directory.
+const char kLogNetLog[] = "log-net-log";
+
// Don't send HTTP-Referer headers.
const char kNoReferrers[] = "no-referrers";
diff --git a/chromium/services/network/public/cpp/network_switches.h b/chromium/services/network/public/cpp/network_switches.h
index f43d8513fd0..411e455bdc9 100644
--- a/chromium/services/network/public/cpp/network_switches.h
+++ b/chromium/services/network/public/cpp/network_switches.h
@@ -2,16 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_NETWORK_SWITCHES_
-#define SERVICES_NETWORK_PUBLIC_CPP_NETWORK_SWITCHES_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_NETWORK_SWITCHES_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_NETWORK_SWITCHES_H_
+
+#include "base/component_export.h"
namespace network {
namespace switches {
-extern const char kNoReferrers[];
-}
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const char kHostResolverRules[];
+COMPONENT_EXPORT(NETWORK_CPP)
+extern const char kIgnoreCertificateErrorsSPKIList[];
+COMPONENT_EXPORT(NETWORK_CPP) extern const char kLogNetLog[];
+COMPONENT_EXPORT(NETWORK_CPP) extern const char kNoReferrers[];
+
+} // namespace switches
} // namespace network
-#endif // SERVICES_NETWORK_PUBLIC_CPP_NETWORK_SWITCHES_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_NETWORK_SWITCHES_H_
diff --git a/chromium/services/network/public/cpp/network_traits_test_service.mojom b/chromium/services/network/public/cpp/network_traits_test_service.mojom
index ab8dae7e6e0..83e5dab6a7e 100644
--- a/chromium/services/network/public/cpp/network_traits_test_service.mojom
+++ b/chromium/services/network/public/cpp/network_traits_test_service.mojom
@@ -4,7 +4,7 @@
module network.mojom;
-import "services/network/public/interfaces/http_request_headers.mojom";
+import "services/network/public/mojom/http_request_headers.mojom";
interface TraitsTestService {
[Sync]
diff --git a/chromium/services/network/public/cpp/network_types.typemap b/chromium/services/network/public/cpp/network_types.typemap
index 22fdb53e5a2..066bf78e2b6 100644
--- a/chromium/services/network/public/cpp/network_types.typemap
+++ b/chromium/services/network/public/cpp/network_types.typemap
@@ -2,14 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/network_types.mojom"
+mojom = "//services/network/public/mojom/network_types.mojom"
public_deps = [
"//net",
]
public_headers = [ "//net/nqe/effective_connection_type.h" ]
traits_headers = [ "//services/network/public/cpp/network_param_ipc_traits.h" ]
deps = [
- "//services/network/public/cpp:typemap_dependencies",
+ "//services/network/public/cpp:cpp_base",
]
type_mappings =
[ "network.mojom.EffectiveConnectionType=net::EffectiveConnectionType" ]
diff --git a/chromium/services/network/public/cpp/proxy_config.typemap b/chromium/services/network/public/cpp/proxy_config.typemap
index 15f09b82809..2e0ad8d4201 100644
--- a/chromium/services/network/public/cpp/proxy_config.typemap
+++ b/chromium/services/network/public/cpp/proxy_config.typemap
@@ -2,17 +2,17 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/proxy_config.mojom"
+mojom = "//services/network/public/mojom/proxy_config.mojom"
public_headers = [
- "//net/proxy/proxy_bypass_rules.h",
- "//net/proxy/proxy_config.h",
- "//net/proxy/proxy_config_source.h",
- "//net/proxy/proxy_list.h",
+ "//net/proxy_resolution/proxy_bypass_rules.h",
+ "//net/proxy_resolution/proxy_config.h",
+ "//net/proxy_resolution/proxy_config_source.h",
+ "//net/proxy_resolution/proxy_list.h",
]
-traits_headers = [ "//services/network/public/cpp/proxy_config_traits.h" ]
+traits_headers = [ "//services/network/public/cpp/proxy_config_mojom_traits.h" ]
deps = [
"//net:net",
- "//services/network/public/interfaces:interfaces_shared",
+ "//services/network/public/mojom:mojom_shared",
]
type_mappings = [
"network.mojom.ProxyBypassRules=net::ProxyBypassRules",
diff --git a/chromium/services/network/public/cpp/proxy_config_traits.cc b/chromium/services/network/public/cpp/proxy_config_mojom_traits.cc
index ad58ca5bb6e..019e41ce478 100644
--- a/chromium/services/network/public/cpp/proxy_config_traits.cc
+++ b/chromium/services/network/public/cpp/proxy_config_mojom_traits.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/proxy_config_traits.h"
+#include "services/network/public/cpp/proxy_config_mojom_traits.h"
#include "base/logging.h"
#include "url/gurl.h"
-#include "url/mojo/url_gurl_struct_traits.h"
+#include "url/mojom/url_gurl_mojom_traits.h"
namespace mojo {
@@ -63,14 +63,14 @@ network::mojom::ProxyRulesType
EnumTraits<network::mojom::ProxyRulesType, net::ProxyConfig::ProxyRules::Type>::
ToMojom(net::ProxyConfig::ProxyRules::Type net_proxy_rules_type) {
switch (net_proxy_rules_type) {
- case net::ProxyConfig::ProxyRules::TYPE_NO_RULES:
- return network::mojom::ProxyRulesType::TYPE_NO_RULES;
- case net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY:
- return network::mojom::ProxyRulesType::TYPE_SINGLE_PROXY;
- case net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME:
- return network::mojom::ProxyRulesType::TYPE_PROXY_PER_SCHEME;
+ case net::ProxyConfig::ProxyRules::Type::EMPTY:
+ return network::mojom::ProxyRulesType::EMPTY;
+ case net::ProxyConfig::ProxyRules::Type::PROXY_LIST:
+ return network::mojom::ProxyRulesType::PROXY_LIST;
+ case net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME:
+ return network::mojom::ProxyRulesType::PROXY_LIST_PER_SCHEME;
}
- return network::mojom::ProxyRulesType::TYPE_NO_RULES;
+ return network::mojom::ProxyRulesType::EMPTY;
}
bool EnumTraits<network::mojom::ProxyRulesType,
@@ -78,14 +78,14 @@ bool EnumTraits<network::mojom::ProxyRulesType,
FromMojom(network::mojom::ProxyRulesType mojo_proxy_rules_type,
net::ProxyConfig::ProxyRules::Type* out) {
switch (mojo_proxy_rules_type) {
- case network::mojom::ProxyRulesType::TYPE_NO_RULES:
- *out = net::ProxyConfig::ProxyRules::TYPE_NO_RULES;
+ case network::mojom::ProxyRulesType::EMPTY:
+ *out = net::ProxyConfig::ProxyRules::Type::EMPTY;
return true;
- case network::mojom::ProxyRulesType::TYPE_SINGLE_PROXY:
- *out = net::ProxyConfig::ProxyRules::TYPE_SINGLE_PROXY;
+ case network::mojom::ProxyRulesType::PROXY_LIST:
+ *out = net::ProxyConfig::ProxyRules::Type::PROXY_LIST;
return true;
- case network::mojom::ProxyRulesType::TYPE_PROXY_PER_SCHEME:
- *out = net::ProxyConfig::ProxyRules::TYPE_PROXY_PER_SCHEME;
+ case network::mojom::ProxyRulesType::PROXY_LIST_PER_SCHEME:
+ *out = net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME;
return true;
}
return false;
@@ -179,7 +179,6 @@ bool StructTraits<network::mojom::ProxyConfigDataView, net::ProxyConfig>::Read(
out_proxy_config->set_auto_detect(data.auto_detect());
out_proxy_config->set_pac_mandatory(data.pac_mandatory());
- out_proxy_config->set_id(data.id());
return true;
}
diff --git a/chromium/services/network/public/cpp/proxy_config_traits.h b/chromium/services/network/public/cpp/proxy_config_mojom_traits.h
index 368ed811361..f5ba70d8742 100644
--- a/chromium/services/network/public/cpp/proxy_config_traits.h
+++ b/chromium/services/network/public/cpp/proxy_config_mojom_traits.h
@@ -2,23 +2,25 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_PROXY_CONFIG_TRAITS_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_PROXY_CONFIG_TRAITS_H_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_PROXY_CONFIG_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_PROXY_CONFIG_MOJOM_TRAITS_H_
-#include "net/proxy/proxy_bypass_rules.h"
-#include "net/proxy/proxy_config.h"
-#include "net/proxy/proxy_config_source.h"
-#include "net/proxy/proxy_list.h"
-#include "services/network/public/interfaces/proxy_config.mojom-shared.h"
-#include "url/mojo/url_gurl_struct_traits.h"
+#include "base/component_export.h"
+#include "net/proxy_resolution/proxy_bypass_rules.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "net/proxy_resolution/proxy_config_source.h"
+#include "net/proxy_resolution/proxy_list.h"
+#include "services/network/public/mojom/proxy_config.mojom-shared.h"
+#include "url/mojom/url_gurl_mojom_traits.h"
// This file handles the serialization of net::ProxyConfig.
namespace mojo {
template <>
-struct StructTraits<network::mojom::ProxyBypassRulesDataView,
- net::ProxyBypassRules> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::ProxyBypassRulesDataView,
+ net::ProxyBypassRules> {
public:
static std::vector<std::string> rules(const net::ProxyBypassRules& r);
static bool Read(network::mojom::ProxyBypassRulesDataView data,
@@ -26,7 +28,8 @@ struct StructTraits<network::mojom::ProxyBypassRulesDataView,
};
template <>
-struct StructTraits<network::mojom::ProxyListDataView, net::ProxyList> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::ProxyListDataView, net::ProxyList> {
public:
static std::vector<std::string> proxies(const net::ProxyList& r);
static bool Read(network::mojom::ProxyListDataView data,
@@ -34,8 +37,9 @@ struct StructTraits<network::mojom::ProxyListDataView, net::ProxyList> {
};
template <>
-struct EnumTraits<network::mojom::ProxyRulesType,
- net::ProxyConfig::ProxyRules::Type> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ EnumTraits<network::mojom::ProxyRulesType,
+ net::ProxyConfig::ProxyRules::Type> {
public:
static network::mojom::ProxyRulesType ToMojom(
net::ProxyConfig::ProxyRules::Type net_proxy_rules_type);
@@ -44,8 +48,9 @@ struct EnumTraits<network::mojom::ProxyRulesType,
};
template <>
-struct StructTraits<network::mojom::ProxyRulesDataView,
- net::ProxyConfig::ProxyRules> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::ProxyRulesDataView,
+ net::ProxyConfig::ProxyRules> {
public:
static const net::ProxyBypassRules& bypass_rules(
const net::ProxyConfig::ProxyRules& r) {
@@ -84,7 +89,8 @@ struct StructTraits<network::mojom::ProxyRulesDataView,
};
template <>
-struct EnumTraits<network::mojom::ProxyConfigSource, net::ProxyConfigSource> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ EnumTraits<network::mojom::ProxyConfigSource, net::ProxyConfigSource> {
public:
static network::mojom::ProxyConfigSource ToMojom(
net::ProxyConfigSource net_proxy_config_source);
@@ -94,7 +100,8 @@ struct EnumTraits<network::mojom::ProxyConfigSource, net::ProxyConfigSource> {
};
template <>
-struct StructTraits<network::mojom::ProxyConfigDataView, net::ProxyConfig> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ StructTraits<network::mojom::ProxyConfigDataView, net::ProxyConfig> {
public:
static bool auto_detect(const net::ProxyConfig& r) { return r.auto_detect(); }
static const GURL& pac_url(const net::ProxyConfig& r) { return r.pac_url(); }
@@ -108,11 +115,10 @@ struct StructTraits<network::mojom::ProxyConfigDataView, net::ProxyConfig> {
static net::ProxyConfigSource source(const net::ProxyConfig& r) {
return r.source();
}
- static int32_t id(const net::ProxyConfig& r) { return r.id(); }
static bool Read(network::mojom::ProxyConfigDataView data,
net::ProxyConfig* out_proxy_config);
};
} // namespace mojo
-#endif // SERVICES_NETWORK_PUBLIC_CPP_PROXY_CONFIG_TRAITS_H_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_PROXY_CONFIG_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/proxy_config_traits_unittest.cc b/chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc
index 7ca3ea17460..c17ba4ba7a1 100644
--- a/chromium/services/network/public/cpp/proxy_config_traits_unittest.cc
+++ b/chromium/services/network/public/cpp/proxy_config_mojom_traits_unittest.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/proxy_config_traits.h"
+#include "services/network/public/cpp/proxy_config_mojom_traits.h"
-#include "net/proxy/proxy_bypass_rules.h"
-#include "net/proxy/proxy_config.h"
-#include "services/network/public/interfaces/proxy_config.mojom.h"
+#include "net/proxy_resolution/proxy_bypass_rules.h"
+#include "net/proxy_resolution/proxy_config.h"
+#include "services/network/public/mojom/proxy_config.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -21,21 +21,17 @@ bool TestProxyConfigRoundTrip(net::ProxyConfig& original_config) {
mojom::ProxyConfig::Serialize(&original_config), &copied_config));
return original_config.Equals(copied_config) &&
- original_config.id() == copied_config.id() &&
- original_config.source() == copied_config.source() &&
- original_config.is_valid() == copied_config.is_valid();
+ original_config.source() == copied_config.source();
}
TEST(ProxyConfigTraitsTest, AutoDetect) {
net::ProxyConfig proxy_config = net::ProxyConfig::CreateAutoDetect();
- proxy_config.set_id(1);
proxy_config.set_source(net::ProxyConfigSource::PROXY_CONFIG_SOURCE_KDE);
EXPECT_TRUE(TestProxyConfigRoundTrip(proxy_config));
}
TEST(ProxyConfigTraitsTest, Direct) {
net::ProxyConfig proxy_config = net::ProxyConfig::CreateDirect();
- proxy_config.set_id(2);
proxy_config.set_source(
net::ProxyConfigSource::PROXY_CONFIG_SOURCE_GSETTINGS);
EXPECT_TRUE(TestProxyConfigRoundTrip(proxy_config));
diff --git a/chromium/services/network/public/cpp/resource_request.h b/chromium/services/network/public/cpp/resource_request.h
index f0fd32bd967..99f42e6a749 100644
--- a/chromium/services/network/public/cpp/resource_request.h
+++ b/chromium/services/network/public/cpp/resource_request.h
@@ -8,21 +8,22 @@
#include <stdint.h>
#include <string>
+#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "net/base/request_priority.h"
#include "net/http/http_request_headers.h"
#include "net/url_request/url_request.h"
#include "services/network/public/cpp/resource_request_body.h"
-#include "services/network/public/interfaces/cors.mojom-shared.h"
-#include "services/network/public/interfaces/fetch_api.mojom-shared.h"
-#include "services/network/public/interfaces/request_context_frame_type.mojom-shared.h"
+#include "services/network/public/mojom/cors.mojom-shared.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
+#include "services/network/public/mojom/request_context_frame_type.mojom-shared.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace network {
-struct ResourceRequest {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequest {
ResourceRequest();
ResourceRequest(const ResourceRequest& request);
~ResourceRequest();
@@ -116,10 +117,9 @@ struct ResourceRequest {
// The service worker mode that indicates which service workers should get
// events for this request.
- // Note: this is an enum of type content::ServiceWorkerMode.
// TODO(jam): remove this from the struct since network service shouldn't know
// about this.
- int service_worker_mode = 0;
+ bool skip_service_worker = false;
// The request mode passed to the ServiceWorker.
mojom::FetchRequestMode fetch_request_mode =
@@ -214,10 +214,6 @@ struct ResourceRequest {
// Wether or not the initiator of this request is a secure context.
bool initiated_in_secure_context = false;
-
- // The response should be downloaded and stored in the network cache, but not
- // sent back to the renderer.
- bool download_to_network_cache_only = false;
};
} // namespace network
diff --git a/chromium/services/network/public/cpp/resource_request_body.cc b/chromium/services/network/public/cpp/resource_request_body.cc
index 379c34b674a..37fb2274de2 100644
--- a/chromium/services/network/public/cpp/resource_request_body.cc
+++ b/chromium/services/network/public/cpp/resource_request_body.cc
@@ -51,16 +51,6 @@ void ResourceRequestBody::AppendBlob(const std::string& uuid) {
elements_.back().SetToBlob(uuid);
}
-void ResourceRequestBody::AppendFileSystemFileRange(
- const GURL& url,
- uint64_t offset,
- uint64_t length,
- const base::Time& expected_modification_time) {
- elements_.push_back(DataElement());
- elements_.back().SetToFileSystemUrlRange(url, offset, length,
- expected_modification_time);
-}
-
void ResourceRequestBody::AppendDataPipe(
mojom::DataPipeGetterPtr data_pipe_getter) {
elements_.push_back(DataElement());
diff --git a/chromium/services/network/public/cpp/resource_request_body.h b/chromium/services/network/public/cpp/resource_request_body.h
index 7846d15c007..64b945ad73c 100644
--- a/chromium/services/network/public/cpp/resource_request_body.h
+++ b/chromium/services/network/public/cpp/resource_request_body.h
@@ -10,18 +10,18 @@
#include <string>
#include <vector>
+#include "base/component_export.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "build/build_config.h"
#include "services/network/public/cpp/data_element.h"
#include "url/gurl.h"
namespace network {
// ResourceRequestBody represents body (i.e. upload data) of a HTTP request.
-class ResourceRequestBody
+class COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceRequestBody
: public base::RefCountedThreadSafe<ResourceRequestBody> {
public:
ResourceRequestBody();
@@ -44,10 +44,6 @@ class ResourceRequestBody
const base::Time& expected_modification_time);
void AppendBlob(const std::string& uuid);
- void AppendFileSystemFileRange(const GURL& url,
- uint64_t offset,
- uint64_t length,
- const base::Time& expected_modification_time);
void AppendDataPipe(mojom::DataPipeGetterPtr data_pipe_getter);
const std::vector<DataElement>* elements() const { return &elements_; }
diff --git a/chromium/services/network/public/cpp/resource_response.cc b/chromium/services/network/public/cpp/resource_response.cc
index 67163514fce..777a2b4c138 100644
--- a/chromium/services/network/public/cpp/resource_response.cc
+++ b/chromium/services/network/public/cpp/resource_response.cc
@@ -18,8 +18,8 @@ scoped_refptr<ResourceResponse> ResourceResponse::DeepCopy() const {
}
new_response->head.mime_type = head.mime_type;
new_response->head.charset = head.charset;
+ new_response->head.ct_policy_compliance = head.ct_policy_compliance;
new_response->head.is_legacy_symantec_cert = head.is_legacy_symantec_cert;
- new_response->head.cert_validity_start = head.cert_validity_start;
new_response->head.content_length = head.content_length;
new_response->head.encoded_data_length = head.encoded_data_length;
new_response->head.encoded_body_length = head.encoded_body_length;
diff --git a/chromium/services/network/public/cpp/resource_response.h b/chromium/services/network/public/cpp/resource_response.h
index 011bffeee2d..71cac5f4f31 100644
--- a/chromium/services/network/public/cpp/resource_response.h
+++ b/chromium/services/network/public/cpp/resource_response.h
@@ -11,6 +11,7 @@
#include <string>
#include "base/compiler_specific.h"
+#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "net/url_request/url_request_status.h"
#include "services/network/public/cpp/resource_response_info.h"
@@ -19,7 +20,8 @@
namespace network {
// Parameters for a resource response header.
-struct ResourceResponseHead : ResourceResponseInfo {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceResponseHead
+ : ResourceResponseInfo {
// TimeTicks::Now() when the browser received the request from the renderer.
base::TimeTicks request_start;
// TimeTicks::Now() when the browser sent the response to the renderer.
@@ -28,7 +30,8 @@ struct ResourceResponseHead : ResourceResponseInfo {
// Simple wrapper that refcounts ResourceResponseHead.
// Inherited, rather than typedef'd, to allow forward declarations.
-struct ResourceResponse : public base::RefCountedThreadSafe<ResourceResponse> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceResponse
+ : public base::RefCountedThreadSafe<ResourceResponse> {
public:
ResourceResponseHead head;
diff --git a/chromium/services/network/public/cpp/resource_response_info.cc b/chromium/services/network/public/cpp/resource_response_info.cc
index f97e14b52ab..c47e87b8557 100644
--- a/chromium/services/network/public/cpp/resource_response_info.cc
+++ b/chromium/services/network/public/cpp/resource_response_info.cc
@@ -9,7 +9,9 @@
namespace network {
ResourceResponseInfo::ResourceResponseInfo()
- : is_legacy_symantec_cert(false),
+ : ct_policy_compliance(net::ct::CTPolicyCompliance::
+ CT_POLICY_COMPLIANCE_DETAILS_NOT_AVAILABLE),
+ is_legacy_symantec_cert(false),
content_length(-1),
encoded_data_length(-1),
encoded_body_length(-1),
diff --git a/chromium/services/network/public/cpp/resource_response_info.h b/chromium/services/network/public/cpp/resource_response_info.h
index 66d5da34fdc..9b9c6c73cc6 100644
--- a/chromium/services/network/public/cpp/resource_response_info.h
+++ b/chromium/services/network/public/cpp/resource_response_info.h
@@ -9,24 +9,26 @@
#include <string>
+#include "base/component_export.h"
#include "base/files/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "net/base/host_port_pair.h"
#include "net/base/load_timing_info.h"
+#include "net/cert/ct_policy_status.h"
#include "net/cert/signed_certificate_timestamp_and_status.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/nqe/effective_connection_type.h"
#include "services/network/public/cpp/http_raw_request_response_info.h"
-#include "services/network/public/interfaces/fetch_api.mojom-shared.h"
+#include "services/network/public/mojom/fetch_api.mojom-shared.h"
#include "url/gurl.h"
namespace network {
// NOTE: when modifying this structure, also update ResourceResponse::DeepCopy
// in resource_response.cc.
-struct ResourceResponseInfo {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) ResourceResponseInfo {
ResourceResponseInfo();
ResourceResponseInfo(const ResourceResponseInfo& other);
~ResourceResponseInfo();
@@ -49,13 +51,13 @@ struct ResourceResponseInfo {
// response's mime type. This may be a derived value.
std::string charset;
+ // The resource's compliance with the Certificate Transparency policy.
+ net::ct::CTPolicyCompliance ct_policy_compliance;
+
// True if the resource was loaded with an otherwise-valid legacy Symantec
// certificate which will be distrusted in future.
bool is_legacy_symantec_cert;
- // The time at which the certificate (if any) of the resource expires.
- base::Time cert_validity_start;
-
// Content length if available. -1 if not available
int64_t content_length;
@@ -111,9 +113,9 @@ struct ResourceResponseInfo {
// True if the response was fetched by a ServiceWorker.
bool was_fetched_via_service_worker;
- // True when the request whoes mode is |CORS| or |CORS-with-forced-preflight|
+ // True when a request whose mode is |CORS| or |CORS-with-forced-preflight|
// is sent to a ServiceWorker but FetchEvent.respondWith is not called. So the
- // renderer have to resend the request with skip service worker flag
+ // renderer has to resend the request with skip service worker flag
// considering the CORS preflight logic.
bool was_fallback_required_by_service_worker;
@@ -121,7 +123,8 @@ struct ResourceResponseInfo {
// ServiceWorkerResponseInfo::url_list_via_service_worker().
std::vector<GURL> url_list_via_service_worker;
- // The type of the response which was fetched by the ServiceWorker.
+ // The type of the response, if it was returned by a service worker. This is
+ // kDefault if the response was not returned by a service worker.
mojom::FetchResponseType response_type_via_service_worker;
// The time immediately before starting ServiceWorker. If the response is not
diff --git a/chromium/services/network/public/cpp/simple_url_loader.cc b/chromium/services/network/public/cpp/simple_url_loader.cc
new file mode 100644
index 00000000000..4a8192be85a
--- /dev/null
+++ b/chromium/services/network/public/cpp/simple_url_loader.cc
@@ -0,0 +1,1499 @@
+// 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 "services/network/public/cpp/simple_url_loader.h"
+
+#include <stdint.h>
+
+#include <algorithm>
+#include <limits>
+
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/location.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_piece.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/base/net_errors.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_request_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/data_element.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
+#include "services/network/public/mojom/data_pipe_getter.mojom.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace network {
+
+const size_t SimpleURLLoader::kMaxBoundedStringDownloadSize = 1024 * 1024;
+const size_t SimpleURLLoader::kMaxUploadStringSizeToCopy = 256 * 1024;
+
+namespace {
+
+// This file contains SimpleURLLoaderImpl, several BodyHandler implementations,
+// BodyReader, and StringUploadDataPipeGetter.
+//
+// SimpleURLLoaderImpl implements URLLoaderClient and drives the URLLoader.
+//
+// Each SimpleURLLoaderImpl creates a BodyHandler when the request is started.
+// The BodyHandler drives the body pipe, handles body data as needed (writes it
+// to a string, file, etc), and handles passing that data to the consumer's
+// callback.
+//
+// BodyReader is a utility class that BodyHandler implementations use to drive
+// the BodyPipe. This isn't handled by the SimpleURLLoader as some BodyHandlers
+// consume data off thread, so having it as a separate class allows the data
+// pipe to be used off thread, reducing use of the main thread.
+//
+// StringUploadDataPipeGetter is a class to stream a string upload body to the
+// network service, rather than to copy it all at once.
+
+class StringUploadDataPipeGetter : public mojom::DataPipeGetter {
+ public:
+ explicit StringUploadDataPipeGetter(const std::string& upload_string)
+ : upload_string_(upload_string) {}
+ ~StringUploadDataPipeGetter() override = default;
+
+ // Returns a DataPipeGetterPtr for a new upload attempt, closing all
+ // previously opened pipes.
+ mojom::DataPipeGetterPtr GetPtrForNewUpload() {
+ // If this is a retry, need to close all bindings, since only one consumer
+ // can read from the data pipe at a time.
+ binding_set_.CloseAllBindings();
+ // Not strictly needed, but seems best to close the old body pipe and stop
+ // any pending reads.
+ ResetBodyPipe();
+
+ mojom::DataPipeGetterPtr data_pipe_getter;
+ binding_set_.AddBinding(this, mojo::MakeRequest(&data_pipe_getter));
+ return data_pipe_getter;
+ }
+
+ private:
+ // DataPipeGetter implementation:
+
+ void Read(mojo::ScopedDataPipeProducerHandle pipe,
+ ReadCallback callback) override {
+ // Close any previous body pipe, to avoid confusion between the two, if the
+ // consumer wants to restart reading from the file.
+ ResetBodyPipe();
+
+ std::move(callback).Run(net::OK, upload_string_.length());
+ upload_body_pipe_ = std::move(pipe);
+ handle_watcher_ = std::make_unique<mojo::SimpleWatcher>(
+ FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL);
+ handle_watcher_->Watch(
+ upload_body_pipe_.get(),
+ // Don't bother watching for close - rely on read pipes for errors.
+ MOJO_HANDLE_SIGNAL_WRITABLE, MOJO_WATCH_CONDITION_SATISFIED,
+ base::BindRepeating(&StringUploadDataPipeGetter::MojoReadyCallback,
+ base::Unretained(this)));
+ WriteData();
+ }
+
+ void Clone(mojom::DataPipeGetterRequest request) override {
+ binding_set_.AddBinding(this, std::move(request));
+ }
+
+ void MojoReadyCallback(MojoResult result,
+ const mojo::HandleSignalsState& state) {
+ WriteData();
+ }
+
+ void WriteData() {
+ DCHECK_LE(write_position_, upload_string_.length());
+
+ while (true) {
+ uint32_t write_size = static_cast<uint32_t>(
+ std::min(static_cast<size_t>(32 * 1024),
+ upload_string_.length() - write_position_));
+ if (write_size == 0) {
+ // Upload is done. Close the uplaod body pipe and wait for another call
+ // to Read().
+ ResetBodyPipe();
+ return;
+ }
+
+ int result =
+ upload_body_pipe_->WriteData(upload_string_.data() + write_position_,
+ &write_size, MOJO_WRITE_DATA_FLAG_NONE);
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ handle_watcher_->ArmOrNotify();
+ return;
+ }
+
+ if (result != MOJO_RESULT_OK) {
+ // Ignore the pipe being closed - the upload may still be retried with
+ // another call to Read.
+ ResetBodyPipe();
+ return;
+ }
+
+ write_position_ += write_size;
+ DCHECK_LE(write_position_, upload_string_.length());
+ }
+ }
+
+ // Closes the body pipe, and resets the position the class is writing from.
+ // Should be called either when a new binding is created, or a new read
+ // through the file is started.
+ void ResetBodyPipe() {
+ handle_watcher_.reset();
+ upload_body_pipe_.reset();
+ write_position_ = 0;
+ }
+
+ mojo::BindingSet<mojom::DataPipeGetter> binding_set_;
+
+ mojo::ScopedDataPipeProducerHandle upload_body_pipe_;
+ // Must be below |write_pipe_|, so it's deleted first.
+ std::unique_ptr<mojo::SimpleWatcher> handle_watcher_;
+ size_t write_position_ = 0;
+
+ const std::string upload_string_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringUploadDataPipeGetter);
+};
+
+class BodyHandler;
+
+class SimpleURLLoaderImpl : public SimpleURLLoader,
+ public mojom::URLLoaderClient {
+ public:
+ SimpleURLLoaderImpl(std::unique_ptr<ResourceRequest> resource_request,
+ const net::NetworkTrafficAnnotationTag& annotation_tag);
+ ~SimpleURLLoaderImpl() override;
+
+ // SimpleURLLoader implementation.
+ void DownloadToString(mojom::URLLoaderFactory* url_loader_factory,
+ BodyAsStringCallback body_as_string_callback,
+ size_t max_body_size) override;
+ void DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+ mojom::URLLoaderFactory* url_loader_factory,
+ BodyAsStringCallback body_as_string_callback) override;
+ void DownloadToFile(
+ mojom::URLLoaderFactory* url_loader_factory,
+ DownloadToFileCompleteCallback download_to_file_complete_callback,
+ const base::FilePath& file_path,
+ int64_t max_body_size) override;
+ void DownloadToTempFile(
+ mojom::URLLoaderFactory* url_loader_factory,
+ DownloadToFileCompleteCallback download_to_file_complete_callback,
+ int64_t max_body_size) override;
+ void DownloadAsStream(
+ mojom::URLLoaderFactory* url_loader_factory,
+ SimpleURLLoaderStreamConsumer* stream_consumer) override;
+ void SetOnRedirectCallback(
+ const OnRedirectCallback& on_redirect_callback) override;
+ void SetOnResponseStartedCallback(
+ const OnResponseStartedCallback& on_response_started_callback) override;
+ void SetAllowPartialResults(bool allow_partial_results) override;
+ void SetAllowHttpErrorResults(bool allow_http_error_results) override;
+ void AttachStringForUpload(const std::string& upload_data,
+ const std::string& upload_content_type) override;
+ void AttachFileForUpload(const base::FilePath& upload_file_path,
+ const std::string& upload_content_type) override;
+ void SetRetryOptions(int max_retries, int retry_mode) override;
+ int NetError() const override;
+ const ResourceResponseHead* ResponseInfo() const override;
+ const GURL& GetFinalURL() const override;
+
+ // Called by BodyHandler when the BodyHandler body handler is done. If |error|
+ // is not net::OK, some error occurred reading or consuming the body. If it is
+ // net::OK, the pipe was closed and all data received was successfully
+ // handled. This could indicate an error, concellation, or completion. To
+ // determine which case this is, the size will also be compared to the size
+ // reported in URLLoaderCompletionStatus(), if
+ // URLLoaderCompletionStatus indicates a success.
+ void OnBodyHandlerDone(net::Error error, int64_t received_body_size);
+
+ // Finished the request with the provided error code, after freeing Mojo
+ // resources. Closes any open pipes, so no URLLoader or BodyHandlers callbacks
+ // will be invoked after this is called.
+ void FinishWithResult(int net_error);
+
+ private:
+ // Per-request state values. This object is re-created for each retry.
+ // Separating out the values makes re-initializing them on retry simpler.
+ struct RequestState {
+ RequestState() = default;
+ ~RequestState() = default;
+
+ bool request_completed = false;
+ // The expected total size of the body, taken from
+ // URLLoaderCompletionStatus.
+ int64_t expected_body_size = 0;
+
+ bool body_started = false;
+ bool body_completed = false;
+ // Final size of the body. Set once the body's Mojo pipe has been closed.
+ int64_t received_body_size = 0;
+
+ // Set to true when FinishWithResult() is called. Once that happens, the
+ // consumer is informed of completion, and both pipes are closed.
+ bool finished = false;
+
+ // Result of the request.
+ int net_error = net::ERR_IO_PENDING;
+
+ std::unique_ptr<ResourceResponseHead> response_info;
+ };
+
+ // Prepares internal state to start a request, and then calls StartRequest().
+ // Only used for the initial request (Not retries).
+ void Start(mojom::URLLoaderFactory* url_loader_factory);
+
+ // Starts a request. Used for both the initial request and retries, if any.
+ void StartRequest(mojom::URLLoaderFactory* url_loader_factory);
+
+ // Re-initializes state of |this| and |body_handler_| prior to retrying a
+ // request.
+ void Retry();
+
+ // mojom::URLLoaderClient implementation;
+ void OnReceiveResponse(const ResourceResponseHead& response_head,
+ const base::Optional<net::SSLInfo>& ssl_info,
+ mojom::DownloadedTempFilePtr downloaded_file) override;
+ void OnReceiveRedirect(const net::RedirectInfo& redirect_info,
+ const ResourceResponseHead& response_head) override;
+ void OnDataDownloaded(int64_t data_length, int64_t encoded_length) override;
+ void OnReceiveCachedMetadata(const std::vector<uint8_t>& data) override;
+ void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+ void OnUploadProgress(int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback ack_callback) override;
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) override;
+ void OnComplete(const URLLoaderCompletionStatus& status) override;
+
+ // Choose the TaskPriority based on |resource_request_|'s net priority.
+ // TODO(mmenke): Can something better be done here?
+ base::TaskPriority GetTaskPriority() const {
+ base::TaskPriority task_priority;
+ if (resource_request_->priority >= net::MEDIUM) {
+ task_priority = base::TaskPriority::USER_BLOCKING;
+ } else if (resource_request_->priority >= net::LOW) {
+ task_priority = base::TaskPriority::USER_VISIBLE;
+ } else {
+ task_priority = base::TaskPriority::BACKGROUND;
+ }
+ return task_priority;
+ }
+
+ // Bound to the URLLoaderClient message pipe (|client_binding_|) via
+ // set_connection_error_handler.
+ void OnConnectionError();
+
+ // Completes the request by calling FinishWithResult() if OnComplete() was
+ // called and either no body pipe was ever received, or the body pipe was
+ // closed.
+ void MaybeComplete();
+
+ OnRedirectCallback on_redirect_callback_;
+ OnResponseStartedCallback on_response_started_callback_;
+ bool allow_partial_results_ = false;
+ bool allow_http_error_results_ = false;
+
+ // Information related to retrying.
+ int remaining_retries_ = 0;
+ int retry_mode_ = RETRY_NEVER;
+
+ // The next values contain all the information required to restart the
+ // request.
+
+ // Populated in the constructor, and cleared once no longer needed, when no
+ // more retries are possible.
+ std::unique_ptr<ResourceRequest> resource_request_;
+ const net::NetworkTrafficAnnotationTag annotation_tag_;
+ // Cloned from the input URLLoaderFactory if it may be needed to follow
+ // redirects.
+ mojom::URLLoaderFactoryPtr url_loader_factory_ptr_;
+ std::unique_ptr<BodyHandler> body_handler_;
+
+ mojo::Binding<mojom::URLLoaderClient> client_binding_;
+ mojom::URLLoaderPtr url_loader_;
+
+ std::unique_ptr<StringUploadDataPipeGetter> string_upload_data_pipe_getter_;
+
+ // Per-request state. Always non-null, but re-created on redirect.
+ std::unique_ptr<RequestState> request_state_;
+
+ GURL final_url_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ base::WeakPtrFactory<SimpleURLLoaderImpl> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleURLLoaderImpl);
+};
+
+// Utility class to drive the pipe reading a response body. Can be created on
+// one thread and then used to read data on another. A BodyReader may only be
+// used once. If a request is retried, a new one must be created.
+class BodyReader {
+ public:
+ class Delegate {
+ public:
+ Delegate() {}
+
+ // The specified amount of data was read from the pipe. The Delegate should
+ // return net::OK to continue reading, or a value indicating an error if the
+ // pipe should be closed. A return value of net::ERR_IO_PENDING means that
+ // the BodyReader should stop reading, and not call OnDone(), until its
+ // Resume() method is called. Resume() must not be called synchronously.
+ //
+ // It's safe to delete the BodyReader during this call. If that happens,
+ // |data| will still remain valid for the duration of the call, and the
+ // returned net::Error will be ignored.
+ virtual net::Error OnDataRead(uint32_t length, const char* data) = 0;
+
+ // Called when the pipe is closed by the remote size, the size limit is
+ // reached, or OnDataRead returned an error. |error| is net::OK if the
+ // pipe was closed, or an error value otherwise. It is safe to delete the
+ // BodyReader during this callback.
+ virtual void OnDone(net::Error error, int64_t total_bytes) = 0;
+
+ protected:
+ virtual ~Delegate() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Delegate);
+ };
+
+ BodyReader(Delegate* delegate, int64_t max_body_size)
+ : delegate_(delegate),
+ max_body_size_(max_body_size),
+ weak_ptr_factory_(this) {
+ DCHECK_GE(max_body_size_, 0);
+ }
+
+ // Makes the reader start reading from |body_data_pipe|. May only be called
+ // once. The reader will continuously to try to read from the pipe (without
+ // blocking the thread), calling OnDataRead as data is read, until one of the
+ // following happens:
+ // * The size limit is reached.
+ // * OnDataRead returns an error.
+ // * The BodyReader is deleted.
+ void Start(mojo::ScopedDataPipeConsumerHandle body_data_pipe) {
+ DCHECK(!body_data_pipe_.is_valid());
+ body_data_pipe_ = std::move(body_data_pipe);
+ handle_watcher_ = std::make_unique<mojo::SimpleWatcher>(
+ FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::MANUAL);
+ handle_watcher_->Watch(
+ body_data_pipe_.get(),
+ MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_WATCH_CONDITION_SATISFIED,
+ base::BindRepeating(&BodyReader::MojoReadyCallback,
+ base::Unretained(this)));
+ ReadData();
+ }
+
+ void Resume() { ReadData(); }
+
+ private:
+ void MojoReadyCallback(MojoResult result,
+ const mojo::HandleSignalsState& state) {
+ // Shouldn't be watching the pipe when there's a pending error.
+ DCHECK_EQ(net::OK, pending_error_);
+
+ ReadData();
+ }
+
+ // Reads as much data as possible from |body_data_pipe_|, copying it to
+ // |body_|. Arms |handle_watcher_| when data is not currently available.
+ void ReadData() {
+ while (true) {
+ if (pending_error_) {
+ ClosePipe();
+ // This call may delete the BodyReader.
+ delegate_->OnDone(pending_error_, total_bytes_read_);
+ return;
+ }
+
+ const void* body_data;
+ uint32_t read_size;
+ MojoResult result = body_data_pipe_->BeginReadData(
+ &body_data, &read_size, MOJO_READ_DATA_FLAG_NONE);
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ handle_watcher_->ArmOrNotify();
+ return;
+ }
+
+ // If the pipe was closed, unclear if it was an error or success. Notify
+ // the consumer of how much data was received.
+ if (result != MOJO_RESULT_OK) {
+ // The only error other than MOJO_RESULT_SHOULD_WAIT this should fail
+ // with is MOJO_RESULT_FAILED_PRECONDITION, in the case the pipe was
+ // closed.
+ DCHECK_EQ(MOJO_RESULT_FAILED_PRECONDITION, result);
+ ClosePipe();
+
+ // This call may delete the BodyReader.
+ delegate_->OnDone(net::OK, total_bytes_read_);
+ return;
+ }
+
+ // Check size against the limit.
+ uint32_t copy_size = read_size;
+ if (static_cast<int64_t>(copy_size) > max_body_size_ - total_bytes_read_)
+ copy_size = max_body_size_ - total_bytes_read_;
+
+ total_bytes_read_ += copy_size;
+
+ if (copy_size < read_size)
+ pending_error_ = net::ERR_INSUFFICIENT_RESOURCES;
+
+ // Need a weak pointer to |this| to detect deletion.
+ base::WeakPtr<BodyReader> weak_this =
+ this->weak_ptr_factory_.GetWeakPtr();
+ // Need to keep the data pipe alive if |this| is deleted, to keep
+ // |body_data| alive. Also unclear if it's safe to delete while a read is
+ // in progress.
+ mojo::ScopedDataPipeConsumerHandle body_data_pipe =
+ std::move(body_data_pipe_);
+
+ // This call may delete the BodyReader.
+ net::Error error =
+ delegate_->OnDataRead(copy_size, static_cast<const char*>(body_data));
+ body_data_pipe->EndReadData(read_size);
+ if (!weak_this) {
+ // This object was deleted, so nothing else to do.
+ return;
+ }
+
+ body_data_pipe_ = std::move(body_data_pipe);
+
+ // Wait for Resume() on net::ERR_IO_PENDING.
+ if (error == net::ERR_IO_PENDING)
+ return;
+
+ if (error != net::OK)
+ pending_error_ = error;
+ }
+ }
+
+ // Frees Mojo resources and prevents any more Mojo messages from arriving.
+ void ClosePipe() {
+ handle_watcher_.reset();
+ body_data_pipe_.reset();
+ }
+
+ mojo::ScopedDataPipeConsumerHandle body_data_pipe_;
+ std::unique_ptr<mojo::SimpleWatcher> handle_watcher_;
+
+ Delegate* const delegate_;
+
+ const int64_t max_body_size_;
+ int64_t total_bytes_read_ = 0;
+
+ // Set to an error code when Delegate::OnDataRead() returns ERR_IO_PENDING,
+ // and there was a pending error from the BodyReader itself (Generally, length
+ // limit exceeded). When this happens, the error will be passed to the
+ // Delegate only after Resume() is called.
+ net::Error pending_error_ = net::OK;
+
+ base::WeakPtrFactory<BodyReader> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(BodyReader);
+};
+
+// Class to drive the pipe for reading the body, handle the results of the body
+// read as appropriate, and invoke the consumer's callback to notify it of
+// request completion. Implementations typically use a BodyReader to to manage
+// reads from the body data pipe.
+class BodyHandler {
+ public:
+ // A raw pointer is safe, since |simple_url_loader| owns the BodyHandler.
+ explicit BodyHandler(SimpleURLLoaderImpl* simple_url_loader)
+ : simple_url_loader_(simple_url_loader) {}
+ virtual ~BodyHandler() {}
+
+ // Called by SimpleURLLoader with the data pipe received from the URLLoader.
+ // The BodyHandler is responsible for reading from it and monitoring it for
+ // closure. Should call SimpleURLLoaderImpl::OnBodyHandlerDone(), once either
+ // when the body pipe is closed or when an error occurs, like a write to a
+ // file fails.
+ virtual void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body_data_pipe) = 0;
+
+ // Called by SimpleURLLoader. Notifies the SimpleURLLoader's consumer that the
+ // request has completed, either successfully or with an error. May be invoked
+ // before OnStartLoadingResponseBody(), or before the BodyHandler has notified
+ // SimplerURLLoader of completion or an error. Once this is called, the
+ // BodyHandler must not invoke any of SimpleURLLoaderImpl's callbacks. If
+ // |destroy_results| is true, any received data should be destroyed instead of
+ // being sent to the consumer.
+ virtual void NotifyConsumerOfCompletion(bool destroy_results) = 0;
+
+ // Called before retrying a request. Only called either before receiving a
+ // body pipe, or after the body pipe has been closed, so there should be no
+ // pending callbacks when invoked. |retry_callback| should be invoked when
+ // the BodyHandler is ready for the request to be retried. Callback may be
+ // invoked synchronously.
+ virtual void PrepareToRetry(base::OnceClosure retry_callback) = 0;
+
+ protected:
+ SimpleURLLoaderImpl* simple_url_loader() { return simple_url_loader_; }
+
+ private:
+ SimpleURLLoaderImpl* const simple_url_loader_;
+
+ DISALLOW_COPY_AND_ASSIGN(BodyHandler);
+};
+
+// BodyHandler implementation for consuming the response as a string.
+class SaveToStringBodyHandler : public BodyHandler,
+ public BodyReader::Delegate {
+ public:
+ SaveToStringBodyHandler(
+ SimpleURLLoaderImpl* simple_url_loader,
+ SimpleURLLoader::BodyAsStringCallback body_as_string_callback,
+ int64_t max_body_size)
+ : BodyHandler(simple_url_loader),
+ max_body_size_(max_body_size),
+ body_as_string_callback_(std::move(body_as_string_callback)) {}
+
+ ~SaveToStringBodyHandler() override {}
+
+ // BodyHandler implementation:
+
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body_data_pipe) override {
+ DCHECK(!body_);
+ DCHECK(!body_reader_);
+
+ body_ = std::make_unique<std::string>();
+ body_reader_ = std::make_unique<BodyReader>(this, max_body_size_);
+ body_reader_->Start(std::move(body_data_pipe));
+ }
+
+ void NotifyConsumerOfCompletion(bool destroy_results) override {
+ body_reader_.reset();
+ if (destroy_results)
+ body_.reset();
+
+ std::move(body_as_string_callback_).Run(std::move(body_));
+ }
+
+ void PrepareToRetry(base::OnceClosure retry_callback) override {
+ body_.reset();
+ body_reader_.reset();
+ std::move(retry_callback).Run();
+ }
+
+ private:
+ // BodyReader::Delegate implementation.
+
+ net::Error OnDataRead(uint32_t length, const char* data) override {
+ body_->append(data, length);
+ return net::OK;
+ }
+
+ void OnDone(net::Error error, int64_t total_bytes) override {
+ DCHECK_EQ(body_->size(), static_cast<size_t>(total_bytes));
+ simple_url_loader()->OnBodyHandlerDone(error, total_bytes);
+ }
+
+ const int64_t max_body_size_;
+
+ std::unique_ptr<std::string> body_;
+ SimpleURLLoader::BodyAsStringCallback body_as_string_callback_;
+
+ std::unique_ptr<BodyReader> body_reader_;
+
+ DISALLOW_COPY_AND_ASSIGN(SaveToStringBodyHandler);
+};
+
+// BodyHandler implementation for saving the response to a file
+class SaveToFileBodyHandler : public BodyHandler {
+ public:
+ // |net_priority| is the priority from the ResourceRequest, and is used to
+ // determine the TaskPriority of the sequence used to read from the response
+ // body and write to the file. If |create_temp_file| is true, a temp file is
+ // created instead of using |path|.
+ SaveToFileBodyHandler(SimpleURLLoaderImpl* simple_url_loader,
+ SimpleURLLoader::DownloadToFileCompleteCallback
+ download_to_file_complete_callback,
+ const base::FilePath& path,
+ bool create_temp_file,
+ uint64_t max_body_size,
+ base::TaskPriority task_priority)
+ : BodyHandler(simple_url_loader),
+ download_to_file_complete_callback_(
+ std::move(download_to_file_complete_callback)),
+ weak_ptr_factory_(this) {
+ DCHECK(create_temp_file || !path.empty());
+
+ // Can only do this after initializing the WeakPtrFactory.
+ file_writer_ = std::make_unique<FileWriter>(path, create_temp_file,
+ max_body_size, task_priority);
+ }
+
+ ~SaveToFileBodyHandler() override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (file_writer_) {
+ // |file_writer_| is only non-null at this point if any downloaded file
+ // wasn't passed to the consumer. Destroy any partially downloaded file.
+ file_writer_->DeleteFile(base::OnceClosure());
+ FileWriter::Destroy(std::move(file_writer_));
+ }
+ }
+
+ // BodyHandler implementation:
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body_data_pipe) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ file_writer_->StartWriting(std::move(body_data_pipe),
+ base::BindOnce(&SaveToFileBodyHandler::OnDone,
+ weak_ptr_factory_.GetWeakPtr()));
+ }
+
+ void NotifyConsumerOfCompletion(bool destroy_results) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!download_to_file_complete_callback_.is_null());
+
+ if (destroy_results) {
+ // Prevent the FileWriter from calling OnDone().
+ weak_ptr_factory_.InvalidateWeakPtrs();
+
+ // To avoid any issues if the consumer tries to re-download a file to the
+ // same location, don't invoke the callback until any partially downloaded
+ // file has been destroyed.
+ file_writer_->DeleteFile(
+ base::BindOnce(&SaveToFileBodyHandler::InvokeCallbackAsynchronously,
+ weak_ptr_factory_.GetWeakPtr()));
+ FileWriter::Destroy(std::move(file_writer_));
+ return;
+ }
+
+ // Destroy the |file_writer_|, so the file won't be destroyed in |this|'s
+ // destructor.
+ FileWriter::Destroy(std::move(file_writer_));
+
+ std::move(download_to_file_complete_callback_).Run(path_);
+ }
+
+ void PrepareToRetry(base::OnceClosure retry_callback) override {
+ // |file_writer_| is only destroyed when notifying the consumer of
+ // completion and in the destructor. After either of those happens, a
+ // request should not be retried.
+ DCHECK(file_writer_);
+
+ // Delete file and wait for it to be destroyed, so if the retry fails
+ // before trying to create a new file, the consumer will still only be
+ // notified of completion after the file is destroyed.
+ file_writer_->DeleteFile(std::move(retry_callback));
+ }
+
+ private:
+ // Class to read from a mojo::ScopedDataPipeConsumerHandle and write the
+ // contents to a file. Does all reading and writing on a separate file
+ // SequencedTaskRunner. All public methods except the destructor are called on
+ // BodyHandler's TaskRunner. All private methods and the destructor are run
+ // on the file TaskRunner.
+ //
+ // FileWriter is owned by the SaveToFileBodyHandler and destroyed by a task
+ // moving its unique_ptr to the |file_writer_task_runner_|. As a result, tasks
+ // posted to |file_writer_task_runner_| can always use base::Unretained. Tasks
+ // posted the other way, however, require the SaveToFileBodyHandler to use
+ // WeakPtrs, since the SaveToFileBodyHandler can be destroyed at any time.
+ //
+ // When a request is retried, the FileWriter deletes any partially downloaded
+ // file, and is then reused.
+ class FileWriter : public BodyReader::Delegate {
+ public:
+ using OnDoneCallback = base::OnceCallback<void(net::Error error,
+ int64_t total_bytes,
+ const base::FilePath& path)>;
+
+ FileWriter(const base::FilePath& path,
+ bool create_temp_file,
+ int64_t max_body_size,
+ base::TaskPriority priority)
+ : body_handler_task_runner_(base::SequencedTaskRunnerHandle::Get()),
+ file_writer_task_runner_(base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), priority,
+ base::TaskShutdownBehavior::BLOCK_SHUTDOWN})),
+ path_(path),
+ create_temp_file_(create_temp_file),
+ max_body_size_(max_body_size) {
+ DCHECK(body_handler_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(create_temp_file_ || !path_.empty());
+ }
+
+ // Starts reading from |body_data_pipe| and writing to the file.
+ void StartWriting(mojo::ScopedDataPipeConsumerHandle body_data_pipe,
+ OnDoneCallback on_done_callback) {
+ DCHECK(body_handler_task_runner_->RunsTasksInCurrentSequence());
+ file_writer_task_runner_->PostTask(
+ FROM_HERE,
+ base::BindOnce(&FileWriter::StartWritingOnFileSequence,
+ base::Unretained(this), std::move(body_data_pipe),
+ std::move(on_done_callback)));
+ }
+
+ // Deletes any partially downloaded file, and closes the body pipe, if open.
+ // Must be called if SaveToFileBodyHandler's OnDone() method is never
+ // invoked, to avoid keeping around partial downloads that were never passed
+ // to the consumer.
+ //
+ // If |on_file_deleted_closure| is non-null, it will be invoked on the
+ // caller's task runner once the file has been deleted.
+ void DeleteFile(base::OnceClosure on_file_deleted_closure) {
+ DCHECK(body_handler_task_runner_->RunsTasksInCurrentSequence());
+ file_writer_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(&FileWriter::DeleteFileOnFileSequence,
+ base::Unretained(this),
+ std::move(on_file_deleted_closure)));
+ }
+
+ // Destroys the FileWriter on the file TaskRunner.
+ static void Destroy(std::unique_ptr<FileWriter> file_writer) {
+ DCHECK(
+ file_writer->body_handler_task_runner_->RunsTasksInCurrentSequence());
+
+ // Have to stash this pointer before posting a task, since |file_writer|
+ // is bound to the callback that's posted to the TaskRunner.
+ base::SequencedTaskRunner* task_runner =
+ file_writer->file_writer_task_runner_.get();
+ task_runner->DeleteSoon(FROM_HERE, std::move(file_writer));
+ }
+
+ // Destructor is only public so the consumer can keep it in a unique_ptr.
+ // Class must be destroyed by using Destroy().
+ ~FileWriter() override {
+ DCHECK(file_writer_task_runner_->RunsTasksInCurrentSequence());
+ }
+
+ private:
+ void StartWritingOnFileSequence(
+ mojo::ScopedDataPipeConsumerHandle body_data_pipe,
+ OnDoneCallback on_done_callback) {
+ DCHECK(file_writer_task_runner_->RunsTasksInCurrentSequence());
+ DCHECK(!file_.IsValid());
+ DCHECK(!body_reader_);
+
+ bool have_path = !create_temp_file_;
+ if (!have_path) {
+ DCHECK(create_temp_file_);
+ have_path = base::CreateTemporaryFile(&path_);
+ // CreateTemporaryFile() creates an empty file.
+ if (have_path)
+ owns_file_ = true;
+ }
+
+ if (have_path) {
+ // Try to initialize |file_|, creating the file if needed.
+ file_.Initialize(
+ path_, base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS);
+ }
+
+ // If CreateTemporaryFile() or File::Initialize() failed, report failure.
+ if (!file_.IsValid()) {
+ body_handler_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(std::move(on_done_callback),
+ net::MapSystemError(
+ logging::GetLastSystemErrorCode()),
+ 0, base::FilePath()));
+ return;
+ }
+
+ on_done_callback_ = std::move(on_done_callback);
+ owns_file_ = true;
+ body_reader_ = std::make_unique<BodyReader>(this, max_body_size_);
+ body_reader_->Start(std::move(body_data_pipe));
+ }
+
+ // BodyReader::Delegate implementation:
+ net::Error OnDataRead(uint32_t length, const char* data) override {
+ DCHECK(file_writer_task_runner_->RunsTasksInCurrentSequence());
+ while (length > 0) {
+ int written = file_.WriteAtCurrentPos(
+ data, std::min(length, static_cast<uint32_t>(
+ std::numeric_limits<int>::max())));
+ if (written < 0)
+ return net::MapSystemError(logging::GetLastSystemErrorCode());
+ length -= written;
+ data += written;
+ }
+
+ return net::OK;
+ }
+
+ void OnDone(net::Error error, int64_t total_bytes) override {
+ DCHECK(file_writer_task_runner_->RunsTasksInCurrentSequence());
+ // This should only be called if the file was successfully created.
+ DCHECK(file_.IsValid());
+
+ // Close the file so that there's no ownership contention when the
+ // consumer uses it.
+ file_.Close();
+ body_reader_.reset();
+
+ body_handler_task_runner_->PostTask(
+ FROM_HERE, base::BindOnce(std::move(on_done_callback_), error,
+ total_bytes, path_));
+ }
+
+ void DeleteFileOnFileSequence(base::OnceClosure on_file_deleted_closure) {
+ DCHECK(file_writer_task_runner_->RunsTasksInCurrentSequence());
+
+ if (owns_file_) {
+ // Close the file before deleting it, if it's still open.
+ file_.Close();
+
+ // Close the body pipe.
+ body_reader_.reset();
+
+ // May as well clean this up, too.
+ on_done_callback_.Reset();
+
+ DCHECK(!path_.empty());
+ base::DeleteFile(path_, false /* recursive */);
+
+ owns_file_ = false;
+ }
+
+ if (on_file_deleted_closure) {
+ body_handler_task_runner_->PostTask(FROM_HERE,
+ std::move(on_file_deleted_closure));
+ }
+ }
+
+ // These are set on cosntruction and accessed on both task runners.
+ const scoped_refptr<base::SequencedTaskRunner> body_handler_task_runner_;
+ const scoped_refptr<base::SequencedTaskRunner> file_writer_task_runner_;
+
+ // After construction, all other values are only read and written on the
+ // |file_writer_task_runner_|.
+
+ base::FilePath path_;
+ const bool create_temp_file_;
+ const int64_t max_body_size_;
+
+ // File being downloaded to. Created just before reading from the data pipe.
+ base::File file_;
+
+ OnDoneCallback on_done_callback_;
+
+ std::unique_ptr<BodyReader> body_reader_;
+
+ // True if a file was successfully created. Set to false when the file is
+ // destroyed.
+ bool owns_file_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(FileWriter);
+ };
+
+ // Called by FileWriter::Destroy after deleting a partially downloaded file.
+ void InvokeCallbackAsynchronously() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ std::move(download_to_file_complete_callback_).Run(base::FilePath());
+ }
+
+ void OnDone(net::Error error,
+ int64_t total_bytes,
+ const base::FilePath& path) {
+ path_ = path;
+ simple_url_loader()->OnBodyHandlerDone(error, total_bytes);
+ }
+
+ // Path of the file. Set in OnDone().
+ base::FilePath path_;
+
+ SimpleURLLoader::DownloadToFileCompleteCallback
+ download_to_file_complete_callback_;
+
+ std::unique_ptr<FileWriter> file_writer_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ base::WeakPtrFactory<SaveToFileBodyHandler> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SaveToFileBodyHandler);
+};
+
+// Class to handle streaming data to the consumer as it arrives
+class DownloadAsStreamBodyHandler : public BodyHandler,
+ public BodyReader::Delegate {
+ public:
+ DownloadAsStreamBodyHandler(SimpleURLLoaderImpl* simple_url_loader,
+ SimpleURLLoaderStreamConsumer* stream_consumer)
+ : BodyHandler(simple_url_loader),
+ stream_consumer_(stream_consumer),
+ weak_ptr_factory_(this) {}
+
+ ~DownloadAsStreamBodyHandler() override {}
+
+ // BodyHandler implementation:
+
+ void OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body_data_pipe) override {
+ DCHECK(!body_reader_);
+
+ body_reader_ =
+ std::make_unique<BodyReader>(this, std::numeric_limits<int64_t>::max());
+ body_reader_->Start(std::move(body_data_pipe));
+ }
+
+ void NotifyConsumerOfCompletion(bool destroy_results) override {
+ body_reader_.reset();
+ stream_consumer_->OnComplete(simple_url_loader()->NetError() == net::OK);
+ }
+
+ void PrepareToRetry(base::OnceClosure retry_callback) override {
+ body_reader_.reset();
+ stream_consumer_->OnRetry(std::move(retry_callback));
+ }
+
+ private:
+ // BodyReader::Delegate implementation.
+
+ net::Error OnDataRead(uint32_t length, const char* data) override {
+ in_recursive_call_ = true;
+ base::WeakPtr<DownloadAsStreamBodyHandler> weak_this(
+ weak_ptr_factory_.GetWeakPtr());
+ stream_consumer_->OnDataReceived(
+ base::StringPiece(data, length),
+ base::BindOnce(&DownloadAsStreamBodyHandler::Resume,
+ weak_ptr_factory_.GetWeakPtr()));
+ // Protect against deletion.
+ if (weak_this)
+ in_recursive_call_ = false;
+ return net::ERR_IO_PENDING;
+ }
+
+ void OnDone(net::Error error, int64_t total_bytes) override {
+ simple_url_loader()->OnBodyHandlerDone(error, total_bytes);
+ }
+
+ void Resume() {
+ // Can't call DownloadAsStreamBodyHandler::Resume() immediately when called
+ // recursively from OnDataRead.
+ if (in_recursive_call_) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&DownloadAsStreamBodyHandler::Resume,
+ weak_ptr_factory_.GetWeakPtr()));
+ return;
+ }
+ body_reader_->Resume();
+ }
+
+ SimpleURLLoaderStreamConsumer* stream_consumer_;
+
+ std::unique_ptr<BodyReader> body_reader_;
+
+ bool in_recursive_call_ = false;
+
+ base::WeakPtrFactory<DownloadAsStreamBodyHandler> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DownloadAsStreamBodyHandler);
+};
+
+SimpleURLLoaderImpl::SimpleURLLoaderImpl(
+ std::unique_ptr<ResourceRequest> resource_request,
+ const net::NetworkTrafficAnnotationTag& annotation_tag)
+ : resource_request_(std::move(resource_request)),
+ annotation_tag_(annotation_tag),
+ client_binding_(this),
+ request_state_(std::make_unique<RequestState>()),
+ final_url_(resource_request_->url),
+ weak_ptr_factory_(this) {
+ // Allow creation and use on different threads.
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+#if DCHECK_IS_ON()
+ if (resource_request_->request_body) {
+ for (const DataElement& element :
+ *resource_request_->request_body->elements()) {
+ // Files should be attached with AttachFileForUpload, so that (Once
+ // supported) they can be opened in the current process.
+ //
+ // TODO(mmenke): Add a similar method for bytes, to allow streaming of
+ // large byte buffers to the network process when uploading.
+ DCHECK(element.type() != DataElement::TYPE_FILE &&
+ element.type() != DataElement::TYPE_BYTES);
+ }
+ }
+#endif // DCHECK_IS_ON()
+}
+
+SimpleURLLoaderImpl::~SimpleURLLoaderImpl() {}
+
+void SimpleURLLoaderImpl::DownloadToString(
+ mojom::URLLoaderFactory* url_loader_factory,
+ BodyAsStringCallback body_as_string_callback,
+ size_t max_body_size) {
+ DCHECK_LE(max_body_size, kMaxBoundedStringDownloadSize);
+ body_handler_ = std::make_unique<SaveToStringBodyHandler>(
+ this, std::move(body_as_string_callback), max_body_size);
+ Start(url_loader_factory);
+}
+
+void SimpleURLLoaderImpl::DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+ mojom::URLLoaderFactory* url_loader_factory,
+ BodyAsStringCallback body_as_string_callback) {
+ body_handler_ = std::make_unique<SaveToStringBodyHandler>(
+ this, std::move(body_as_string_callback),
+ // int64_t because URLLoaderCompletionStatus::decoded_body_length
+ // is an int64_t, not a size_t.
+ std::numeric_limits<int64_t>::max());
+ Start(url_loader_factory);
+}
+
+void SimpleURLLoaderImpl::DownloadToFile(
+ mojom::URLLoaderFactory* url_loader_factory,
+ DownloadToFileCompleteCallback download_to_file_complete_callback,
+ const base::FilePath& file_path,
+ int64_t max_body_size) {
+ DCHECK(!file_path.empty());
+ body_handler_ = std::make_unique<SaveToFileBodyHandler>(
+ this, std::move(download_to_file_complete_callback), file_path,
+ false /* create_temp_file */, max_body_size, GetTaskPriority());
+ Start(url_loader_factory);
+}
+
+void SimpleURLLoaderImpl::DownloadToTempFile(
+ mojom::URLLoaderFactory* url_loader_factory,
+ DownloadToFileCompleteCallback download_to_file_complete_callback,
+ int64_t max_body_size) {
+ body_handler_ = std::make_unique<SaveToFileBodyHandler>(
+ this, std::move(download_to_file_complete_callback), base::FilePath(),
+ true /* create_temp_file */, max_body_size, GetTaskPriority());
+ Start(url_loader_factory);
+}
+
+void SimpleURLLoaderImpl::DownloadAsStream(
+ mojom::URLLoaderFactory* url_loader_factory,
+ SimpleURLLoaderStreamConsumer* stream_consumer) {
+ body_handler_ =
+ std::make_unique<DownloadAsStreamBodyHandler>(this, stream_consumer);
+ Start(url_loader_factory);
+}
+
+void SimpleURLLoaderImpl::SetOnRedirectCallback(
+ const OnRedirectCallback& on_redirect_callback) {
+ on_redirect_callback_ = on_redirect_callback;
+}
+
+void SimpleURLLoaderImpl::SetOnResponseStartedCallback(
+ const OnResponseStartedCallback& on_response_started_callback) {
+ on_response_started_callback_ = on_response_started_callback;
+}
+
+void SimpleURLLoaderImpl::SetAllowPartialResults(bool allow_partial_results) {
+ // Check if a request has not yet been started.
+ DCHECK(!body_handler_);
+ allow_partial_results_ = allow_partial_results;
+}
+
+void SimpleURLLoaderImpl::SetAllowHttpErrorResults(
+ bool allow_http_error_results) {
+ // Check if a request has not yet been started.
+ DCHECK(!body_handler_);
+ allow_http_error_results_ = allow_http_error_results;
+}
+
+void SimpleURLLoaderImpl::AttachStringForUpload(
+ const std::string& upload_data,
+ const std::string& upload_content_type) {
+ // Currently only allow a single string to be attached.
+ DCHECK(!resource_request_->request_body);
+ DCHECK(resource_request_->method != "GET" &&
+ resource_request_->method != "HEAD");
+
+ resource_request_->request_body = new ResourceRequestBody();
+
+ if (upload_data.length() <= kMaxUploadStringSizeToCopy) {
+ int copy_length = static_cast<int>(upload_data.length());
+ DCHECK_EQ(static_cast<size_t>(copy_length), upload_data.length());
+ resource_request_->request_body->AppendBytes(upload_data.c_str(),
+ copy_length);
+ } else {
+ // Don't attach the upload body here. A new pipe will need to be created
+ // each time the request is tried.
+ string_upload_data_pipe_getter_ =
+ std::make_unique<StringUploadDataPipeGetter>(upload_data);
+ }
+
+ resource_request_->headers.SetHeader(net::HttpRequestHeaders::kContentType,
+ upload_content_type);
+}
+
+void SimpleURLLoaderImpl::AttachFileForUpload(
+ const base::FilePath& upload_file_path,
+ const std::string& upload_content_type) {
+ DCHECK(!upload_file_path.empty());
+
+ // Currently only allow a single file to be attached.
+ DCHECK(!resource_request_->request_body);
+ DCHECK(resource_request_->method != "GET" &&
+ resource_request_->method != "HEAD");
+
+ // Create an empty body to make DCHECKing that there's no upload body yet
+ // simpler.
+ resource_request_->request_body = new ResourceRequestBody();
+ // TODO(mmenke): Open the file in the current process and append the file
+ // handle instead of the file path.
+ resource_request_->request_body->AppendFileRange(
+ upload_file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
+
+ resource_request_->headers.SetHeader(net::HttpRequestHeaders::kContentType,
+ upload_content_type);
+}
+
+void SimpleURLLoaderImpl::SetRetryOptions(int max_retries, int retry_mode) {
+ // Check if a request has not yet been started.
+ DCHECK(!body_handler_);
+ DCHECK_GE(max_retries, 0);
+ // Non-zero |max_retries| makes no sense when retries are disabled.
+ DCHECK(max_retries > 0 || retry_mode == RETRY_NEVER);
+
+ remaining_retries_ = max_retries;
+ retry_mode_ = retry_mode;
+
+#if DCHECK_IS_ON()
+ if (max_retries > 0 && resource_request_->request_body) {
+ for (const DataElement& element :
+ *resource_request_->request_body->elements()) {
+ // Data pipes are single-use, so can't retry uploads when there's a data
+ // pipe.
+ // TODO(mmenke): Data pipes can be Cloned(), though, so maybe update code
+ // to do that?
+ DCHECK(element.type() != DataElement::TYPE_DATA_PIPE);
+ }
+ }
+#endif // DCHECK_IS_ON()
+}
+
+int SimpleURLLoaderImpl::NetError() const {
+ // Should only be called once the request is compelete.
+ DCHECK(request_state_->finished);
+ DCHECK_NE(net::ERR_IO_PENDING, request_state_->net_error);
+ return request_state_->net_error;
+}
+
+const GURL& SimpleURLLoaderImpl::GetFinalURL() const {
+ // Should only be called once the request is compelete.
+ DCHECK(request_state_->finished);
+ return final_url_;
+}
+
+const ResourceResponseHead* SimpleURLLoaderImpl::ResponseInfo() const {
+ // Should only be called once the request is compelete.
+ DCHECK(request_state_->finished);
+ return request_state_->response_info.get();
+}
+
+void SimpleURLLoaderImpl::OnBodyHandlerDone(net::Error error,
+ int64_t received_body_size) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(request_state_->body_started);
+ DCHECK(!request_state_->body_completed);
+
+ // If there's an error, fail request and report it immediately.
+ if (error != net::OK) {
+ FinishWithResult(error);
+ return;
+ }
+
+ // Otherwise, need to wait until the URLRequestClient pipe receives a complete
+ // message or is closed, to determine if the entire body was received.
+ request_state_->body_completed = true;
+ request_state_->received_body_size = received_body_size;
+ MaybeComplete();
+}
+
+void SimpleURLLoaderImpl::FinishWithResult(int net_error) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(!request_state_->finished);
+
+ client_binding_.Close();
+ url_loader_.reset();
+
+ request_state_->finished = true;
+ request_state_->net_error = net_error;
+ // If it's a partial download or an error was received, erase the body.
+ bool destroy_results =
+ request_state_->net_error != net::OK && !allow_partial_results_;
+ body_handler_->NotifyConsumerOfCompletion(destroy_results);
+}
+
+void SimpleURLLoaderImpl::Start(mojom::URLLoaderFactory* url_loader_factory) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(resource_request_);
+ // It's illegal to use a single SimpleURLLoaderImpl to make multiple requests.
+ DCHECK(!request_state_->finished);
+ DCHECK(!url_loader_);
+ DCHECK(!request_state_->body_started);
+
+ // If retries are enabled, stash the information needed to retry a request.
+ if (remaining_retries_ > 0) {
+ // Clone the URLLoaderFactory, to avoid any dependencies on its lifetime.
+ // Results in an easier to use API, with no shutdown ordering requirements,
+ // at the cost of some resources.
+ url_loader_factory->Clone(mojo::MakeRequest(&url_loader_factory_ptr_));
+ }
+
+ StartRequest(url_loader_factory);
+}
+
+void SimpleURLLoaderImpl::StartRequest(
+ mojom::URLLoaderFactory* url_loader_factory) {
+ DCHECK(resource_request_);
+ DCHECK(url_loader_factory);
+
+ mojom::URLLoaderClientPtr client_ptr;
+ client_binding_.Bind(mojo::MakeRequest(&client_ptr));
+ client_binding_.set_connection_error_handler(base::BindOnce(
+ &SimpleURLLoaderImpl::OnConnectionError, base::Unretained(this)));
+ // Data elements that use pipes aren't reuseable, currently (Since the IPC
+ // code doesn't call the Clone() method), so need to create another one, if
+ // uploading a string via a data pipe.
+ if (string_upload_data_pipe_getter_) {
+ resource_request_->request_body = new ResourceRequestBody();
+ mojom::DataPipeGetterPtr data_pipe_getter;
+ resource_request_->request_body->AppendDataPipe(
+ string_upload_data_pipe_getter_->GetPtrForNewUpload());
+ }
+ url_loader_factory->CreateLoaderAndStart(
+ mojo::MakeRequest(&url_loader_), 0 /* routing_id */, 0 /* request_id */,
+ 0 /* options */, *resource_request_, std::move(client_ptr),
+ net::MutableNetworkTrafficAnnotationTag(annotation_tag_));
+
+ // If no more retries left, can clean up a little.
+ if (remaining_retries_ == 0) {
+ resource_request_.reset();
+ url_loader_factory_ptr_.reset();
+ }
+}
+
+void SimpleURLLoaderImpl::Retry() {
+ DCHECK(resource_request_);
+ DCHECK(url_loader_factory_ptr_);
+ DCHECK_GT(remaining_retries_, 0);
+ --remaining_retries_;
+
+ client_binding_.Close();
+ url_loader_.reset();
+
+ request_state_ = std::make_unique<RequestState>();
+
+ body_handler_->PrepareToRetry(base::BindOnce(
+ &SimpleURLLoaderImpl::StartRequest, weak_ptr_factory_.GetWeakPtr(),
+ url_loader_factory_ptr_.get()));
+}
+
+void SimpleURLLoaderImpl::OnReceiveResponse(
+ const ResourceResponseHead& response_head,
+ const base::Optional<net::SSLInfo>& ssl_info,
+ mojom::DownloadedTempFilePtr downloaded_file) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (request_state_->response_info) {
+ // The final headers have already been received, so the URLLoader is
+ // violating the API contract.
+ FinishWithResult(net::ERR_UNEXPECTED);
+ return;
+ }
+
+ // Assume a 200 response unless headers were received indicating otherwise.
+ // No headers indicates this was not a real HTTP response (Could be a file
+ // URL, FTP, response could have been provided by something else, etc).
+ int response_code = 200;
+ if (response_head.headers)
+ response_code = response_head.headers->response_code();
+
+ // If a 5xx response was received, and |this| should retry on 5xx errors,
+ // retry the request.
+ if (response_code / 100 == 5 && remaining_retries_ > 0 &&
+ (retry_mode_ & RETRY_ON_5XX)) {
+ Retry();
+ return;
+ }
+
+ if (on_response_started_callback_) {
+ base::WeakPtr<SimpleURLLoaderImpl> weak_this =
+ weak_ptr_factory_.GetWeakPtr();
+ // Copy |final_url_| to a stack allocated GURL so it remains valid even if
+ // the callback deletes |this|.
+ GURL final_url = final_url_;
+ on_response_started_callback_.Run(final_url, response_head);
+ // If deleted by the callback, bail now.
+ if (!weak_this)
+ return;
+ }
+
+ request_state_->response_info =
+ std::make_unique<ResourceResponseHead>(response_head);
+ if (!allow_http_error_results_ && response_code / 100 != 2)
+ FinishWithResult(net::ERR_FAILED);
+}
+
+void SimpleURLLoaderImpl::OnReceiveRedirect(
+ const net::RedirectInfo& redirect_info,
+ const ResourceResponseHead& response_head) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (request_state_->response_info) {
+ // If the headers have already been received, the URLLoader is violating the
+ // API contract.
+ FinishWithResult(net::ERR_UNEXPECTED);
+ return;
+ }
+
+ if (on_redirect_callback_) {
+ base::WeakPtr<SimpleURLLoaderImpl> weak_this =
+ weak_ptr_factory_.GetWeakPtr();
+ on_redirect_callback_.Run(redirect_info, response_head);
+ // If deleted by the callback, bail now.
+ if (!weak_this)
+ return;
+ }
+
+ final_url_ = redirect_info.new_url;
+ url_loader_->FollowRedirect();
+}
+
+void SimpleURLLoaderImpl::OnDataDownloaded(int64_t data_length,
+ int64_t encoded_length) {
+ NOTIMPLEMENTED();
+}
+
+void SimpleURLLoaderImpl::OnReceiveCachedMetadata(
+ const std::vector<uint8_t>& data) {
+ NOTREACHED();
+}
+
+void SimpleURLLoaderImpl::OnTransferSizeUpdated(int32_t transfer_size_diff) {}
+
+void SimpleURLLoaderImpl::OnUploadProgress(
+ int64_t current_position,
+ int64_t total_size,
+ OnUploadProgressCallback ack_callback) {}
+
+void SimpleURLLoaderImpl::OnStartLoadingResponseBody(
+ mojo::ScopedDataPipeConsumerHandle body) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (request_state_->body_started || !request_state_->response_info) {
+ // If this was already called, or the headers have not yet been received,
+ // the URLLoader is violating the API contract.
+ FinishWithResult(net::ERR_UNEXPECTED);
+ return;
+ }
+ request_state_->body_started = true;
+ body_handler_->OnStartLoadingResponseBody(std::move(body));
+}
+
+void SimpleURLLoaderImpl::OnComplete(const URLLoaderCompletionStatus& status) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Request should not have been completed yet.
+ DCHECK(!request_state_->finished);
+ DCHECK(!request_state_->request_completed);
+
+ // Close pipes to ignore any subsequent close notification.
+ client_binding_.Close();
+ url_loader_.reset();
+
+ request_state_->request_completed = true;
+ request_state_->expected_body_size = status.decoded_body_length;
+ request_state_->net_error = status.error_code;
+ // If |status| indicates success, but the body pipe was never received, the
+ // URLLoader is violating the API contract.
+ if (request_state_->net_error == net::OK && !request_state_->body_started)
+ request_state_->net_error = net::ERR_UNEXPECTED;
+
+ MaybeComplete();
+}
+
+void SimpleURLLoaderImpl::OnConnectionError() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // |this| closes the pipe to the URLLoader in OnComplete(), so this method
+ // being called indicates the pipe was closed before completion, most likely
+ // due to peer death, or peer not calling OnComplete() on cancellation.
+
+ // Request should not have been completed yet.
+ DCHECK(!request_state_->finished);
+ DCHECK(!request_state_->request_completed);
+ DCHECK_EQ(net::ERR_IO_PENDING, request_state_->net_error);
+
+ request_state_->request_completed = true;
+ request_state_->net_error = net::ERR_FAILED;
+ // Wait to receive any pending data on the data pipe before reporting the
+ // failure.
+ MaybeComplete();
+}
+
+void SimpleURLLoaderImpl::MaybeComplete() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ // Request should not have completed yet.
+ DCHECK(!request_state_->finished);
+
+ // Make sure the URLLoader's pipe has been closed.
+ if (!request_state_->request_completed)
+ return;
+
+ // Make sure the body pipe either was never opened or has been closed. Even if
+ // the request failed, if allow_partial_results_ is true, may still be able to
+ // read more data.
+ if (request_state_->body_started && !request_state_->body_completed)
+ return;
+
+ // Retry on network change errors. Waiting for body complete isn't strictly
+ // necessary, but it guarantees a consistent situation, with no reads pending
+ // on the body pipe.
+ if (request_state_->net_error == net::ERR_NETWORK_CHANGED &&
+ remaining_retries_ > 0 && (retry_mode_ & RETRY_ON_NETWORK_CHANGE)) {
+ Retry();
+ return;
+ }
+
+ // When OnCompleted sees a success result, still need to report an error if
+ // the size isn't what was expected.
+ if (request_state_->net_error == net::OK &&
+ request_state_->expected_body_size !=
+ request_state_->received_body_size) {
+ if (request_state_->expected_body_size >
+ request_state_->received_body_size) {
+ // The body pipe was closed before it received the entire body.
+ request_state_->net_error = net::ERR_FAILED;
+ } else {
+ // The caller provided more data through the pipe than it reported in
+ // URLLoaderCompletionStatus, so the URLLoader is violating the
+ // API contract. Just fail the request.
+ request_state_->net_error = net::ERR_UNEXPECTED;
+ }
+ }
+
+ FinishWithResult(request_state_->net_error);
+}
+
+} // namespace
+
+std::unique_ptr<SimpleURLLoader> SimpleURLLoader::Create(
+ std::unique_ptr<ResourceRequest> resource_request,
+ const net::NetworkTrafficAnnotationTag& annotation_tag) {
+ DCHECK(resource_request);
+ return std::make_unique<SimpleURLLoaderImpl>(std::move(resource_request),
+ annotation_tag);
+}
+
+SimpleURLLoader::~SimpleURLLoader() {}
+
+SimpleURLLoader::SimpleURLLoader() {}
+
+} // namespace network
diff --git a/chromium/services/network/public/cpp/simple_url_loader.h b/chromium/services/network/public/cpp/simple_url_loader.h
new file mode 100644
index 00000000000..c062a6b5233
--- /dev/null
+++ b/chromium/services/network/public/cpp/simple_url_loader.h
@@ -0,0 +1,279 @@
+// 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 SERVICES_NETWORK_PUBLIC_CPP_SIMPLE_URL_LOADER_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_SIMPLE_URL_LOADER_H_
+
+#include <stdint.h>
+
+#include <limits>
+#include <memory>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+
+class GURL;
+
+namespace base {
+class FilePath;
+}
+
+namespace net {
+struct NetworkTrafficAnnotationTag;
+struct RedirectInfo;
+} // namespace net
+
+namespace network {
+struct ResourceRequest;
+struct ResourceResponseHead;
+namespace mojom {
+class URLLoaderFactory;
+}
+} // namespace network
+
+namespace network {
+
+class SimpleURLLoaderStreamConsumer;
+
+// Creates and wraps a URLLoader, and runs it to completion. It's recommended
+// that consumers use this class instead of URLLoader directly, due to the
+// complexity of the API.
+//
+// Deleting a SimpleURLLoader before it completes cancels the requests and frees
+// any resources it is using (including any partially downloaded files).
+//
+// Each SimpleURLLoader can only be used for a single request.
+//
+// TODO(mmenke): Support the following:
+// * Consumer-provided methods to receive streaming (with backpressure).
+// * Uploads (Fixed strings, files, data streams (with backpressure), chunked
+// uploads). ResourceRequest may already have some support, but should make it
+// simple.
+// * Maybe some sort of retry backoff or delay? ServiceURLLoaderContext enables
+// throttling for its URLFetchers. Could additionally/alternatively support
+// 503 + Retry-After.
+class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader {
+ public:
+ // When a failed request should automatically be retried. These are intended
+ // to be ORed together.
+ enum RetryMode {
+ RETRY_NEVER = 0x0,
+ // Retries whenever the server returns a 5xx response code.
+ RETRY_ON_5XX = 0x1,
+ // Retries on net::ERR_NETWORK_CHANGED.
+ RETRY_ON_NETWORK_CHANGE = 0x2,
+ };
+
+ // The maximum size DownloadToString will accept.
+ static const size_t kMaxBoundedStringDownloadSize;
+
+ // Maximum upload body size to send as a block to the URLLoaderFactory. This
+ // data may appear in memory twice for a while, in the retry case, and there
+ // may briefly be 3 to 5 copies as it's copied over the Mojo pipe: This
+ // class's copy (with retries enabled), the source mojo pipe's input copy, the
+ // copy on the IPC buffer, the destination mojo pipe's copy, and the network
+ // service's copy.
+ //
+ // Only exposed for tests.
+ static const size_t kMaxUploadStringSizeToCopy;
+
+ // Callback used when downloading the response body as a std::string.
+ // |response_body| is the body of the response, or nullptr on failure.
+ using BodyAsStringCallback =
+ base::OnceCallback<void(std::unique_ptr<std::string> response_body)>;
+
+ // Callback used when download the response body to a file. On failure, |path|
+ // will be empty.
+ using DownloadToFileCompleteCallback =
+ base::OnceCallback<void(const base::FilePath& path)>;
+
+ // Callback used when a redirect is being followed. It is safe to delete the
+ // SimpleURLLoader during the callback.
+ using OnRedirectCallback =
+ base::RepeatingCallback<void(const net::RedirectInfo& redirect_info,
+ const ResourceResponseHead& response_head)>;
+
+ // Callback used when a redirect is being followed. It is safe to delete the
+ // SimpleURLLoader during the callback.
+ using OnResponseStartedCallback =
+ base::RepeatingCallback<void(const GURL& final_url,
+ const ResourceResponseHead& response_head)>;
+
+ // Creates a SimpleURLLoader for |resource_request|. The request can be
+ // started by calling any one of the Download methods once. The loader may not
+ // be reused.
+ static std::unique_ptr<SimpleURLLoader> Create(
+ std::unique_ptr<ResourceRequest> resource_request,
+ const net::NetworkTrafficAnnotationTag& annotation_tag);
+
+ virtual ~SimpleURLLoader();
+
+ // Starts the request using |network_context|. The SimpleURLLoader will
+ // accumulate all downloaded data in an in-memory string of bounded size. If
+ // |max_body_size| is exceeded, the request will fail with
+ // net::ERR_INSUFFICIENT_RESOURCES. |max_body_size| must be no greater than 1
+ // MiB. For anything larger, it's recommended to either save to a temp file,
+ // or consume the data as it is received.
+ //
+ // Whether the request succeeds or fails, the URLLoaderFactory pipe is closed,
+ // or the body exceeds |max_body_size|, |body_as_string_callback| will be
+ // invoked on completion. Deleting the SimpleURLLoader before the callback is
+ // invoked will result in cancelling the request, and the callback will not be
+ // called.
+ virtual void DownloadToString(mojom::URLLoaderFactory* url_loader_factory,
+ BodyAsStringCallback body_as_string_callback,
+ size_t max_body_size) = 0;
+
+ // Same as DownloadToString, but downloads to a buffer of unbounded size,
+ // potentially causing a crash if the amount of addressable memory is
+ // exceeded. It's recommended consumers use one of the other download methods
+ // instead (DownloadToString if the body is expected to be of reasonable
+ // length, or DownloadToFile otherwise).
+ virtual void DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+ mojom::URLLoaderFactory* url_loader_factory,
+ BodyAsStringCallback body_as_string_callback) = 0;
+
+ // SimpleURLLoader will download the entire response to a file at the
+ // specified path. File I/O will happen on another sequence, so it's safe to
+ // use this on any sequence.
+ //
+ // If there's a file, network, Mojo, or http error, or the max limit
+ // is exceeded, the file will be automatically destroyed before the callback
+ // is invoked and en empty path passed to the callback, unless
+ // SetAllowPartialResults() and/or SetAllowHttpErrorResults() were used to
+ // indicate partial results are allowed.
+ //
+ // If the SimpleURLLoader is destroyed before it has invoked the callback, the
+ // downloaded file will be deleted asynchronously and the callback will not be
+ // invoked, regardless of other settings.
+ virtual void DownloadToFile(
+ mojom::URLLoaderFactory* url_loader_factory,
+ DownloadToFileCompleteCallback download_to_file_complete_callback,
+ const base::FilePath& file_path,
+ int64_t max_body_size = std::numeric_limits<int64_t>::max()) = 0;
+
+ // Same as DownloadToFile, but creates a temporary file instead of taking a
+ // FilePath.
+ virtual void DownloadToTempFile(
+ mojom::URLLoaderFactory* url_loader_factory,
+ DownloadToFileCompleteCallback download_to_file_complete_callback,
+ int64_t max_body_size = std::numeric_limits<int64_t>::max()) = 0;
+
+ // SimpleURLLoader will stream the response body to
+ // SimpleURLLoaderStreamConsumer on the current thread. Destroying the
+ // SimpleURLLoader will cancel the request, and prevent any subsequent
+ // methods from being invoked on the Handler. The SimpleURLLoader may also be
+ // destroyed in any of the Handler's callbacks.
+ //
+ // |stream_handler| must remain valid until either the SimpleURLLoader is
+ // deleted, or the handler's OnComplete() method has been invoked by the
+ // SimpleURLLoader.
+ virtual void DownloadAsStream(
+ mojom::URLLoaderFactory* url_loader_factory,
+ SimpleURLLoaderStreamConsumer* stream_consumer) = 0;
+
+ // Sets callback to be invoked during redirects. Callback may delete the
+ // SimpleURLLoader.
+ virtual void SetOnRedirectCallback(
+ const OnRedirectCallback& on_redirect_callback) = 0;
+
+ // Sets callback to be invoked when the response has started. May be called
+ // multiple times if retries are enabled.
+ // Callback may delete the SimpleURLLoader.
+ virtual void SetOnResponseStartedCallback(
+ const OnResponseStartedCallback& on_response_started_callback) = 0;
+
+ // Sets whether partially received results are allowed. Defaults to false.
+ // When true, if an error is received after reading the body starts or the max
+ // allowed body size exceeded, the partial response body that was received
+ // will be provided to the caller. The partial response body may be an empty
+ // string.
+ //
+ // When downloading as a stream, this has no observable effect.
+ //
+ // May only be called before the request is started.
+ virtual void SetAllowPartialResults(bool allow_partial_results) = 0;
+
+ // Sets whether bodies of non-2xx responses are returned. May only be called
+ // before the request is started.
+ //
+ // When false, if a non-2xx result is received (Other than a redirect), the
+ // request will fail with net::FAILED without waiting to read the response
+ // body, though headers will be accessible through response_info().
+ //
+ // When true, non-2xx responses are treated no differently than other
+ // responses, so their response body is returned just as with any other
+ // response code, and when they complete, net_error() will return net::OK, if
+ // no other problem occurs.
+ //
+ // Defaults to false.
+ // TODO(mmenke): Consider adding a new error code for this.
+ virtual void SetAllowHttpErrorResults(bool allow_http_error_results) = 0;
+
+ // Attaches the specified string as the upload body. Depending on the length
+ // of the string, the string may be copied to the URLLoader, or may be
+ // streamed to it from the current process. May only be called once, and only
+ // if ResourceRequest passed to the constructor had a null |request_body|.
+ //
+ // |content_type| will overwrite any Content-Type header in the
+ // ResourceRequest passed to Create().
+ //
+ // TODO(mmenke): This currently always requires a copy. Update DataElement not
+ // to require this.
+ virtual void AttachStringForUpload(
+ const std::string& upload_data,
+ const std::string& upload_content_type) = 0;
+
+ // Helper method to attach a file for upload, so the consumer won't need to
+ // open the file itself off-thread. May only be called once, and only if the
+ // ResourceRequest passed to the constructor had a null |request_body|.
+ //
+ // |content_type| will overwrite any Content-Type header in the
+ // ResourceRequest passed to Create().
+ virtual void AttachFileForUpload(const base::FilePath& upload_file_path,
+ const std::string& upload_content_type) = 0;
+
+ // Sets the when to try and the max number of times to retry a request, if
+ // any. |max_retries| is the number of times to retry the request, not
+ // counting the initial request. |retry_mode| is a combination of one or more
+ // RetryModes, indicating when the request should be retried. If it is
+ // RETRY_NEVER, |max_retries| must be 0.
+ //
+ // By default, a request will not be retried.
+ //
+ // When a request is retried, the the request will start again using the
+ // initial content::ResourceRequest, even if the request was redirected.
+ //
+ // Calling this multiple times will overwrite the values previously passed to
+ // this method. May only be called before the request is started.
+ //
+ // Cannot retry requests with an upload body that contains a data pipe that
+ // was added to the ResourceRequest passed to Create() by the consumer.
+ virtual void SetRetryOptions(int max_retries, int retry_mode) = 0;
+
+ // Returns the net::Error representing the final status of the request. May
+ // only be called once the loader has informed the caller of completion.
+ virtual int NetError() const = 0;
+
+ // The ResourceResponseHead for the request. Will be nullptr if ResponseInfo
+ // was never received. May only be called once the loader has informed the
+ // caller of completion.
+ virtual const ResourceResponseHead* ResponseInfo() const = 0;
+
+ // Returns the URL that this loader is processing. May only be called once the
+ // loader has informed the caller of completion.
+ virtual const GURL& GetFinalURL() const = 0;
+
+ protected:
+ SimpleURLLoader();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SimpleURLLoader);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_SIMPLE_URL_LOADER_H_
diff --git a/chromium/services/network/public/cpp/simple_url_loader_stream_consumer.h b/chromium/services/network/public/cpp/simple_url_loader_stream_consumer.h
new file mode 100644
index 00000000000..5fb1a411ba8
--- /dev/null
+++ b/chromium/services/network/public/cpp/simple_url_loader_stream_consumer.h
@@ -0,0 +1,71 @@
+// Copyright 2018 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 SERVICES_NETWORK_PUBLIC_CPP_SIMPLE_URL_LOADER_STREAM_CONSUMER_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_SIMPLE_URL_LOADER_STREAM_CONSUMER_H_
+
+#include "base/callback_forward.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/strings/string_piece.h"
+
+namespace network {
+
+// Interface to handle streaming data from SimpleURLLoader. All methods are
+// invoked on the sequence the SimpleURLLoader was started on, and all callbacks
+// must be invoked on the same sequence. The SimpleURLLoader may be deleted at
+// any time. None of these methods will be called during SimpleURLLoader
+// destruction.
+class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoaderStreamConsumer {
+ public:
+ // Called as body data is received.
+ //
+ // More data will not be read until |resume| is called. It's safe to call
+ // |resume| synchronously, and to delete the SimpleURLLoader during the call.
+ //
+ // |string_piece| will only be valid for the duration of the OnDataReceived()
+ // call, but does remain valid during that call even if the SimpleURLLoader
+ // is destroyed. |string_piece| will never be of length 0.
+ //
+ // In the case of error, all data received over the pipe will be passed to
+ // this method before calling OnComplete, even if partial responses are set to
+ // be treated as errors (the default behavior), as it may not yet be known if
+ // the request will succeed or fail.
+ virtual void OnDataReceived(base::StringPiece string_piece,
+ base::OnceClosure resume) = 0;
+
+ // Called on successful completion, or error. In the default configuration,
+ // |success| is true if the request received a 2xx response and the entire
+ // response body, false otherwise. Allowing partial responses or HTTP errors
+ // will affect the value of |success|.
+ //
+ // 4xx and 5xx responses are considered successes, if
+ // SimpleURLLoader::SetAllowHttpErrorResults() is set to true.
+ //
+ // When the SimpleURLLoader retries a request, OnComplete() is only called
+ // after the final retry.
+ virtual void OnComplete(bool success) = 0;
+
+ // When retries are enabled for a request, this is called before the
+ // SimpleURLLoader retries. If this is called after data has been received,
+ // the entire response of the retried request will be passed to
+ // OnDataReceived() again, and any previously received partial response should
+ // be discarded.
+ //
+ // The request will not be retried until start_retry is invoked, which may be
+ // done synchronously or asynchronously. It's safe to delete the
+ // SimpleURLLoader during this call.
+ virtual void OnRetry(base::OnceClosure start_retry) = 0;
+
+ protected:
+ SimpleURLLoaderStreamConsumer() {}
+ virtual ~SimpleURLLoaderStreamConsumer() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SimpleURLLoaderStreamConsumer);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_PUBLIC_CPP_SIMPLE_URL_LOADER_STREAM_CONSUMER_H_
diff --git a/chromium/services/network/public/cpp/simple_url_loader_unittest.cc b/chromium/services/network/public/cpp/simple_url_loader_unittest.cc
new file mode 100644
index 00000000000..cf918816e07
--- /dev/null
+++ b/chromium/services/network/public/cpp/simple_url_loader_unittest.cc
@@ -0,0 +1,2614 @@
+// 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 "services/network/public/cpp/simple_url_loader.h"
+
+#include <stdint.h>
+
+#include <string>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/format_macros.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/sequence_checker.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/scoped_task_environment.h"
+#include "mojo/public/c/system/types.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "net/http/http_response_headers.h"
+#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_request.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/redirect_info.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
+#include "services/network/public/cpp/url_loader_completion_status.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace network {
+namespace {
+
+// Server path that returns a response containing as many a's as are specified
+// in the query part of the URL.
+const char kResponseSizePath[] = "/response-size";
+
+// Server path that returns a gzip response with a non-gzipped body.
+const char kInvalidGzipPath[] = "/invalid-gzip";
+
+// Server path that returns truncated response (Content-Length less than body
+// size).
+const char kTruncatedBodyPath[] = "/truncated-body";
+// The body of the truncated response (After truncation).
+const char kTruncatedBody[] = "Truncated Body";
+
+// Server path returns a 5xx error once, then returns the request body.
+const char kFailOnceThenEchoBody[] = "/fail-once-then-echo-body";
+
+// Used in string upload tests.
+const char kShortUploadBody[] =
+ "Though this upload be but little, it is fierce.";
+
+// Returns a string longer than
+// SimpleURLLoader::kMaxUploadStringAsStringLength, to test the path where
+// strings are streamed to the URLLoader.
+std::string GetLongUploadBody() {
+ std::string long_string;
+ long_string.reserve(SimpleURLLoader::kMaxUploadStringSizeToCopy);
+ while (long_string.length() <= SimpleURLLoader::kMaxUploadStringSizeToCopy) {
+ long_string.append(kShortUploadBody);
+ }
+ return long_string;
+}
+
+// Class to make it easier to start a SimpleURLLoader, wait for it to complete,
+// and check the result.
+class SimpleLoaderTestHelper : public SimpleURLLoaderStreamConsumer {
+ public:
+ // What the response should be downloaded to. Running all tests for all types
+ // is more than strictly needed, but simplest just to cover all cases.
+ enum class DownloadType { TO_STRING, TO_FILE, TO_TEMP_FILE, AS_STREAM };
+
+ explicit SimpleLoaderTestHelper(
+ std::unique_ptr<network::ResourceRequest> resource_request,
+ DownloadType download_type)
+ : download_type_(download_type),
+ simple_url_loader_(
+ SimpleURLLoader::Create(std::move(resource_request),
+ TRAFFIC_ANNOTATION_FOR_TESTS)) {
+ // Create a desistination directory, if downloading to a file.
+ if (download_type_ == DownloadType::TO_FILE) {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
+ dest_path_ = temp_dir_.GetPath().AppendASCII("foo");
+ }
+ }
+
+ ~SimpleLoaderTestHelper() override {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ if (temp_dir_.IsValid())
+ EXPECT_TRUE(temp_dir_.Delete());
+ if (!on_destruction_callback_.is_null())
+ std::move(on_destruction_callback_).Run();
+ }
+
+ // File path that will be written to.
+ const base::FilePath& dest_path() const {
+ DCHECK_EQ(DownloadType::TO_FILE, download_type_);
+ return dest_path_;
+ }
+
+ // Starts a SimpleURLLoader using the method corresponding to the
+ // DownloadType, but does not wait for it to complete. The default
+ // |max_body_size| of -1 means don't use a max body size (Use
+ // DownloadToStringOfUnboundedSizeUntilCrashAndDie for string downloads, and
+ // don't specify a size for other types of downloads).
+ void StartSimpleLoader(network::mojom::URLLoaderFactory* url_loader_factory,
+ int64_t max_body_size = -1) {
+ EXPECT_FALSE(done_);
+ switch (download_type_) {
+ case DownloadType::TO_STRING:
+ if (max_body_size < 0) {
+ simple_url_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
+ url_loader_factory,
+ base::BindOnce(&SimpleLoaderTestHelper::DownloadedToString,
+ base::Unretained(this)));
+ } else {
+ simple_url_loader_->DownloadToString(
+ url_loader_factory,
+ base::BindOnce(&SimpleLoaderTestHelper::DownloadedToString,
+ base::Unretained(this)),
+ max_body_size);
+ }
+ break;
+ case DownloadType::TO_FILE:
+ if (max_body_size < 0) {
+ simple_url_loader_->DownloadToFile(
+ url_loader_factory,
+ base::BindOnce(&SimpleLoaderTestHelper::DownloadedToFile,
+ base::Unretained(this)),
+ dest_path_);
+ } else {
+ simple_url_loader_->DownloadToFile(
+ url_loader_factory,
+ base::BindOnce(&SimpleLoaderTestHelper::DownloadedToFile,
+ base::Unretained(this)),
+ dest_path_, max_body_size);
+ }
+ break;
+ case DownloadType::TO_TEMP_FILE:
+ if (max_body_size < 0) {
+ simple_url_loader_->DownloadToTempFile(
+ url_loader_factory,
+ base::BindOnce(&SimpleLoaderTestHelper::DownloadedToFile,
+ base::Unretained(this)));
+ } else {
+ simple_url_loader_->DownloadToTempFile(
+ url_loader_factory,
+ base::BindOnce(&SimpleLoaderTestHelper::DownloadedToFile,
+ base::Unretained(this)),
+ max_body_size);
+ }
+ break;
+ case DownloadType::AS_STREAM:
+ // Downloading to stream doesn't support a max body size.
+ DCHECK_LT(max_body_size, 0);
+ simple_url_loader_->DownloadAsStream(url_loader_factory, this);
+ break;
+ }
+ }
+
+ // Starts the SimpleURLLoader waits for completion.
+ void StartSimpleLoaderAndWait(
+ network::mojom::URLLoaderFactory* url_loader_factory,
+ int64_t max_body_size = -1) {
+ StartSimpleLoader(url_loader_factory, max_body_size);
+ Wait();
+ }
+
+ // Waits until the request is completed. Automatically called by
+ // StartSimpleLoaderAndWait, but exposed so some tests can start the
+ // SimpleURLLoader directly.
+ void Wait() { run_loop_.Run(); }
+
+ // Sets whether a file should still exists on download-to-file errors.
+ // Defaults to false.
+ void set_expect_path_exists_on_error(bool expect_path_exists_on_error) {
+ EXPECT_EQ(DownloadType::TO_FILE, download_type_);
+ expect_path_exists_on_error_ = expect_path_exists_on_error;
+ }
+
+ // Sets whether reading is resumed asynchronously when downloading as a
+ // stream. Defaults to false.
+ void set_download_to_stream_async_resume(
+ bool download_to_stream_async_resume) {
+ download_to_stream_async_resume_ = download_to_stream_async_resume;
+ }
+
+ // Sets whether the helper should destroy the SimpleURLLoader in
+ // OnDataReceived.
+ void set_download_to_stream_destroy_on_data_received(
+ bool download_to_stream_destroy_on_data_received) {
+ download_to_stream_destroy_on_data_received_ =
+ download_to_stream_destroy_on_data_received;
+ }
+
+ // Sets whether retrying is done asynchronously when downloading as a stream.
+ // Defaults to false.
+ void set_download_to_stream_async_retry(bool download_to_stream_async_retry) {
+ download_to_stream_async_retry_ = download_to_stream_async_retry;
+ }
+
+ // Sets whether the helper should destroy the SimpleURLLoader in OnRetry.
+ void set_download_to_stream_destroy_on_retry(
+ bool download_to_stream_destroy_on_retry) {
+ download_to_stream_destroy_on_retry_ = download_to_stream_destroy_on_retry;
+ }
+
+ // Received response body, if any. Returns nullptr if no body was received
+ // (Which is different from a 0-length body). For DownloadType::TO_STRING,
+ // this is just the value passed to the callback. For DownloadType::TO_FILE,
+ // it is nullptr if an empty FilePath was passed to the callback, or the
+ // contents of the file, otherwise.
+ const std::string* response_body() const {
+ EXPECT_TRUE(done_);
+ return response_body_.get();
+ }
+
+ // Returns true if the callback has been invoked.
+ bool done() const { return done_; }
+
+ SimpleURLLoader* simple_url_loader() { return simple_url_loader_.get(); }
+
+ // Destroys the SimpleURLLoader. Useful in tests where the SimpleURLLoader is
+ // destroyed while it still has an open file, as the file needs to be closed
+ // before the SimpleLoaderTestHelper's destructor tries to clean up the temp
+ // directory.
+ void DestroySimpleURLLoader() { simple_url_loader_.reset(); }
+
+ void SetAllowPartialResults(bool allow_partial_results) {
+ simple_url_loader_->SetAllowPartialResults(allow_partial_results);
+ allow_http_error_results_ = allow_partial_results;
+ }
+
+ // Returns the HTTP response code. Fails if there isn't one.
+ int GetResponseCode() const {
+ EXPECT_TRUE(done_);
+ if (!simple_url_loader_->ResponseInfo()) {
+ ADD_FAILURE() << "No response info.";
+ return -1;
+ }
+ if (!simple_url_loader_->ResponseInfo()->headers) {
+ ADD_FAILURE() << "No response headers.";
+ return -1;
+ }
+ return simple_url_loader_->ResponseInfo()->headers->response_code();
+ }
+
+ // Returns the number of retries. Number of retries are only exposed when
+ // downloading as a stream.
+ int download_as_stream_retries() const {
+ DCHECK_EQ(DownloadType::AS_STREAM, download_type_);
+ return download_as_stream_retries_;
+ }
+
+ private:
+ void DownloadedToString(std::unique_ptr<std::string> response_body) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ EXPECT_FALSE(done_);
+ EXPECT_EQ(DownloadType::TO_STRING, download_type_);
+ EXPECT_FALSE(response_body_);
+
+ response_body_ = std::move(response_body);
+
+ done_ = true;
+ run_loop_.Quit();
+ }
+
+ void DownloadedToFile(const base::FilePath& file_path) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ EXPECT_FALSE(done_);
+ EXPECT_TRUE(download_type_ == DownloadType::TO_FILE ||
+ download_type_ == DownloadType::TO_TEMP_FILE);
+ EXPECT_FALSE(response_body_);
+
+ base::ScopedAllowBlockingForTesting allow_blocking;
+
+ if (!file_path.empty()) {
+ EXPECT_TRUE(base::PathExists(file_path));
+ response_body_ = std::make_unique<std::string>();
+ EXPECT_TRUE(base::ReadFileToString(file_path, response_body_.get()));
+ }
+
+ // Can do some additional checks in the TO_FILE case. Unfortunately, in the
+ // temp file case, can't check that temp files were cleaned up, since it's
+ // a shared directory.
+ if (download_type_ == DownloadType::TO_FILE) {
+ // Make sure the destination file exists if |file_path| is non-empty, or
+ // the file is expected to exist on error.
+ EXPECT_EQ(!file_path.empty() || expect_path_exists_on_error_,
+ base::PathExists(dest_path_));
+
+ if (!file_path.empty())
+ EXPECT_EQ(dest_path_, file_path);
+ }
+
+ // Clean up file, so tests don't leave around files in the temp directory.
+ // Only matters in the TO_TEMP_FILE case.
+ if (!file_path.empty())
+ base::DeleteFile(file_path, false);
+
+ done_ = true;
+ run_loop_.Quit();
+ }
+
+ // SimpleURLLoaderStreamConsumer implementation:
+
+ void OnDataReceived(base::StringPiece string_piece,
+ base::OnceClosure resume) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ EXPECT_FALSE(done_);
+ EXPECT_EQ(DownloadType::AS_STREAM, download_type_);
+
+ // If destroying the stream on data received, destroy the stream before
+ // reading the data, to make sure that works.
+ if (download_to_stream_destroy_on_data_received_) {
+ simple_url_loader_.reset();
+ done_ = true;
+ }
+
+ download_as_stream_response_body_.append(string_piece.as_string());
+
+ if (download_to_stream_destroy_on_data_received_) {
+ run_loop_.Quit();
+ return;
+ }
+
+ if (download_to_stream_async_resume_) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(resume));
+ return;
+ }
+ std::move(resume).Run();
+ }
+
+ void OnComplete(bool success) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ EXPECT_FALSE(done_);
+ EXPECT_EQ(DownloadType::AS_STREAM, download_type_);
+ EXPECT_FALSE(response_body_);
+
+ // If headers weren't received for the final request, the response body
+ // should be empty.
+ if (!simple_url_loader_->ResponseInfo())
+ DCHECK(download_as_stream_response_body_.empty());
+
+ // This makes behavior of downloading a response to a stream more closely
+ // resemble other DownloadTypes, so most test logic can be shared.
+ if (success ||
+ (allow_http_error_results_ && simple_url_loader_->ResponseInfo())) {
+ response_body_ =
+ std::make_unique<std::string>(download_as_stream_response_body_);
+ }
+
+ done_ = true;
+ run_loop_.Quit();
+ }
+
+ void OnRetry(base::OnceClosure start_retry) override {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ EXPECT_FALSE(done_);
+ EXPECT_EQ(DownloadType::AS_STREAM, download_type_);
+
+ ++download_as_stream_retries_;
+ download_as_stream_response_body_.clear();
+
+ if (download_to_stream_destroy_on_retry_) {
+ simple_url_loader_.reset();
+ done_ = true;
+ run_loop_.Quit();
+ return;
+ }
+
+ if (download_to_stream_async_retry_) {
+ base::SequencedTaskRunnerHandle::Get()->PostTask(FROM_HERE,
+ std::move(start_retry));
+ return;
+ }
+ std::move(start_retry).Run();
+ }
+
+ DownloadType download_type_;
+ bool done_ = false;
+
+ bool expect_path_exists_on_error_ = false;
+
+ std::unique_ptr<SimpleURLLoader> simple_url_loader_;
+ base::RunLoop run_loop_;
+
+ // Response body, regardless of DownloadType. Only populated on completion.
+ // Null on error.
+ std::unique_ptr<std::string> response_body_;
+
+ base::OnceClosure on_destruction_callback_;
+
+ // Response data when downloading as stream:
+ std::string download_as_stream_response_body_;
+ int download_as_stream_retries_ = 0;
+
+ bool download_to_stream_async_resume_ = false;
+ bool download_to_stream_destroy_on_data_received_ = false;
+ bool download_to_stream_async_retry_ = false;
+ bool download_to_stream_destroy_on_retry_ = false;
+
+ bool allow_http_error_results_ = false;
+
+ base::ScopedTempDir temp_dir_;
+ base::FilePath dest_path_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(SimpleLoaderTestHelper);
+};
+
+// Request handler for the embedded test server that returns a response body
+// with the length indicated by the query string.
+std::unique_ptr<net::test_server::HttpResponse> HandleResponseSize(
+ const net::test_server::HttpRequest& request) {
+ if (request.GetURL().path_piece() != kResponseSizePath)
+ return nullptr;
+
+ std::unique_ptr<net::test_server::BasicHttpResponse> response =
+ std::make_unique<net::test_server::BasicHttpResponse>();
+
+ uint32_t length;
+ if (!base::StringToUint(request.GetURL().query(), &length)) {
+ ADD_FAILURE() << "Invalid length: " << request.GetURL();
+ } else {
+ response->set_content(std::string(length, 'a'));
+ }
+
+ return std::move(response);
+}
+
+// Request handler for the embedded test server that returns a an invalid gzip
+// response body. No body bytes will be read successfully.
+std::unique_ptr<net::test_server::HttpResponse> HandleInvalidGzip(
+ const net::test_server::HttpRequest& request) {
+ if (request.GetURL().path_piece() != kInvalidGzipPath)
+ return nullptr;
+
+ std::unique_ptr<net::test_server::BasicHttpResponse> response =
+ std::make_unique<net::test_server::BasicHttpResponse>();
+ response->AddCustomHeader("Content-Encoding", "gzip");
+ response->set_content("Not gzipped");
+
+ return std::move(response);
+}
+
+// Request handler for the embedded test server that returns a response with a
+// truncated body. Consumer should see an error after reading some data.
+std::unique_ptr<net::test_server::HttpResponse> HandleTruncatedBody(
+ const net::test_server::HttpRequest& request) {
+ if (request.GetURL().path_piece() != kTruncatedBodyPath)
+ return nullptr;
+
+ std::unique_ptr<net::test_server::RawHttpResponse> response =
+ std::make_unique<net::test_server::RawHttpResponse>(
+ base::StringPrintf("HTTP/1.1 200 OK\r\n"
+ "Content-Length: %" PRIuS "\r\n",
+ strlen(kTruncatedBody) + 4),
+ kTruncatedBody);
+
+ return std::move(response);
+}
+
+// Request handler for the embedded test server that returns a 5xx error once,
+// and on future requests, has a response body matching the request body.
+std::unique_ptr<net::test_server::HttpResponse> FailOnceThenEchoBody(
+ bool* has_failed_request,
+ const net::test_server::HttpRequest& request) {
+ if (request.GetURL().path_piece() != kFailOnceThenEchoBody)
+ return nullptr;
+
+ if (!*has_failed_request) {
+ EXPECT_FALSE(request.content.empty());
+ *has_failed_request = true;
+ std::unique_ptr<net::test_server::BasicHttpResponse> response =
+ std::make_unique<net::test_server::BasicHttpResponse>();
+ response->set_code(net::HTTP_INTERNAL_SERVER_ERROR);
+ return response;
+ }
+
+ std::unique_ptr<net::test_server::BasicHttpResponse> response =
+ std::make_unique<net::test_server::BasicHttpResponse>();
+ response->set_content(request.content);
+ return std::move(response);
+}
+
+// Base class with shared setup logic.
+class SimpleURLLoaderTestBase {
+ public:
+ SimpleURLLoaderTestBase()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {
+ network::mojom::NetworkServicePtr network_service_ptr;
+ network::mojom::NetworkServiceRequest network_service_request =
+ mojo::MakeRequest(&network_service_ptr);
+ network_service_ =
+ network::NetworkService::Create(std::move(network_service_request),
+ /*netlog=*/nullptr);
+ network::mojom::NetworkContextParamsPtr context_params =
+ network::mojom::NetworkContextParams::New();
+ context_params->enable_data_url_support = true;
+ network_service_ptr->CreateNetworkContext(
+ mojo::MakeRequest(&network_context_), std::move(context_params));
+
+ network_context_->CreateURLLoaderFactory(
+ mojo::MakeRequest(&url_loader_factory_), 0);
+
+ test_server_.AddDefaultHandlers(base::FilePath(FILE_PATH_LITERAL("")));
+ test_server_.RegisterRequestHandler(
+ base::BindRepeating(&HandleResponseSize));
+ test_server_.RegisterRequestHandler(
+ base::BindRepeating(&HandleInvalidGzip));
+ test_server_.RegisterRequestHandler(
+ base::BindRepeating(&HandleTruncatedBody));
+ test_server_.RegisterRequestHandler(base::BindRepeating(
+ &FailOnceThenEchoBody, base::Owned(new bool(false))));
+
+ EXPECT_TRUE(test_server_.Start());
+
+ // Can only create this after blocking calls. Creating the network stack
+ // has some, as does starting the test server.
+ disallow_blocking_ = std::make_unique<base::ScopedDisallowBlocking>();
+ }
+
+ virtual ~SimpleURLLoaderTestBase() {}
+
+ // Returns the path of a file that can be used in upload tests.
+ static base::FilePath GetTestFilePath() {
+ base::FilePath test_data_dir;
+ base::PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir);
+ return test_data_dir.AppendASCII("services/test/data/title1.html");
+ }
+
+ static std::string GetTestFileContents() {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ std::string file_contents;
+ EXPECT_TRUE(base::ReadFileToString(GetTestFilePath(), &file_contents));
+ return file_contents;
+ }
+
+ protected:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ std::unique_ptr<network::mojom::NetworkService> network_service_;
+ network::mojom::NetworkContextPtr network_context_;
+ network::mojom::URLLoaderFactoryPtr url_loader_factory_;
+
+ net::test_server::EmbeddedTestServer test_server_;
+
+ std::unique_ptr<base::ScopedDisallowBlocking> disallow_blocking_;
+};
+
+class SimpleURLLoaderTest
+ : public SimpleURLLoaderTestBase,
+ public testing::TestWithParam<SimpleLoaderTestHelper::DownloadType> {
+ public:
+ SimpleURLLoaderTest() {}
+
+ ~SimpleURLLoaderTest() override {}
+
+ std::unique_ptr<SimpleLoaderTestHelper> CreateHelper(
+ std::unique_ptr<network::ResourceRequest> resource_request) {
+ EXPECT_TRUE(resource_request);
+ return std::make_unique<SimpleLoaderTestHelper>(std::move(resource_request),
+ GetParam());
+ }
+
+ std::unique_ptr<SimpleLoaderTestHelper> CreateHelperForURL(
+ const GURL& url,
+ const char* method = "GET") {
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ resource_request->url = url;
+ resource_request->method = method;
+ return std::make_unique<SimpleLoaderTestHelper>(std::move(resource_request),
+ GetParam());
+ }
+};
+
+TEST_P(SimpleURLLoaderTest, BasicRequest) {
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ // Use a more interesting request than "/echo", just to verify more than the
+ // request URL is hooked up.
+ resource_request->url = test_server_.GetURL("/echoheader?foo");
+ resource_request->headers.SetHeader("foo", "Expected Response");
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelper(std::move(resource_request));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("Expected Response", *test_helper->response_body());
+}
+
+// Test that SimpleURLLoader handles data URLs, which don't have headers.
+TEST_P(SimpleURLLoaderTest, DataURL) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("data:text/plain,foo"));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->simple_url_loader()->ResponseInfo());
+ EXPECT_FALSE(test_helper->simple_url_loader()->ResponseInfo()->headers);
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("foo", *test_helper->response_body());
+}
+
+// Make sure the class works when the size of the encoded and decoded bodies are
+// different.
+TEST_P(SimpleURLLoaderTest, GzipBody) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/gzip-body?foo"));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("foo", *test_helper->response_body());
+}
+
+// Make sure redirects are followed.
+TEST_P(SimpleURLLoaderTest, Redirect) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ "/server-redirect?" + test_server_.GetURL("/echo").spec()));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("Echo", *test_helper->response_body());
+}
+
+// Make sure OnRedirectCallback is invoked on a redirect.
+TEST_P(SimpleURLLoaderTest, OnRedirectCallback) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ "/server-redirect?" + test_server_.GetURL("/echo").spec()));
+
+ int num_redirects = 0;
+ net::RedirectInfo redirect_info;
+ network::ResourceResponseHead response_head;
+ test_helper->simple_url_loader()->SetOnRedirectCallback(base::BindRepeating(
+ [](int* num_redirects, net::RedirectInfo* redirect_info_ptr,
+ network::ResourceResponseHead* response_head_ptr,
+ const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& response_head) {
+ ++*num_redirects;
+ *redirect_info_ptr = redirect_info;
+ *response_head_ptr = response_head;
+ },
+ base::Unretained(&num_redirects), base::Unretained(&redirect_info),
+ base::Unretained(&response_head)));
+
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("Echo", *test_helper->response_body());
+
+ EXPECT_EQ(1, num_redirects);
+ EXPECT_EQ(test_server_.GetURL("/echo"), redirect_info.new_url);
+ ASSERT_TRUE(response_head.headers);
+ EXPECT_EQ(301, response_head.headers->response_code());
+}
+
+// Make sure OnRedirectCallback is invoked on each redirect.
+TEST_P(SimpleURLLoaderTest, OnRedirectCallbackTwoRedirects) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ "/server-redirect?" +
+ test_server_
+ .GetURL("/server-redirect?" + test_server_.GetURL("/echo").spec())
+ .spec()));
+ int num_redirects = 0;
+ test_helper->simple_url_loader()->SetOnRedirectCallback(base::BindRepeating(
+ [](int* num_redirects, const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& response_head) {
+ ++*num_redirects;
+ },
+ base::Unretained(&num_redirects)));
+
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("Echo", *test_helper->response_body());
+
+ EXPECT_EQ(2, num_redirects);
+}
+
+TEST_P(SimpleURLLoaderTest, DeleteInOnRedirectCallback) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ "/server-redirect?" + test_server_.GetURL("/echo").spec()));
+
+ SimpleLoaderTestHelper* unowned_test_helper = test_helper.get();
+ base::RunLoop run_loop;
+ unowned_test_helper->simple_url_loader()->SetOnRedirectCallback(
+ base::BindRepeating(
+ [](std::unique_ptr<SimpleLoaderTestHelper> test_helper,
+ base::RunLoop* run_loop, const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& response_head) {
+ run_loop->Quit();
+ },
+ base::Passed(std::move(test_helper)), &run_loop));
+
+ unowned_test_helper->StartSimpleLoader(url_loader_factory_.get());
+
+ run_loop.Run();
+}
+
+TEST_P(SimpleURLLoaderTest, UploadShortStringWithRedirect) {
+ // Use a 307 redirect to preserve the body across the redirect.
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelperForURL(
+ test_server_.GetURL("/server-redirect-307?" +
+ test_server_.GetURL("/echo").spec()),
+ "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(kShortUploadBody,
+ "text/plain");
+
+ int num_redirects = 0;
+ test_helper->simple_url_loader()->SetOnRedirectCallback(base::BindRepeating(
+ [](int* num_redirects, const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& response_head) {
+ ++*num_redirects;
+ },
+ base::Unretained(&num_redirects)));
+
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kShortUploadBody, *test_helper->response_body());
+ // Make sure request really was redirected.
+ EXPECT_EQ(1, num_redirects);
+}
+
+TEST_P(SimpleURLLoaderTest, UploadLongStringWithRedirect) {
+ // Use a 307 redirect to preserve the body across the redirect.
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper = CreateHelperForURL(
+ test_server_.GetURL("/server-redirect-307?" +
+ test_server_.GetURL("/echo").spec()),
+ "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(GetLongUploadBody(),
+ "text/plain");
+
+ int num_redirects = 0;
+ test_helper->simple_url_loader()->SetOnRedirectCallback(base::BindRepeating(
+ [](int* num_redirects, const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& response_head) {
+ ++*num_redirects;
+ },
+ base::Unretained(&num_redirects)));
+
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(GetLongUploadBody(), *test_helper->response_body());
+ // Make sure request really was redirected.
+ EXPECT_EQ(1, num_redirects);
+}
+
+TEST_P(SimpleURLLoaderTest, OnResponseStartedCallback) {
+ GURL url = test_server_.GetURL("/set-header?foo: bar");
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ resource_request->url = test_server_.GetURL("/server-redirect?" + url.spec());
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelper(std::move(resource_request));
+
+ base::RunLoop run_loop;
+ GURL actual_url;
+ std::string foo_header_value;
+ test_helper->simple_url_loader()->SetOnResponseStartedCallback(
+ base::BindRepeating(
+ [](GURL* out_final_url, std::string* foo_header_value,
+ base::OnceClosure quit_closure, const GURL& final_url,
+ const ResourceResponseHead& response_head) {
+ *out_final_url = final_url;
+ if (response_head.headers) {
+ response_head.headers->EnumerateHeader(/*iter=*/nullptr, "foo",
+ foo_header_value);
+ }
+ std::move(quit_closure).Run();
+ },
+ &actual_url, &foo_header_value, run_loop.QuitClosure()));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ run_loop.Run();
+
+ EXPECT_EQ(url, actual_url);
+ EXPECT_EQ("bar", foo_header_value);
+}
+
+TEST_P(SimpleURLLoaderTest, DeleteInOnResponseStartedCallback) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo"));
+
+ SimpleLoaderTestHelper* unowned_test_helper = test_helper.get();
+ base::RunLoop run_loop;
+ unowned_test_helper->simple_url_loader()->SetOnResponseStartedCallback(
+ base::BindRepeating(
+ [](std::unique_ptr<SimpleLoaderTestHelper> test_helper,
+ base::OnceClosure quit_closure, const GURL& final_url,
+ const ResourceResponseHead& response_head) {
+ // Delete the SimpleURLLoader.
+ test_helper.reset();
+ // Access the parameters to trigger a memory error if they have been
+ // deleted. (ASAN build should catch it)
+ EXPECT_FALSE(response_head.request_start.is_null());
+ EXPECT_TRUE(final_url.is_valid());
+ std::move(quit_closure).Run();
+ },
+ base::Passed(std::move(test_helper)), run_loop.QuitClosure()));
+
+ unowned_test_helper->StartSimpleLoader(url_loader_factory_.get());
+
+ run_loop.Run();
+}
+
+// Check the case where a URLLoaderFactory with a closed Mojo pipe was passed
+// in.
+TEST_P(SimpleURLLoaderTest, DisconnectedURLLoader) {
+ // Destroy the NetworkContext, and wait for the Mojo URLLoaderFactory proxy to
+ // be informed of the closed pipe.
+ network_context_.reset();
+ base::RunLoop().RunUntilIdle();
+
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ resource_request->url = test_server_.GetURL("/echoheader?foo");
+ resource_request->headers.SetHeader("foo", "Expected Response");
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelper(std::move(resource_request));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::ERR_FAILED, test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->simple_url_loader()->ResponseInfo());
+}
+
+// Check that no body is returned with an HTTP error response.
+TEST_P(SimpleURLLoaderTest, HttpErrorStatusCodeResponse) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo?status=400"));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::ERR_FAILED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(400, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+// Check that the body is returned with an HTTP error response, when
+// SetAllowHttpErrorResults(true) is called.
+TEST_P(SimpleURLLoaderTest, HttpErrorStatusCodeResponseAllowed) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo?status=400"));
+ test_helper->simple_url_loader()->SetAllowHttpErrorResults(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(400, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("Echo", *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, EmptyResponseBody) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/nocontent"));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(204, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ // A response body is sent from the NetworkService, but it's empty.
+ EXPECT_EQ("", *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, BigResponseBody) {
+ // Big response that requires multiple reads, and exceeds the maximum size
+ // limit of SimpleURLLoader::DownloadToString(). That is, this test make sure
+ // that DownloadToStringOfUnboundedSizeUntilCrashAndDie() can receive strings
+ // longer than DownloadToString() allows.
+ const uint32_t kResponseSize = 2 * 1024 * 1024;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kResponseSize, test_helper->response_body()->length());
+ EXPECT_EQ(std::string(kResponseSize, 'a'), *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, ResponseBodyWithSizeMatchingLimit) {
+ // Download to stream doesn't support response sizes.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ return;
+
+ const uint32_t kResponseSize = 16;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get(),
+ kResponseSize);
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kResponseSize, test_helper->response_body()->length());
+ EXPECT_EQ(std::string(kResponseSize, 'a'), *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, ResponseBodyWithSizeBelowLimit) {
+ // Download to stream doesn't support response sizes.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ return;
+
+ const uint32_t kResponseSize = 16;
+ const uint32_t kMaxResponseSize = kResponseSize + 1;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get(),
+ kMaxResponseSize);
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kResponseSize, test_helper->response_body()->length());
+ EXPECT_EQ(std::string(kResponseSize, 'a'), *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, ResponseBodyWithSizeAboveLimit) {
+ // Download to stream doesn't support response sizes.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ return;
+
+ const uint32_t kResponseSize = 16;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get(),
+ kResponseSize - 1);
+
+ EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+// Same as above, but with setting allow_partial_results to true.
+TEST_P(SimpleURLLoaderTest, ResponseBodyWithSizeAboveLimitPartialResponse) {
+ // Download to stream doesn't support response sizes.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ return;
+
+ const uint32_t kResponseSize = 16;
+ const uint32_t kMaxResponseSize = kResponseSize - 1;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->SetAllowPartialResults(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get(),
+ kMaxResponseSize);
+
+ EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES,
+ test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(std::string(kMaxResponseSize, 'a'), *test_helper->response_body());
+ EXPECT_EQ(kMaxResponseSize, test_helper->response_body()->length());
+}
+
+// The next 4 tests duplicate the above 4, but with larger response sizes. This
+// means the size limit will not be exceeded on the first read.
+TEST_P(SimpleURLLoaderTest, BigResponseBodyWithSizeMatchingLimit) {
+ // Download to stream doesn't support response sizes.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ return;
+
+ const uint32_t kResponseSize = 512 * 1024;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get(),
+ kResponseSize);
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kResponseSize, test_helper->response_body()->length());
+ EXPECT_EQ(std::string(kResponseSize, 'a'), *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, BigResponseBodyWithSizeBelowLimit) {
+ // Download to stream doesn't support response sizes.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ return;
+
+ const uint32_t kResponseSize = 512 * 1024;
+ const uint32_t kMaxResponseSize = kResponseSize + 1;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get(),
+ kMaxResponseSize);
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kResponseSize, test_helper->response_body()->length());
+ EXPECT_EQ(std::string(kResponseSize, 'a'), *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, BigResponseBodyWithSizeAboveLimit) {
+ // Download to stream doesn't support response sizes.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ return;
+
+ const uint32_t kResponseSize = 512 * 1024;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get(),
+ kResponseSize - 1);
+
+ EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, BigResponseBodyWithSizeAboveLimitPartialResponse) {
+ // Download to stream doesn't support response sizes.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ return;
+
+ const uint32_t kResponseSize = 512 * 1024;
+ const uint32_t kMaxResponseSize = kResponseSize - 1;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->SetAllowPartialResults(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get(),
+ kMaxResponseSize);
+
+ EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES,
+ test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(std::string(kMaxResponseSize, 'a'), *test_helper->response_body());
+ EXPECT_EQ(kMaxResponseSize, test_helper->response_body()->length());
+}
+
+TEST_P(SimpleURLLoaderTest, NetErrorBeforeHeaders) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/close-socket"));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::ERR_EMPTY_RESPONSE,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->simple_url_loader()->ResponseInfo());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, NetErrorBeforeHeadersWithPartialResults) {
+ // Allow response body on error. There should still be no response body, since
+ // the error is before body reading starts.
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/close-socket"));
+ test_helper->SetAllowPartialResults(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_FALSE(test_helper->response_body());
+
+ EXPECT_EQ(net::ERR_EMPTY_RESPONSE,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->simple_url_loader()->ResponseInfo());
+}
+
+TEST_P(SimpleURLLoaderTest, NetErrorAfterHeaders) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kInvalidGzipPath));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::ERR_CONTENT_DECODING_FAILED,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, NetErrorAfterHeadersWithPartialResults) {
+ // Allow response body on error. This case results in a 0-byte response body.
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kInvalidGzipPath));
+ test_helper->SetAllowPartialResults(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::ERR_CONTENT_DECODING_FAILED,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("", *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, TruncatedBody) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kTruncatedBodyPath));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::ERR_CONTENT_LENGTH_MISMATCH,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, TruncatedBodyWithPartialResults) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kTruncatedBodyPath));
+ test_helper->SetAllowPartialResults(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::ERR_CONTENT_LENGTH_MISMATCH,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kTruncatedBody, *test_helper->response_body());
+}
+
+// Test case where NetworkService is destroyed before headers are received (and
+// before the request is even made, for that matter).
+TEST_P(SimpleURLLoaderTest, DestroyServiceBeforeResponseStarts) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/hung"));
+ test_helper->StartSimpleLoader(url_loader_factory_.get());
+ {
+ // Destroying the NetworkService may result in blocking operations on some
+ // platforms, like joining threads.
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ network_service_.reset();
+ }
+ test_helper->Wait();
+
+ EXPECT_EQ(net::ERR_FAILED, test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->response_body());
+ ASSERT_FALSE(test_helper->simple_url_loader()->ResponseInfo());
+}
+
+TEST_P(SimpleURLLoaderTest, UploadShortString) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo"), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(kShortUploadBody,
+ "text/plain");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kShortUploadBody, *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, UploadLongString) {
+ std::string long_string = GetLongUploadBody();
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo"), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(long_string,
+ "text/plain");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(long_string, *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, UploadEmptyString) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo"), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload("", "text/plain");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("", *test_helper->response_body());
+
+ // Also make sure the correct method was sent, with the right content-type.
+ test_helper = CreateHelperForURL(test_server_.GetURL("/echoall"), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload("", "text/plain");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_NE(std::string::npos,
+ test_helper->response_body()->find("Content-Type: text/plain"));
+ EXPECT_NE(std::string::npos, test_helper->response_body()->find("POST /"));
+ EXPECT_EQ(std::string::npos, test_helper->response_body()->find("PUT /"));
+}
+
+TEST_P(SimpleURLLoaderTest, UploadShortStringWithRetry) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kFailOnceThenEchoBody), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(kShortUploadBody,
+ "text/plain");
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kShortUploadBody, *test_helper->response_body());
+
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ EXPECT_EQ(1, test_helper->download_as_stream_retries());
+}
+
+TEST_P(SimpleURLLoaderTest, UploadLongStringWithRetry) {
+ std::string long_string = GetLongUploadBody();
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kFailOnceThenEchoBody), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(long_string,
+ "text/plain");
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(long_string, *test_helper->response_body());
+
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ EXPECT_EQ(1, test_helper->download_as_stream_retries());
+}
+
+TEST_P(SimpleURLLoaderTest, UploadFile) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo"), "POST");
+ test_helper->simple_url_loader()->AttachFileForUpload(GetTestFilePath(),
+ "text/plain");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(GetTestFileContents(), *test_helper->response_body());
+
+ // Also make sure the correct method was sent, with the right content-type.
+ test_helper = CreateHelperForURL(test_server_.GetURL("/echoall"), "POST");
+ test_helper->simple_url_loader()->AttachFileForUpload(GetTestFilePath(),
+ "text/plain");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_NE(std::string::npos,
+ test_helper->response_body()->find("Content-Type: text/plain"));
+ EXPECT_NE(std::string::npos, test_helper->response_body()->find("POST /"));
+ EXPECT_EQ(std::string::npos, test_helper->response_body()->find("PUT /"));
+}
+
+TEST_P(SimpleURLLoaderTest, UploadFileWithPut) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo"), "PUT");
+ test_helper->simple_url_loader()->AttachFileForUpload(GetTestFilePath(),
+ "text/plain");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(GetTestFileContents(), *test_helper->response_body());
+
+ // Also make sure the correct method was sent, with the right content-type.
+ test_helper = CreateHelperForURL(test_server_.GetURL("/echoall"), "PUT");
+ test_helper->simple_url_loader()->AttachFileForUpload(GetTestFilePath(),
+ "text/salted");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_NE(std::string::npos,
+ test_helper->response_body()->find("Content-Type: text/salted"));
+ EXPECT_EQ(std::string::npos,
+ test_helper->response_body()->find("Content-Type: text/plain"));
+ EXPECT_EQ(std::string::npos, test_helper->response_body()->find("POST /"));
+ EXPECT_NE(std::string::npos, test_helper->response_body()->find("PUT /"));
+}
+
+TEST_P(SimpleURLLoaderTest, UploadFileWithRetry) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kFailOnceThenEchoBody), "POST");
+ test_helper->simple_url_loader()->AttachFileForUpload(GetTestFilePath(),
+ "text/plain");
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(GetTestFileContents(), *test_helper->response_body());
+
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ EXPECT_EQ(1, test_helper->download_as_stream_retries());
+}
+
+TEST_P(SimpleURLLoaderTest, UploadNonexistantFile) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/echo"), "POST");
+ // Path to a file that doesn't exist. Start with the test directory just to
+ // get a valid absolute path the test has access to.
+ base::FilePath path_to_nonexistent_file =
+ GetTestFilePath().DirName().AppendASCII("this/file/does/not/exist");
+ // Appending a path to the end of a file should guarantee no such file exists.
+ test_helper->simple_url_loader()->AttachFileForUpload(
+ path_to_nonexistent_file, "text/plain");
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::ERR_FILE_NOT_FOUND,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->simple_url_loader()->ResponseInfo());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+// Test case where uploading a file is canceled before the URLLoader is started
+// (But after the SimpleURLLoader is started).
+TEST_P(SimpleURLLoaderTest, UploadFileCanceledBeforeLoaderStarted) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("http://does_not_matter:7/"), "POST");
+ test_helper->simple_url_loader()->AttachFileForUpload(GetTestFilePath(),
+ "text/plain");
+
+ test_helper->StartSimpleLoader(url_loader_factory_.get());
+ test_helper.reset();
+ scoped_task_environment_.RunUntilIdle();
+}
+
+TEST_P(SimpleURLLoaderTest, UploadFileCanceledWithRetry) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/hung"), "POST");
+ test_helper->simple_url_loader()->AttachFileForUpload(GetTestFilePath(),
+ "text/plain");
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 2, SimpleURLLoader::RETRY_ON_5XX);
+ test_helper->StartSimpleLoader(url_loader_factory_.get());
+ scoped_task_environment_.RunUntilIdle();
+ test_helper.reset();
+ scoped_task_environment_.RunUntilIdle();
+}
+
+enum class TestLoaderEvent {
+ // States related to reading the long upload body (Returned by
+ // GetLongUploadBody()). They expect the ResourceRequest to have a request
+ // body with a single DataPipeGetter.
+
+ // Call Read() on the DataPipeGetter.
+ kStartReadLongUploadBody,
+ // Wait for Read() to complete, expecting it to succeed and return the size of
+ // the string returned by GetLongUploadBody().
+ kWaitForLongUploadBodySize,
+ // Read the entire body, expecting it to equal the string returned by
+ // GetLongUploadBody().
+ kReadLongUploadBody,
+ // Read the first byte of the upload body. Cannot be followed by a call to
+ // kReadLongUploadBody.
+ kReadFirstByteOfLongUploadBody,
+
+ kReceivedRedirect,
+ // Receive a response with a 200 status code.
+ kReceivedResponse,
+ // Receive a response with a 401 status code.
+ kReceived401Response,
+ // Receive a response with a 501 status code.
+ kReceived501Response,
+ kBodyBufferReceived,
+ kBodyDataRead,
+ // ResponseComplete indicates a success.
+ kResponseComplete,
+ // ResponseComplete is passed a network error (net::ERR_TIMED_OUT).
+ kResponseCompleteFailed,
+ // ResponseComplete is passed net::ERR_NETWORK_CHANGED.
+ kResponseCompleteNetworkChanged,
+ // Less body data is received than is expected.
+ kResponseCompleteTruncated,
+ // More body data is received than is expected.
+ kResponseCompleteWithExtraData,
+ kClientPipeClosed,
+ kBodyBufferClosed,
+};
+
+// URLLoader that the test fixture can control. This allows finer grained
+// control over event order over when a pipe is closed, and in ordering of
+// events where there are multiple pipes. It also allows sending events in
+// unexpected order, to test handling of events from less trusted processes.
+class MockURLLoader : public network::mojom::URLLoader {
+ public:
+ MockURLLoader(base::test::ScopedTaskEnvironment* scoped_task_environment,
+ network::mojom::URLLoaderRequest url_loader_request,
+ network::mojom::URLLoaderClientPtr client,
+ std::vector<TestLoaderEvent> test_events,
+ scoped_refptr<network::ResourceRequestBody> request_body)
+ : scoped_task_environment_(scoped_task_environment),
+ binding_(this, std::move(url_loader_request)),
+ client_(std::move(client)),
+ test_events_(std::move(test_events)),
+ weak_factory_for_data_pipe_callbacks_(this) {
+ if (request_body && request_body->elements()->size() == 1 &&
+ (*request_body->elements())[0].type() ==
+ network::DataElement::TYPE_DATA_PIPE) {
+ // The const_cast is weird, but it's how the current API works.
+ data_pipe_getter_ =
+ const_cast<network::DataElement*>(&(*request_body->elements())[0])
+ ->ReleaseDataPipeGetter();
+ DCHECK(data_pipe_getter_);
+ }
+ }
+
+ void RunTest() {
+ for (auto test_event : test_events_) {
+ switch (test_event) {
+ case TestLoaderEvent::kStartReadLongUploadBody: {
+ ASSERT_TRUE(data_pipe_getter_);
+ upload_data_pipe_.reset();
+ weak_factory_for_data_pipe_callbacks_.InvalidateWeakPtrs();
+ read_run_loop_ = std::make_unique<base::RunLoop>();
+ mojo::DataPipe data_pipe;
+ data_pipe_getter_->Read(
+ std::move(data_pipe.producer_handle),
+ base::BindOnce(
+ &MockURLLoader::OnReadComplete,
+ weak_factory_for_data_pipe_callbacks_.GetWeakPtr()));
+ upload_data_pipe_ = std::move(data_pipe.consumer_handle);
+ // Continue instead of break, to avoid spinning the message loop -
+ // only wait for the response if next step indicates to do so.
+ continue;
+ }
+ case TestLoaderEvent::kWaitForLongUploadBodySize: {
+ ASSERT_TRUE(data_pipe_getter_);
+ ASSERT_TRUE(read_run_loop_);
+ read_run_loop_->Run();
+ break;
+ }
+ case TestLoaderEvent::kReadLongUploadBody: {
+ ASSERT_TRUE(data_pipe_getter_);
+ ASSERT_TRUE(upload_data_pipe_.is_valid());
+ std::string upload_body;
+ while (true) {
+ char read_buffer[32 * 1024];
+ uint32_t read_size = sizeof(read_buffer);
+ MojoResult result = upload_data_pipe_->ReadData(
+ read_buffer, &read_size, MOJO_READ_DATA_FLAG_NONE);
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ base::RunLoop().RunUntilIdle();
+ continue;
+ }
+ if (result != MOJO_RESULT_OK)
+ break;
+ upload_body.append(read_buffer, read_size);
+ }
+ EXPECT_EQ(GetLongUploadBody(), upload_body);
+ break;
+ }
+ case TestLoaderEvent::kReadFirstByteOfLongUploadBody: {
+ ASSERT_TRUE(data_pipe_getter_);
+ ASSERT_TRUE(upload_data_pipe_.is_valid());
+ MojoResult result;
+ char byte;
+ uint32_t read_size;
+ while (true) {
+ read_size = 1;
+ result = upload_data_pipe_->ReadData(&byte, &read_size,
+ MOJO_READ_DATA_FLAG_NONE);
+ if (result != MOJO_RESULT_SHOULD_WAIT)
+ break;
+ base::RunLoop().RunUntilIdle();
+ }
+ if (result != MOJO_RESULT_OK) {
+ ADD_FAILURE() << "Expected to read one byte of data.";
+ break;
+ }
+ EXPECT_EQ(1u, read_size);
+ EXPECT_EQ(GetLongUploadBody()[0], byte);
+ break;
+ }
+ case TestLoaderEvent::kReceivedRedirect: {
+ net::RedirectInfo redirect_info;
+ redirect_info.new_method = "GET";
+ redirect_info.new_url = GURL("bar://foo/");
+ redirect_info.status_code = 301;
+
+ network::ResourceResponseHead response_info;
+ std::string headers(
+ "HTTP/1.0 301 The Response Has Moved to Another Server\n"
+ "Location: bar://foo/");
+ response_info.headers =
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers.c_str(), headers.size()));
+ client_->OnReceiveRedirect(redirect_info, response_info);
+ break;
+ }
+ case TestLoaderEvent::kReceivedResponse: {
+ network::ResourceResponseHead response_info;
+ std::string headers("HTTP/1.0 200 OK");
+ response_info.headers =
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers.c_str(), headers.size()));
+ client_->OnReceiveResponse(response_info,
+ base::Optional<net::SSLInfo>(), nullptr);
+ break;
+ }
+ case TestLoaderEvent::kReceived401Response: {
+ network::ResourceResponseHead response_info;
+ std::string headers("HTTP/1.0 401 Client Borkage");
+ response_info.headers =
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers.c_str(), headers.size()));
+ client_->OnReceiveResponse(response_info,
+ base::Optional<net::SSLInfo>(), nullptr);
+ break;
+ }
+ case TestLoaderEvent::kReceived501Response: {
+ network::ResourceResponseHead response_info;
+ std::string headers("HTTP/1.0 501 Server Borkage");
+ response_info.headers =
+ new net::HttpResponseHeaders(net::HttpUtil::AssembleRawHeaders(
+ headers.c_str(), headers.size()));
+ client_->OnReceiveResponse(response_info,
+ base::Optional<net::SSLInfo>(), nullptr);
+ break;
+ }
+ case TestLoaderEvent::kBodyBufferReceived: {
+ mojo::DataPipe data_pipe(1024);
+ body_stream_ = std::move(data_pipe.producer_handle);
+ client_->OnStartLoadingResponseBody(
+ std::move(data_pipe.consumer_handle));
+ break;
+ }
+ case TestLoaderEvent::kBodyDataRead: {
+ uint32_t num_bytes = 1;
+ // Writing one byte should always succeed synchronously, for the
+ // amount of data these tests send.
+ EXPECT_EQ(MOJO_RESULT_OK,
+ body_stream_->WriteData("a", &num_bytes,
+ MOJO_WRITE_DATA_FLAG_NONE));
+ EXPECT_EQ(num_bytes, 1u);
+ break;
+ }
+ case TestLoaderEvent::kResponseComplete: {
+ network::URLLoaderCompletionStatus status;
+ status.error_code = net::OK;
+ status.decoded_body_length = CountBytesToSend();
+ client_->OnComplete(status);
+ break;
+ }
+ case TestLoaderEvent::kResponseCompleteFailed: {
+ network::URLLoaderCompletionStatus status;
+ // Use an error that SimpleURLLoader doesn't create itself, so clear
+ // when this is the source of the error code.
+ status.error_code = net::ERR_TIMED_OUT;
+ status.decoded_body_length = CountBytesToSend();
+ client_->OnComplete(status);
+ break;
+ }
+ case TestLoaderEvent::kResponseCompleteNetworkChanged: {
+ network::URLLoaderCompletionStatus status;
+ status.error_code = net::ERR_NETWORK_CHANGED;
+ status.decoded_body_length = CountBytesToSend();
+ client_->OnComplete(status);
+ break;
+ }
+ case TestLoaderEvent::kResponseCompleteTruncated: {
+ network::URLLoaderCompletionStatus status;
+ status.error_code = net::OK;
+ status.decoded_body_length = CountBytesToSend() + 1;
+ client_->OnComplete(status);
+ break;
+ }
+ case TestLoaderEvent::kResponseCompleteWithExtraData: {
+ // Make sure |decoded_body_length| doesn't underflow.
+ DCHECK_GT(CountBytesToSend(), 0u);
+ network::URLLoaderCompletionStatus status;
+ status.error_code = net::OK;
+ status.decoded_body_length = CountBytesToSend() - 1;
+ client_->OnComplete(status);
+ break;
+ }
+ case TestLoaderEvent::kClientPipeClosed: {
+ DCHECK(client_);
+ EXPECT_TRUE(binding_.is_bound());
+ client_.reset();
+ break;
+ }
+ case TestLoaderEvent::kBodyBufferClosed: {
+ body_stream_.reset();
+ break;
+ }
+ }
+ // Wait for Mojo to pass along the message, to ensure expected ordering.
+ scoped_task_environment_->RunUntilIdle();
+ }
+ }
+ ~MockURLLoader() override {}
+
+ // network::mojom::URLLoader implementation:
+ void FollowRedirect() override {}
+ void ProceedWithResponse() override {}
+ void SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) override {
+ NOTREACHED();
+ }
+ void PauseReadingBodyFromNet() override {}
+ void ResumeReadingBodyFromNet() override {}
+
+ network::mojom::URLLoaderClient* client() const { return client_.get(); }
+
+ private:
+ // Counts the total number of bytes that will be sent over the course of
+ // running the request. Includes both those that have been sent already, and
+ // those that have yet to be sent.
+ uint32_t CountBytesToSend() const {
+ int total_bytes = 0;
+ for (auto test_event : test_events_) {
+ if (test_event == TestLoaderEvent::kBodyDataRead)
+ ++total_bytes;
+ }
+ return total_bytes;
+ }
+
+ void OnReadComplete(int32_t status, uint64_t size) {
+ EXPECT_EQ(net::OK, status);
+ EXPECT_EQ(GetLongUploadBody().size(), size);
+ read_run_loop_->Quit();
+ }
+
+ base::test::ScopedTaskEnvironment* scoped_task_environment_;
+
+ std::unique_ptr<net::URLRequest> url_request_;
+ mojo::Binding<network::mojom::URLLoader> binding_;
+ network::mojom::URLLoaderClientPtr client_;
+
+ std::vector<TestLoaderEvent> test_events_;
+
+ mojo::ScopedDataPipeProducerHandle body_stream_;
+
+ network::mojom::DataPipeGetterPtr data_pipe_getter_;
+ mojo::ScopedDataPipeConsumerHandle upload_data_pipe_;
+
+ std::unique_ptr<base::RunLoop> read_run_loop_;
+
+ base::WeakPtrFactory<MockURLLoader> weak_factory_for_data_pipe_callbacks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockURLLoader);
+};
+
+class MockURLLoaderFactory : public network::mojom::URLLoaderFactory {
+ public:
+ explicit MockURLLoaderFactory(
+ base::test::ScopedTaskEnvironment* scoped_task_environment)
+ : scoped_task_environment_(scoped_task_environment) {}
+ ~MockURLLoaderFactory() override {}
+
+ // network::mojom::URLLoaderFactory implementation:
+
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest url_loader_request,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest& url_request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override {
+ ASSERT_FALSE(test_events_.empty());
+ requested_urls_.push_back(url_request.url);
+ url_loaders_.push_back(std::make_unique<MockURLLoader>(
+ scoped_task_environment_, std::move(url_loader_request),
+ std::move(client), test_events_.front(), url_request.request_body));
+ test_events_.pop_front();
+
+ url_loader_queue_.push_back(url_loaders_.back().get());
+ }
+
+ void Clone(network::mojom::URLLoaderFactoryRequest request) override {
+ mojo::BindingId id = binding_set_.AddBinding(this, std::move(request));
+ if (close_new_binding_on_clone_)
+ binding_set_.RemoveBinding(id);
+ }
+
+ // Makes clone fail close the newly created binding after bining the request,
+ // Simulating the case where the network service goes away before the cloned
+ // interface is used.
+ void set_close_new_binding_on_clone(bool close_new_binding_on_clone) {
+ close_new_binding_on_clone_ = close_new_binding_on_clone;
+ }
+
+ // Adds a events that will be returned by a single MockURLLoader. Mutliple
+ // calls mean multiple MockURLLoaders are expected to be created. Each will
+ // run to completion before the next one is expected to be created.
+ void AddEvents(const std::vector<TestLoaderEvent> events) {
+ DCHECK(url_loaders_.empty());
+ test_events_.push_back(events);
+ }
+
+ // Runs all events for all created URLLoaders, in order.
+ void RunTest(SimpleLoaderTestHelper* test_helper,
+ bool wait_for_completion = true) {
+ network::mojom::URLLoaderFactoryPtr factory;
+ binding_set_.AddBinding(this, mojo::MakeRequest(&factory));
+
+ test_helper->StartSimpleLoader(factory.get());
+
+ // Wait for the first URLLoader to start receiving messages.
+ base::RunLoop().RunUntilIdle();
+
+ while (!url_loader_queue_.empty()) {
+ url_loader_queue_.front()->RunTest();
+ url_loader_queue_.pop_front();
+ }
+
+ if (wait_for_completion)
+ test_helper->Wait();
+
+ // All loads with added events should have been created and had their
+ // RunTest() methods called by the time the above loop completes.
+ EXPECT_TRUE(test_events_.empty());
+ }
+
+ const std::list<GURL>& requested_urls() const { return requested_urls_; }
+
+ private:
+ base::test::ScopedTaskEnvironment* scoped_task_environment_;
+ std::list<std::unique_ptr<MockURLLoader>> url_loaders_;
+ std::list<std::vector<TestLoaderEvent>> test_events_;
+
+ bool close_new_binding_on_clone_ = false;
+
+ // Queue of URLLoaders that have yet to had their RunTest method called.
+ // Separate list than |url_loaders_| so that old pipes aren't destroyed.
+ std::list<MockURLLoader*> url_loader_queue_;
+
+ std::list<GURL> requested_urls_;
+
+ mojo::BindingSet<network::mojom::URLLoaderFactory> binding_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockURLLoaderFactory);
+};
+
+// Check that the request fails if OnComplete() is called before anything else.
+TEST_P(SimpleURLLoaderTest, ResponseCompleteBeforeReceivedResponse) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kResponseComplete});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->simple_url_loader()->ResponseInfo());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+// Check that the request fails if OnComplete() is called before the body pipe
+// is received.
+TEST_P(SimpleURLLoaderTest, ResponseCompleteAfterReceivedResponse) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kResponseComplete});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, CloseClientPipeBeforeBodyStarts) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kClientPipeClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_FAILED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+// This test tries closing the client pipe / completing the request in most
+// possible valid orders relative to read events (Which always occur in the same
+// order).
+TEST_P(SimpleURLLoaderTest, CloseClientPipeOrder) {
+ enum class ClientCloseOrder {
+ kBeforeData,
+ kDuringData,
+ kAfterData,
+ kAfterBufferClosed,
+ };
+
+ // In what order the URLLoaderClient pipe is closed, relative to read events.
+ // Order of other main events can't vary, relative to each other (Getting body
+ // pipe, reading body bytes, closing body pipe).
+ const ClientCloseOrder kClientCloseOrder[] = {
+ ClientCloseOrder::kBeforeData, ClientCloseOrder::kDuringData,
+ ClientCloseOrder::kAfterData, ClientCloseOrder::kAfterBufferClosed,
+ };
+
+ const TestLoaderEvent kClientCloseEvents[] = {
+ TestLoaderEvent::kResponseComplete,
+ TestLoaderEvent::kResponseCompleteFailed,
+ TestLoaderEvent::kResponseCompleteTruncated,
+ TestLoaderEvent::kClientPipeClosed,
+ };
+
+ for (const auto close_client_order : kClientCloseOrder) {
+ for (const auto close_client_event : kClientCloseEvents) {
+ for (uint32_t bytes_received = 0; bytes_received < 3; bytes_received++) {
+ for (int allow_partial_results = 0; allow_partial_results < 2;
+ allow_partial_results++) {
+ if (close_client_order == ClientCloseOrder::kDuringData &&
+ bytes_received < 2) {
+ continue;
+ }
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ std::vector<TestLoaderEvent> events;
+ events.push_back(TestLoaderEvent::kReceivedResponse);
+ events.push_back(TestLoaderEvent::kBodyBufferReceived);
+ if (close_client_order == ClientCloseOrder::kBeforeData)
+ events.push_back(close_client_event);
+
+ for (uint32_t i = 0; i < bytes_received; ++i) {
+ events.push_back(TestLoaderEvent::kBodyDataRead);
+ if (i == 0 && close_client_order == ClientCloseOrder::kDuringData)
+ events.push_back(close_client_event);
+ }
+
+ if (close_client_order == ClientCloseOrder::kAfterData)
+ events.push_back(close_client_event);
+ events.push_back(TestLoaderEvent::kBodyBufferClosed);
+ if (close_client_order == ClientCloseOrder::kAfterBufferClosed)
+ events.push_back(close_client_event);
+ loader_factory.AddEvents(events);
+
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ test_helper->SetAllowPartialResults(allow_partial_results);
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ if (close_client_event != TestLoaderEvent::kResponseComplete) {
+ if (close_client_event ==
+ TestLoaderEvent::kResponseCompleteFailed) {
+ EXPECT_EQ(net::ERR_TIMED_OUT,
+ test_helper->simple_url_loader()->NetError());
+ } else {
+ EXPECT_EQ(net::ERR_FAILED,
+ test_helper->simple_url_loader()->NetError());
+ }
+ if (!allow_partial_results) {
+ EXPECT_FALSE(test_helper->response_body());
+ } else {
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(std::string(bytes_received, 'a'),
+ *test_helper->response_body());
+ }
+ } else {
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(std::string(bytes_received, 'a'),
+ *test_helper->response_body());
+ }
+ }
+ }
+ }
+ }
+}
+
+// Make sure the close client pipe message doesn't cause any issues.
+TEST_P(SimpleURLLoaderTest, ErrorAndCloseClientPipeBeforeBodyStarts) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kResponseCompleteFailed,
+ TestLoaderEvent::kClientPipeClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_TIMED_OUT, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+// Make sure the close client pipe message doesn't cause any issues.
+TEST_P(SimpleURLLoaderTest, SuccessAndCloseClientPipeBeforeBodyComplete) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kResponseComplete, TestLoaderEvent::kClientPipeClosed,
+ TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kBodyBufferClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("a", *test_helper->response_body());
+}
+
+// Make sure the close client pipe message doesn't cause any issues.
+TEST_P(SimpleURLLoaderTest, SuccessAndCloseClientPipeAfterBodyComplete) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseComplete, TestLoaderEvent::kClientPipeClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("a", *test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, DoubleReceivedResponse) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kReceivedResponse});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, RedirectAfterReseivedResponse) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kReceivedRedirect});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, UnexpectedBodyBufferReceived) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kBodyBufferReceived});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->simple_url_loader()->ResponseInfo());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, DoubleBodyBufferReceived) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyBufferReceived});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, UnexpectedMessageAfterBodyStarts) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kReceivedRedirect});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, UnexpectedMessageAfterBodyStarts2) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kBodyBufferReceived});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, UnexpectedMessageAfterBodyComplete) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kBodyBufferReceived});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, MoreDataThanExpected) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kBodyDataRead,
+ TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseCompleteWithExtraData});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_UNEXPECTED, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+TEST_P(SimpleURLLoaderTest, RetryOn5xx) {
+ const GURL kInitialURL("foo://bar/initial");
+ struct TestCase {
+ // Parameters passed to SetRetryOptions.
+ int max_retries;
+ int retry_mode;
+
+ // Number of 5xx responses before a successful response.
+ int num_5xx;
+
+ // Whether the request is expected to succeed in the end.
+ bool expect_success;
+
+ // Expected times the url should be requested.
+ int expected_num_requests;
+ } const kTestCases[] = {
+ // No retry on 5xx when retries disabled.
+ {0, SimpleURLLoader::RETRY_NEVER, 1, false, 1},
+
+ // No retry on 5xx when retries enabled on network change.
+ {1, SimpleURLLoader::RETRY_ON_NETWORK_CHANGE, 1, false, 1},
+
+ // As many retries allowed as 5xx errors.
+ {1, SimpleURLLoader::RETRY_ON_5XX, 1, true, 2},
+ {1,
+ SimpleURLLoader::RETRY_ON_5XX | SimpleURLLoader::RETRY_ON_NETWORK_CHANGE,
+ 1, true, 2},
+ {2, SimpleURLLoader::RETRY_ON_5XX, 2, true, 3},
+
+ // More retries than 5xx errors.
+ {2, SimpleURLLoader::RETRY_ON_5XX, 1, true, 2},
+
+ // Fewer retries than 5xx errors.
+ {1, SimpleURLLoader::RETRY_ON_5XX, 2, false, 2},
+ };
+
+ for (const auto& test_case : kTestCases) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ for (int i = 0; i < test_case.num_5xx; i++) {
+ loader_factory.AddEvents({TestLoaderEvent::kReceived501Response});
+ }
+
+ if (test_case.expect_success) {
+ // Valid response with a 1-byte body.
+ loader_factory.AddEvents({TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead,
+ TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseComplete});
+ }
+
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL(kInitialURL));
+ test_helper->simple_url_loader()->SetRetryOptions(test_case.max_retries,
+ test_case.retry_mode);
+ loader_factory.RunTest(test_helper.get());
+
+ if (test_case.expect_success) {
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(1u, test_helper->response_body()->size());
+ } else {
+ EXPECT_EQ(501, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+ }
+
+ EXPECT_EQ(static_cast<size_t>(test_case.expected_num_requests),
+ loader_factory.requested_urls().size());
+ for (const auto& url : loader_factory.requested_urls()) {
+ EXPECT_EQ(kInitialURL, url);
+ }
+
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM) {
+ EXPECT_EQ(test_case.expected_num_requests - 1,
+ test_helper->download_as_stream_retries());
+ }
+ }
+}
+
+// Test that when retrying on 5xx is enabled, there's no retry on a 4xx error.
+TEST_P(SimpleURLLoaderTest, NoRetryOn4xx) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kReceived401Response});
+
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(401, test_helper->GetResponseCode());
+ EXPECT_FALSE(test_helper->response_body());
+ EXPECT_EQ(1u, loader_factory.requested_urls().size());
+
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ EXPECT_EQ(0, test_helper->download_as_stream_retries());
+}
+
+// Checks that retrying after a redirect works. The original URL should be
+// re-requested.
+TEST_P(SimpleURLLoaderTest, RetryAfterRedirect) {
+ const GURL kInitialURL("foo://bar/initial");
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kReceivedRedirect,
+ TestLoaderEvent::kReceived501Response});
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kReceivedRedirect, TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseComplete});
+
+ int num_redirects = 0;
+
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(kInitialURL);
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+ test_helper->simple_url_loader()->SetOnRedirectCallback(base::BindRepeating(
+ [](int* num_redirects, const net::RedirectInfo& redirect_info,
+ const network::ResourceResponseHead& response_head) {
+ ++*num_redirects;
+ },
+ base::Unretained(&num_redirects)));
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ EXPECT_TRUE(test_helper->response_body());
+ EXPECT_EQ(2, num_redirects);
+
+ EXPECT_EQ(2u, loader_factory.requested_urls().size());
+ for (const auto& url : loader_factory.requested_urls()) {
+ EXPECT_EQ(kInitialURL, url);
+ }
+
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ EXPECT_EQ(1, test_helper->download_as_stream_retries());
+}
+
+TEST_P(SimpleURLLoaderTest, RetryOnNetworkChange) {
+ // TestLoaderEvents up to (and including) a network change. Since
+ // SimpleURLLoader always waits for the body buffer to be closed before
+ // retrying, everything that has a kBodyBufferReceived message must also have
+ // a kBodyBufferClosed message. Each test case will be tried against each of
+ // these event sequences.
+ const std::vector<std::vector<TestLoaderEvent>> kNetworkChangedEvents = {
+ {TestLoaderEvent::kResponseCompleteNetworkChanged},
+ {TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kResponseCompleteNetworkChanged},
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseCompleteNetworkChanged},
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kResponseCompleteNetworkChanged,
+ TestLoaderEvent::kBodyBufferClosed},
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseCompleteNetworkChanged},
+ {TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead,
+ TestLoaderEvent::kResponseCompleteNetworkChanged,
+ TestLoaderEvent::kBodyBufferClosed},
+ {TestLoaderEvent::kReceivedRedirect,
+ TestLoaderEvent::kResponseCompleteNetworkChanged},
+ };
+
+ const GURL kInitialURL("foo://bar/initial");
+
+ // Test cases in which to try each entry in kNetworkChangedEvents.
+ struct TestCase {
+ // Parameters passed to SetRetryOptions.
+ int max_retries;
+ int retry_mode;
+
+ // Number of network changes responses before a successful response.
+ // For each network change, the entire sequence of an entry in
+ // kNetworkChangedEvents is repeated.
+ int num_network_changes;
+
+ // Whether the request is expected to succeed in the end.
+ bool expect_success;
+
+ // Expected times the url should be requested.
+ int expected_num_requests;
+ } const kTestCases[] = {
+ // No retry on network change when retries disabled.
+ {0, SimpleURLLoader::RETRY_NEVER, 1, false, 1},
+
+ // No retry on network change when retries enabled on 5xx response.
+ {1, SimpleURLLoader::RETRY_ON_5XX, 1, false, 1},
+
+ // As many retries allowed as network changes.
+ {1, SimpleURLLoader::RETRY_ON_NETWORK_CHANGE, 1, true, 2},
+ {1,
+ SimpleURLLoader::RETRY_ON_NETWORK_CHANGE | SimpleURLLoader::RETRY_ON_5XX,
+ 1, true, 2},
+ {2, SimpleURLLoader::RETRY_ON_NETWORK_CHANGE, 2, true, 3},
+
+ // More retries than network changes.
+ {2, SimpleURLLoader::RETRY_ON_NETWORK_CHANGE, 1, true, 2},
+
+ // Fewer retries than network changes.
+ {1, SimpleURLLoader::RETRY_ON_NETWORK_CHANGE, 2, false, 2},
+ };
+
+ for (const auto& network_events : kNetworkChangedEvents) {
+ for (const auto& test_case : kTestCases) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ for (int i = 0; i < test_case.num_network_changes; i++) {
+ loader_factory.AddEvents(network_events);
+ }
+
+ if (test_case.expect_success) {
+ // Valid response with a 1-byte body.
+ loader_factory.AddEvents({TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived,
+ TestLoaderEvent::kBodyDataRead,
+ TestLoaderEvent::kBodyBufferClosed,
+ TestLoaderEvent::kResponseComplete});
+ }
+
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL(kInitialURL));
+ test_helper->simple_url_loader()->SetRetryOptions(test_case.max_retries,
+ test_case.retry_mode);
+ loader_factory.RunTest(test_helper.get());
+
+ if (test_case.expect_success) {
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(1u, test_helper->response_body()->size());
+ } else {
+ EXPECT_EQ(net::ERR_NETWORK_CHANGED,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->response_body());
+ }
+
+ EXPECT_EQ(static_cast<size_t>(test_case.expected_num_requests),
+ loader_factory.requested_urls().size());
+ for (const auto& url : loader_factory.requested_urls()) {
+ EXPECT_EQ(kInitialURL, url);
+ }
+
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM) {
+ EXPECT_EQ(test_case.expected_num_requests - 1,
+ test_helper->download_as_stream_retries());
+ }
+ }
+ }
+
+ // Check that there's no retry for each entry in kNetworkChangedEvents when an
+ // error other than a network change is received.
+ for (const auto& network_events : kNetworkChangedEvents) {
+ std::vector<TestLoaderEvent> modifed_network_events = network_events;
+ for (auto& test_loader_event : modifed_network_events) {
+ if (test_loader_event == TestLoaderEvent::kResponseCompleteNetworkChanged)
+ test_loader_event = TestLoaderEvent::kResponseCompleteFailed;
+ }
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(modifed_network_events);
+
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL(kInitialURL));
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::ERR_TIMED_OUT, test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->response_body());
+ EXPECT_EQ(1u, loader_factory.requested_urls().size());
+
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ EXPECT_EQ(0, test_helper->download_as_stream_retries());
+ }
+}
+
+// Check the case where the URLLoaderFactory has been disconnected before the
+// request is retried.
+TEST_P(SimpleURLLoaderTest, RetryWithUnboundFactory) {
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents({TestLoaderEvent::kResponseCompleteNetworkChanged});
+ // Since clone fails asynchronously, this shouldn't be any different from
+ // the new URLLoaderFactory being disconnected in some other way.
+ loader_factory.set_close_new_binding_on_clone(true);
+
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_NETWORK_CHANGE);
+ loader_factory.RunTest(test_helper.get());
+ EXPECT_EQ(net::ERR_FAILED, test_helper->simple_url_loader()->NetError());
+ EXPECT_FALSE(test_helper->response_body());
+
+ // Retry is still called, before the dead factory is discovered.
+ if (GetParam() == SimpleLoaderTestHelper::DownloadType::AS_STREAM)
+ EXPECT_EQ(1, test_helper->download_as_stream_retries());
+}
+
+// Test the case where DataPipeGetter::Read is called twice in a row,
+// with no intervening reads of the data on the pipe.
+TEST_P(SimpleURLLoaderTest, UploadLongStringStartReadTwice) {
+ std::string long_string = GetLongUploadBody();
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kStartReadLongUploadBody,
+ TestLoaderEvent::kStartReadLongUploadBody,
+ TestLoaderEvent::kWaitForLongUploadBodySize,
+ TestLoaderEvent::kReadLongUploadBody, TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kResponseComplete,
+ TestLoaderEvent::kBodyBufferClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(long_string,
+ "text/plain");
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("", *test_helper->response_body());
+}
+
+// Test the case where DataPipeGetter::Read is called a second time, after only
+// reading part of the response, with no intervening reads of the data on the
+// pipe.
+TEST_P(SimpleURLLoaderTest,
+ UploadLongStringReadPartOfUploadBodyBeforeRestartBodyRead) {
+ std::string long_string = GetLongUploadBody();
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ loader_factory.AddEvents(
+ {TestLoaderEvent::kStartReadLongUploadBody,
+ TestLoaderEvent::kWaitForLongUploadBodySize,
+ TestLoaderEvent::kReadFirstByteOfLongUploadBody,
+ TestLoaderEvent::kStartReadLongUploadBody,
+ TestLoaderEvent::kWaitForLongUploadBodySize,
+ TestLoaderEvent::kReadLongUploadBody, TestLoaderEvent::kReceivedResponse,
+ TestLoaderEvent::kBodyBufferReceived, TestLoaderEvent::kResponseComplete,
+ TestLoaderEvent::kBodyBufferClosed});
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(long_string,
+ "text/plain");
+ loader_factory.RunTest(test_helper.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("", *test_helper->response_body());
+}
+
+// Test for GetFinalURL.
+TEST_P(SimpleURLLoaderTest, GetFinalURL) {
+ GURL url = test_server_.GetURL("/echo");
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ resource_request->url = url;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelper(std::move(resource_request));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(url, test_helper->simple_url_loader()->GetFinalURL());
+}
+
+// Test for GetFinalURL with a redirect.
+TEST_P(SimpleURLLoaderTest, GetFinalURLAfterRedirect) {
+ GURL url = test_server_.GetURL("/echo");
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/server-redirect?" + url.spec()));
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(url, test_helper->simple_url_loader()->GetFinalURL());
+}
+
+INSTANTIATE_TEST_CASE_P(
+ /* No prefix */,
+ SimpleURLLoaderTest,
+ testing::Values(SimpleLoaderTestHelper::DownloadType::TO_STRING,
+ SimpleLoaderTestHelper::DownloadType::TO_FILE,
+ SimpleLoaderTestHelper::DownloadType::TO_TEMP_FILE,
+ SimpleLoaderTestHelper::DownloadType::AS_STREAM));
+
+class SimpleURLLoaderFileTest : public SimpleURLLoaderTestBase,
+ public testing::Test {
+ public:
+ SimpleURLLoaderFileTest() {}
+ ~SimpleURLLoaderFileTest() override {}
+
+ std::unique_ptr<SimpleLoaderTestHelper> CreateHelperForURL(const GURL& url) {
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ resource_request->url = url;
+ return std::make_unique<SimpleLoaderTestHelper>(
+ std::move(resource_request),
+ SimpleLoaderTestHelper::DownloadType::TO_FILE);
+ }
+};
+
+// Make sure that an existing file will be completely overwritten.
+TEST_F(SimpleURLLoaderFileTest, OverwriteFile) {
+ std::string junk_data(100, '!');
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("data:text/plain,foo"));
+ {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ ASSERT_EQ(static_cast<int>(junk_data.size()),
+ base::WriteFile(test_helper->dest_path(), junk_data.data(),
+ junk_data.size()));
+ ASSERT_TRUE(base::PathExists(test_helper->dest_path()));
+ }
+
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->simple_url_loader()->ResponseInfo());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ("foo", *test_helper->response_body());
+}
+
+// Make sure that file creation errors are handled correctly.
+TEST_F(SimpleURLLoaderFileTest, FileCreateError) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("data:text/plain,foo"));
+ {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ ASSERT_TRUE(base::CreateDirectory(test_helper->dest_path()));
+ ASSERT_TRUE(base::PathExists(test_helper->dest_path()));
+ }
+
+ // The directory should still exist after the download fails.
+ test_helper->set_expect_path_exists_on_error(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::ERR_ACCESS_DENIED,
+ test_helper->simple_url_loader()->NetError());
+ EXPECT_TRUE(test_helper->simple_url_loader()->ResponseInfo());
+ EXPECT_FALSE(test_helper->response_body());
+}
+
+// Make sure that destroying the loader destroys a partially downloaded file.
+TEST_F(SimpleURLLoaderFileTest, DeleteLoaderDuringRequestDestroysFile) {
+ for (bool body_data_read : {false, true}) {
+ for (bool body_buffer_closed : {false, true}) {
+ for (bool client_pipe_closed : {false, true}) {
+ // If both pipes were closed cleanly, the file shouldn't be deleted, as
+ // that indicates success.
+ if (body_buffer_closed && client_pipe_closed)
+ continue;
+
+ MockURLLoaderFactory loader_factory(&scoped_task_environment_);
+ std::vector<TestLoaderEvent> events;
+ events.push_back(TestLoaderEvent::kReceivedResponse);
+ events.push_back(TestLoaderEvent::kBodyBufferReceived);
+ if (body_data_read)
+ events.push_back(TestLoaderEvent::kBodyDataRead);
+ if (body_buffer_closed)
+ events.push_back(TestLoaderEvent::kBodyBufferClosed);
+ if (client_pipe_closed)
+ events.push_back(TestLoaderEvent::kClientPipeClosed);
+ loader_factory.AddEvents(events);
+
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(GURL("foo://bar/"));
+
+ // Run events without waiting for the request to complete, since the
+ // request will hang.
+ loader_factory.RunTest(test_helper.get(),
+ false /* wait_for_completion */);
+
+ // Wait for the request to advance as far as it's going to.
+ scoped_task_environment_.RunUntilIdle();
+
+ // Destination file should have been created, and request should still
+ // be in progress.
+ base::FilePath dest_path = test_helper->dest_path();
+ {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ EXPECT_TRUE(base::PathExists(dest_path));
+ EXPECT_FALSE(test_helper->done());
+ }
+
+ // Destroying the SimpleURLLoader now should post a task to destroy the
+ // file.
+ test_helper->DestroySimpleURLLoader();
+ scoped_task_environment_.RunUntilIdle();
+ {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+ EXPECT_FALSE(base::PathExists(dest_path));
+ }
+ }
+ }
+ }
+}
+
+// Used for testing stream-specific features.
+class SimpleURLLoaderStreamTest : public SimpleURLLoaderTestBase,
+ public testing::Test {
+ public:
+ SimpleURLLoaderStreamTest() {}
+ ~SimpleURLLoaderStreamTest() override {}
+
+ std::unique_ptr<SimpleLoaderTestHelper> CreateHelperForURL(
+ const GURL& url,
+ const std::string& method = "GET") {
+ std::unique_ptr<network::ResourceRequest> resource_request =
+ std::make_unique<network::ResourceRequest>();
+ resource_request->url = url;
+ resource_request->method = method;
+ return std::make_unique<SimpleLoaderTestHelper>(
+ std::move(resource_request),
+ SimpleLoaderTestHelper::DownloadType::AS_STREAM);
+ }
+};
+
+TEST_F(SimpleURLLoaderStreamTest, OnDataReceivedCompletesAsync) {
+ const uint32_t kResponseSize = 2 * 1024 * 1024;
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(
+ base::StringPrintf("/response-size?%u", kResponseSize)));
+ test_helper->set_download_to_stream_async_resume(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ EXPECT_EQ(200, test_helper->GetResponseCode());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kResponseSize, test_helper->response_body()->length());
+ EXPECT_EQ(std::string(kResponseSize, 'a'), *test_helper->response_body());
+ EXPECT_EQ(0, test_helper->download_as_stream_retries());
+}
+
+// Test case where class is destroyed during OnDataReceived. Main purpose is to
+// make sure there's not a crash.
+TEST_F(SimpleURLLoaderStreamTest, OnDataReceivedDestruction) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL("/response-size?1"));
+ test_helper->set_download_to_stream_destroy_on_data_received(true);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_FALSE(test_helper->simple_url_loader());
+ // Make sure no pending task results in a crash.
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(SimpleURLLoaderStreamTest, OnRetryCompletesAsync) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kFailOnceThenEchoBody), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(kShortUploadBody,
+ "text/plain");
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+ EXPECT_EQ(net::OK, test_helper->simple_url_loader()->NetError());
+ ASSERT_TRUE(test_helper->response_body());
+ EXPECT_EQ(kShortUploadBody, *test_helper->response_body());
+ EXPECT_EQ(1, test_helper->download_as_stream_retries());
+}
+
+// Test case where class is destroyed during OnRetry. While setting the loader
+// to retry and then destroying it on retry is perhaps a bit strange, seems best
+// to be consistent in the provided API. Main purpose of this test is to make
+// sure there's not a crash.
+TEST_F(SimpleURLLoaderStreamTest, OnRetryDestruction) {
+ std::unique_ptr<SimpleLoaderTestHelper> test_helper =
+ CreateHelperForURL(test_server_.GetURL(kFailOnceThenEchoBody), "POST");
+ test_helper->simple_url_loader()->AttachStringForUpload(kShortUploadBody,
+ "text/plain");
+ test_helper->set_download_to_stream_destroy_on_retry(true);
+ test_helper->simple_url_loader()->SetRetryOptions(
+ 1, SimpleURLLoader::RETRY_ON_5XX);
+ test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
+
+ EXPECT_FALSE(test_helper->simple_url_loader());
+ // Make sure no pending task results in a crash.
+ base::RunLoop().RunUntilIdle();
+}
+
+} // namespace
+} // namespace network
diff --git a/chromium/services/network/public/cpp/url_loader_completion_status.h b/chromium/services/network/public/cpp/url_loader_completion_status.h
index 3f4a3037ada..4d474d1d716 100644
--- a/chromium/services/network/public/cpp/url_loader_completion_status.h
+++ b/chromium/services/network/public/cpp/url_loader_completion_status.h
@@ -7,16 +7,17 @@
#include <stdint.h>
+#include "base/component_export.h"
#include "base/macros.h"
#include "base/optional.h"
#include "base/time/time.h"
#include "net/ssl/ssl_info.h"
#include "services/network/public/cpp/cors/cors_error_status.h"
-#include "services/network/public/interfaces/cors.mojom-shared.h"
+#include "services/network/public/mojom/cors.mojom-shared.h"
namespace network {
-struct URLLoaderCompletionStatus {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE) URLLoaderCompletionStatus {
URLLoaderCompletionStatus();
URLLoaderCompletionStatus(const URLLoaderCompletionStatus& status);
diff --git a/chromium/services/network/public/cpp/url_loader_completion_status.typemap b/chromium/services/network/public/cpp/url_loader_completion_status.typemap
index 65416e4e715..1ac83e89fff 100644
--- a/chromium/services/network/public/cpp/url_loader_completion_status.typemap
+++ b/chromium/services/network/public/cpp/url_loader_completion_status.typemap
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/url_loader.mojom"
+mojom = "//services/network/public/mojom/url_loader.mojom"
public_headers =
[ "//services/network/public/cpp/url_loader_completion_status.h" ]
traits_headers = [ "//services/network/public/cpp/network_param_ipc_traits.h" ]
@@ -10,7 +10,7 @@ deps = [
"//net",
]
public_deps = [
- "//services/network/public/cpp:typemap_dependencies",
+ "//services/network/public/cpp:cpp_base",
]
type_mappings = [
"network.mojom.URLLoaderCompletionStatus=network::URLLoaderCompletionStatus",
diff --git a/chromium/services/network/public/cpp/url_request.typemap b/chromium/services/network/public/cpp/url_request.typemap
index 92dac7e13f0..f4046a46156 100644
--- a/chromium/services/network/public/cpp/url_request.typemap
+++ b/chromium/services/network/public/cpp/url_request.typemap
@@ -2,14 +2,14 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/url_loader.mojom"
+mojom = "//services/network/public/mojom/url_loader.mojom"
public_headers = [ "//services/network/public/cpp/resource_request.h" ]
traits_headers = [
"//services/network/public/cpp/network_param_ipc_traits.h",
- "//services/network/public/cpp/url_request_struct_traits.h",
+ "//services/network/public/cpp/url_request_mojom_traits.h",
]
public_deps = [
- "//services/network/public/cpp:typemap_dependencies",
+ "//services/network/public/cpp:cpp_base",
]
type_mappings = [
"network.mojom.URLRequest=network::ResourceRequest",
diff --git a/chromium/services/network/public/cpp/url_request_struct_traits.cc b/chromium/services/network/public/cpp/url_request_mojom_traits.cc
index 61a1e1983a0..b03e9de3b39 100644
--- a/chromium/services/network/public/cpp/url_request_struct_traits.cc
+++ b/chromium/services/network/public/cpp/url_request_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/network/public/cpp/url_request_struct_traits.h"
+#include "services/network/public/cpp/url_request_mojom_traits.h"
#include "base/logging.h"
diff --git a/chromium/services/network/public/cpp/url_request_struct_traits.h b/chromium/services/network/public/cpp/url_request_mojom_traits.h
index 30f4b7ab555..3e9a34f6933 100644
--- a/chromium/services/network/public/cpp/url_request_struct_traits.h
+++ b/chromium/services/network/public/cpp/url_request_mojom_traits.h
@@ -2,17 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_NETWORK_PUBLIC_CPP_URL_REQUEST_STRUCT_TRAITS_H_
-#define SERVICES_NETWORK_PUBLIC_CPP_URL_REQUEST_STRUCT_TRAITS_H_
+#ifndef SERVICES_NETWORK_PUBLIC_CPP_URL_REQUEST_MOJOM_TRAITS_H_
+#define SERVICES_NETWORK_PUBLIC_CPP_URL_REQUEST_MOJOM_TRAITS_H_
+#include "base/component_export.h"
#include "mojo/public/cpp/bindings/enum_traits.h"
#include "net/base/request_priority.h"
-#include "services/network/public/interfaces/url_loader.mojom-shared.h"
+#include "services/network/public/mojom/url_loader.mojom-shared.h"
namespace mojo {
template <>
-struct EnumTraits<network::mojom::RequestPriority, net::RequestPriority> {
+struct COMPONENT_EXPORT(NETWORK_CPP_BASE)
+ EnumTraits<network::mojom::RequestPriority, net::RequestPriority> {
static network::mojom::RequestPriority ToMojom(net::RequestPriority priority);
static bool FromMojom(network::mojom::RequestPriority in,
net::RequestPriority* out);
@@ -20,4 +22,4 @@ struct EnumTraits<network::mojom::RequestPriority, net::RequestPriority> {
} // namespace mojo
-#endif // SERVICES_NETWORK_PUBLIC_CPP_URL_REQUEST_STRUCT_TRAITS_H_
+#endif // SERVICES_NETWORK_PUBLIC_CPP_URL_REQUEST_MOJOM_TRAITS_H_
diff --git a/chromium/services/network/public/cpp/url_request_redirect_info.typemap b/chromium/services/network/public/cpp/url_request_redirect_info.typemap
index 9f77e3c8a1a..a8162bf821b 100644
--- a/chromium/services/network/public/cpp/url_request_redirect_info.typemap
+++ b/chromium/services/network/public/cpp/url_request_redirect_info.typemap
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/url_loader.mojom"
+mojom = "//services/network/public/mojom/url_loader.mojom"
public_headers = [ "//net/url_request/redirect_info.h" ]
traits_headers = [ "//services/network/public/cpp/network_param_ipc_traits.h" ]
public_deps = [
diff --git a/chromium/services/network/public/cpp/url_response_head.typemap b/chromium/services/network/public/cpp/url_response_head.typemap
index 66e8663dc06..7987df11252 100644
--- a/chromium/services/network/public/cpp/url_response_head.typemap
+++ b/chromium/services/network/public/cpp/url_response_head.typemap
@@ -2,11 +2,11 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/network/public/interfaces/url_loader.mojom"
+mojom = "//services/network/public/mojom/url_loader.mojom"
public_headers = [ "//services/network/public/cpp/resource_response.h" ]
traits_headers = [ "//services/network/public/cpp/network_param_ipc_traits.h" ]
public_deps = [
- "//services/network/public/cpp:typemap_dependencies",
+ "//services/network/public/cpp:cpp_base",
]
type_mappings =
[ "network.mojom.URLResponseHead=network::ResourceResponseHead" ]
diff --git a/chromium/services/network/public/interfaces/BUILD.gn b/chromium/services/network/public/mojom/BUILD.gn
index 19ac4076e22..ada8db31deb 100644
--- a/chromium/services/network/public/interfaces/BUILD.gn
+++ b/chromium/services/network/public/mojom/BUILD.gn
@@ -27,7 +27,30 @@ mojom("data_pipe_interface") {
}
}
-mojom("interfaces") {
+mojom("mutable_network_traffic_annotation_interface") {
+ sources = [
+ "mutable_network_traffic_annotation_tag.mojom",
+ "mutable_partial_network_traffic_annotation_tag.mojom",
+ ]
+}
+
+# UDP socket interface relies on mojo.common.mojom.ReadOnlyBuffer, which is
+# mapped to base::span<const uint8_t>. ReadOnlyBufffer doesn't yet work with
+# lazy serialization, so this needs to be in a separate target that doesn't have
+# support_lazy_serialization = true.
+mojom("udp_socket_interface") {
+ sources = [
+ "udp_socket.mojom",
+ ]
+
+ public_deps = [
+ ":mutable_network_traffic_annotation_interface",
+ "//mojo/common:read_only_buffer",
+ "//net/interfaces:interfaces",
+ ]
+}
+
+mojom("mojom") {
# URLLoader & URLLoaderFactory are used in-process in the browser when
# navigation uses URLLoader (NavigationMojoResponse) and in the renderer
# when Service Worker uses direct communication (S13nServiceWorker).
@@ -38,8 +61,6 @@ mojom("interfaces") {
"cors.mojom",
"fetch_api.mojom",
"http_request_headers.mojom",
- "mutable_network_traffic_annotation_tag.mojom",
- "mutable_partial_network_traffic_annotation_tag.mojom",
"network_change_manager.mojom",
"network_service.mojom",
"network_service_test.mojom",
@@ -53,9 +74,11 @@ mojom("interfaces") {
public_deps = [
":data_pipe_interface",
+ ":mutable_network_traffic_annotation_interface",
+ ":udp_socket_interface",
"//mojo/common:common_custom_types",
- "//services/proxy_resolver/public/interfaces",
- "//url/mojo:url_mojom_gurl",
+ "//services/proxy_resolver/public/mojom",
+ "//url/mojom:url_mojom_gurl",
]
# TODO(crbug/598073): When moving the service implementation to
diff --git a/chromium/services/network/public/interfaces/OWNERS b/chromium/services/network/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/network/public/interfaces/OWNERS
+++ b/chromium/services/network/public/mojom/OWNERS
diff --git a/chromium/services/network/public/interfaces/cookie_manager.mojom b/chromium/services/network/public/mojom/cookie_manager.mojom
index 37dc116a328..d1df23dbd6a 100644
--- a/chromium/services/network/public/interfaces/cookie_manager.mojom
+++ b/chromium/services/network/public/mojom/cookie_manager.mojom
@@ -5,7 +5,7 @@
module network.mojom;
import "mojo/common/time.mojom";
-import "url/mojo/url.mojom";
+import "url/mojom/url.mojom";
enum CookiePriority {
LOW,
@@ -137,9 +137,9 @@ struct CookieDeletionFilter {
CookieDeletionSessionControl session_control = IGNORE_CONTROL;
};
-interface CookieChangeNotification {
+interface CookieChangeListener {
// TODO(rdsmith): Should this be made a batch interface?
- OnCookieChanged(CanonicalCookie cookie, CookieChangeCause cause);
+ OnCookieChange(CanonicalCookie cookie, CookieChangeCause cause);
};
interface CookieManager {
@@ -173,34 +173,37 @@ interface CookieManager {
// Returns the number of cookies deleted.
DeleteCookies(CookieDeletionFilter filter) => (uint32 num_deleted);
- // Send a CookieChangeNotification over which notification
- // for cookie changes will be sent. When the specified cookie
- // associated with the domain/path specified in the URL changes, a
- // notification will be posted to the passed pointer.
+ // Subscribes the given listener to changes to a cookie.
+ //
+ // The subscription is canceled by closing the CookieChangeListener's pipe.
//
// Note that if the caller may be racing with other uses of the cookie store,
- // it should follow the notification request with a probe of the relevant
+ // it should follow the subscription request with a probe of the relevant
// information about the tracked cookie, to make sure that a change to the
- // cookie did not happen while the notification was being installed.
+ // cookie did not happen right before the listener was registered.
//
// TODO(rdsmith): Should this have a filter to register for a lot of
// notifications at once? Maybe combine with the deletion filter?
- RequestNotification(
+ // TODO(rdsmith): Describe the performance implications of using this meethod.
+ // The comments in CookieMonster::AddCallbackForCookie look pretty scary.
+ AddCookieChangeListener(
url.mojom.Url url,
string name,
- CookieChangeNotification notification_pointer);
+ CookieChangeListener listener);
- // Send a CookieChangeNotification over which notification
- // for all cookie changes will be sent. When a cookie associated with
- // the CookieManager changes, a notification will be posted to the
- // passed pointer.
+ // Subscribes the given listener to changes to this CookieManager's cookies.
+ //
+ // The subscription is canceled by closing the CookieChangeListener's pipe.
//
// TODO(rdsmith): Should this have a filter to register for a lot of
// notifications at once? Maybe combine with the deletion filter?
- RequestGlobalNotifications(CookieChangeNotification notification_pointer);
+ AddGlobalChangeListener(CookieChangeListener notification_pointer);
// Clone the interface for use somewhere else. After this call,
// requests to the same implementation may be posted to the other side
// of the pipe new_interface was configured on.
CloneInterface(CookieManager& new_interface);
+
+ // Flush the backing store (if any) to disk.
+ FlushCookieStore() => ();
};
diff --git a/chromium/services/network/public/interfaces/cors.mojom b/chromium/services/network/public/mojom/cors.mojom
index 2a9f393134a..57d4cee6af9 100644
--- a/chromium/services/network/public/interfaces/cors.mojom
+++ b/chromium/services/network/public/mojom/cors.mojom
@@ -16,7 +16,6 @@ enum CORSError {
kDisallowedByMode,
kInvalidResponse,
kAllowOriginMismatch,
- kSubOriginMismatch,
kWildcardOriginNotAllowed,
kMissingAllowOriginHeader,
kMultipleAllowOriginValues,
@@ -31,6 +30,20 @@ enum CORSError {
kPreflightMissingAllowExternal,
kPreflightInvalidAllowExternal,
+ // Failed to parse Access-Control-Allow-Methods response header field in
+ // CORS-preflight response.
+ kInvalidAllowMethodsPreflightResponse,
+
+ // Failed to parse Access-Control-Allow-Headers response header field in
+ // CORS-preflight response.
+ kInvalidAllowHeadersPreflightResponse,
+
+ // Not allowed by Access-Control-Allow-Methods in CORS-preflight response.
+ kMethodDisallowedByPreflightResponse,
+
+ // Not allowed by Access-Control-Allow-Headers in CORS-preflight response.
+ kHeaderDisallowedByPreflightResponse,
+
// Redirect
kRedirectDisallowedScheme,
kRedirectContainsCredentials,
diff --git a/chromium/services/network/public/interfaces/data_pipe_getter.mojom b/chromium/services/network/public/mojom/data_pipe_getter.mojom
index 551ca481c1c..551ca481c1c 100644
--- a/chromium/services/network/public/interfaces/data_pipe_getter.mojom
+++ b/chromium/services/network/public/mojom/data_pipe_getter.mojom
diff --git a/chromium/services/network/public/interfaces/fetch_api.mojom b/chromium/services/network/public/mojom/fetch_api.mojom
index 8239aa0246d..8239aa0246d 100644
--- a/chromium/services/network/public/interfaces/fetch_api.mojom
+++ b/chromium/services/network/public/mojom/fetch_api.mojom
diff --git a/chromium/services/network/public/interfaces/http_request_headers.mojom b/chromium/services/network/public/mojom/http_request_headers.mojom
index 5e38006e3e1..5e38006e3e1 100644
--- a/chromium/services/network/public/interfaces/http_request_headers.mojom
+++ b/chromium/services/network/public/mojom/http_request_headers.mojom
diff --git a/chromium/services/network/public/interfaces/mutable_network_traffic_annotation_tag.mojom b/chromium/services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom
index 34ab3a379ed..34ab3a379ed 100644
--- a/chromium/services/network/public/interfaces/mutable_network_traffic_annotation_tag.mojom
+++ b/chromium/services/network/public/mojom/mutable_network_traffic_annotation_tag.mojom
diff --git a/chromium/services/network/public/interfaces/mutable_partial_network_traffic_annotation_tag.mojom b/chromium/services/network/public/mojom/mutable_partial_network_traffic_annotation_tag.mojom
index 265814c38cc..265814c38cc 100644
--- a/chromium/services/network/public/interfaces/mutable_partial_network_traffic_annotation_tag.mojom
+++ b/chromium/services/network/public/mojom/mutable_partial_network_traffic_annotation_tag.mojom
diff --git a/chromium/services/network/public/interfaces/network_change_manager.mojom b/chromium/services/network/public/mojom/network_change_manager.mojom
index ce157d501bf..ce157d501bf 100644
--- a/chromium/services/network/public/interfaces/network_change_manager.mojom
+++ b/chromium/services/network/public/mojom/network_change_manager.mojom
diff --git a/chromium/services/network/public/interfaces/network_service.mojom b/chromium/services/network/public/mojom/network_service.mojom
index e9f0fa7840b..95fe60b1fd5 100644
--- a/chromium/services/network/public/interfaces/network_service.mojom
+++ b/chromium/services/network/public/mojom/network_service.mojom
@@ -7,19 +7,30 @@ module network.mojom;
import "cookie_manager.mojom";
import "network_change_manager.mojom";
import "proxy_config.mojom";
+import "net/interfaces/ip_endpoint.mojom";
import "url_loader.mojom";
import "url_loader_factory.mojom";
import "restricted_cookie_manager.mojom";
import "mojo/common/file_path.mojom";
import "mojo/common/time.mojom";
-import "url/mojo/url.mojom";
-import "services/proxy_resolver/public/interfaces/proxy_resolver.mojom";
+import "url/mojom/url.mojom";
+import "services/network/public/mojom/udp_socket.mojom";
+import "services/proxy_resolver/public/mojom/proxy_resolver.mojom";
+
+[Native]
+struct AuthChallengeInfo;
+
+[Native]
+struct AuthCredentials;
// Parameters for constructing a network context.
struct NetworkContextParams {
// Name used by memory tools to identify the context.
string? context_name;
+ // The user agent string.
+ string user_agent;
+
// Whether Brotli content-encoding should be enabled for HTTPS responses.
bool enable_brotli = true;
@@ -118,11 +129,6 @@ interface NetworkContext {
CreateURLLoaderFactory(URLLoaderFactory& url_loader_factory,
uint32 process_id);
- // Handles a request to display cache data to the user. |url| is parsed to
- // display different parts of the cache.
- HandleViewCacheRequest(url.mojom.Url url,
- URLLoaderClient client);
-
// Gets the CookieManager associated with this network context.
GetCookieManager(CookieManager& cookie_manager);
@@ -149,6 +155,14 @@ interface NetworkContext {
// TODO(caseq): get rid of header, make profile_id part of ResourceRequest.
SetNetworkConditions(string profile_id, NetworkConditions? conditions);
+ // Creates a UDP socket. Caller can supply a |receiver| interface pointer
+ // to listen for incoming datagrams. A null |receiver| is acceptable if caller
+ // is not interested in incoming data.
+ // Any sockets that are created but are yet to be destroyed will be destroyed
+ // when NetworkContext goes away.
+ CreateUDPSocket(network.mojom.UDPSocket& request,
+ network.mojom.UDPSocketReceiver? receiver);
+
[Sync]
// Adds explicitly-specified data as if it was processed from an
// HSTS header.
@@ -157,8 +171,51 @@ interface NetworkContext {
bool include_subdomains) => ();
};
+// The content/browser implementation of this SSLPrivateKey interface wraps the
+// scoped_refptr<net::SSLPrivateKey> that is received from
+// SSLClientAuthDelegate::ContinueWithCertificate(), and this mojo interface is
+// sent from content/browser to services/network so that services/network can
+// have its own net::SSLPrivateKey implementation that internally uses this mojo
+// interface.
+// The |algorithm| and |input| parameters correspond to the |algorithm| and
+// |input| parameters in net::SSLPrivateKey::Sign().
+// The |net_error| and |signature| parameters correspond to the parameters in
+// net::SSLPrivateKey::SignCallback.
+interface SSLPrivateKey {
+ Sign(uint16 algorithm,
+ array<uint8> input) => (int32 net_error, array<uint8> signature);
+};
+
// Network service interface to the browser.
interface NetworkServiceClient {
+ // Called when we receive an authentication failure.
+ // The |credentials| output parameter is given to URLRequest::SetAuth()
+ // through this mojo interface. It is not set when URLRequest::CancelAuth()
+ // needs to be called.
+ OnAuthRequired(uint32 process_id,
+ uint32 routing_id,
+ url.mojom.Url url,
+ bool first_auth_attempt,
+ AuthChallengeInfo auth_info) => (AuthCredentials? credentials);
+ // Called when an SSL certificate requested message is received for client
+ // authentication.
+ // The |algorithm_preferences| parameter corresponds to the return value
+ // of net::SSLPrivateKey::GetAlgorithmPreferences().
+ // The |cancel_certificate_selection| parameter is used to distinguish
+ // between the following two cases because the |x509_certificate| will be
+ // nullptr in both cases:
+ // 1. The connection is continued with no client cert,
+ // net::URLRequest::ContinueWithCertificate(nullptr, nullptr) needs to be
+ // called.
+ // 2. The request is aborted, net::URLRequest::CancelWithError() needs to be
+ // called.
+ OnCertificateRequested(uint32 process_id,
+ uint32 routing_id,
+ network.mojom.SSLCertRequestInfo cert_info) => (
+ network.mojom.X509Certificate x509_certificate,
+ array<uint16> algorithm_preferences,
+ SSLPrivateKey ssl_private_key,
+ bool cancel_certificate_selection);
// Called when an SSL certificate is encountered.
// The callback argument is a net::ERROR value. If it's net::OK, then the
// request is resumed. Otherwise it's cancelled with the given error.
diff --git a/chromium/services/network/public/interfaces/network_service_test.mojom b/chromium/services/network/public/mojom/network_service_test.mojom
index a78397bf5bf..a78397bf5bf 100644
--- a/chromium/services/network/public/interfaces/network_service_test.mojom
+++ b/chromium/services/network/public/mojom/network_service_test.mojom
diff --git a/chromium/services/network/public/interfaces/network_types.mojom b/chromium/services/network/public/mojom/network_types.mojom
index d3adda5d6b5..d3adda5d6b5 100644
--- a/chromium/services/network/public/interfaces/network_types.mojom
+++ b/chromium/services/network/public/mojom/network_types.mojom
diff --git a/chromium/services/network/public/interfaces/proxy_config.mojom b/chromium/services/network/public/mojom/proxy_config.mojom
index 9cc58ff2a1d..232cba72fc1 100644
--- a/chromium/services/network/public/interfaces/proxy_config.mojom
+++ b/chromium/services/network/public/mojom/proxy_config.mojom
@@ -4,7 +4,7 @@
module network.mojom;
-import "url/mojo/url.mojom";
+import "url/mojom/url.mojom";
// This corresponds to the string representation of net::ProxyConfigBypassRules.
struct ProxyBypassRules {
@@ -19,9 +19,9 @@ struct ProxyList {
// This corresponds to net::ProxyConfig::ProxyRules::Type.
enum ProxyRulesType {
- TYPE_NO_RULES,
- TYPE_SINGLE_PROXY,
- TYPE_PROXY_PER_SCHEME,
+ EMPTY,
+ PROXY_LIST,
+ PROXY_LIST_PER_SCHEME,
};
// These fields mirror those of net::ProxyConfig::ProxyRules.
@@ -55,8 +55,6 @@ struct ProxyConfig {
bool pac_mandatory;
ProxyRules proxy_rules;
ProxyConfigSource source;
- // TODO(mmenke): This is a historical wart. Remove it.
- int32 id;
};
// Interface for pushing proxy configuration updates to a NetworkContext.
diff --git a/chromium/services/network/public/interfaces/request_context_frame_type.mojom b/chromium/services/network/public/mojom/request_context_frame_type.mojom
index 838cab5714d..838cab5714d 100644
--- a/chromium/services/network/public/interfaces/request_context_frame_type.mojom
+++ b/chromium/services/network/public/mojom/request_context_frame_type.mojom
diff --git a/chromium/services/network/public/interfaces/restricted_cookie_manager.mojom b/chromium/services/network/public/mojom/restricted_cookie_manager.mojom
index 3dd9eb99535..c6344786913 100644
--- a/chromium/services/network/public/interfaces/restricted_cookie_manager.mojom
+++ b/chromium/services/network/public/mojom/restricted_cookie_manager.mojom
@@ -6,7 +6,7 @@ module network.mojom;
import "cookie_manager.mojom";
import "mojo/common/time.mojom";
-import "url/mojo/url.mojom";
+import "url/mojom/url.mojom";
enum CookieMatchType {
EQUALS,
diff --git a/chromium/services/network/public/mojom/udp_socket.mojom b/chromium/services/network/public/mojom/udp_socket.mojom
new file mode 100644
index 00000000000..5ea79d8d743
--- /dev/null
+++ b/chromium/services/network/public/mojom/udp_socket.mojom
@@ -0,0 +1,198 @@
+// Copyright 2018 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.
+
+module network.mojom;
+
+import "mutable_network_traffic_annotation_tag.mojom";
+import "mojo/common/read_only_buffer.mojom";
+import "net/interfaces/address_family.mojom";
+import "net/interfaces/ip_address.mojom";
+import "net/interfaces/ip_endpoint.mojom";
+
+// Represents options that consumers can set when requesting a UDPSocket
+// interface pointer.
+struct UDPSocketOptions {
+ // If true, this enables SO_REUSEADDR on the underlying socket.
+ bool allow_address_reuse = false;
+ // Sets interface to use for multicast. Default value is 0, in which case the
+ // default interface is used.
+ uint32 multicast_interface = 0;
+ // Sets the time-to-live option for UDP packets sent to the multicast
+ // group address. The default value of this option is 1. Cannot be more than
+ // 255.
+ uint32 multicast_time_to_live = 1;
+ // Sets the loopback flag for UDP socket. If this flag is true and the socket
+ // joins a group through JoinGroup(), the socket will receive packets sent to
+ // the joined group from itself. The default value of this option is true.
+ //
+ // Note: the behavior of |SetMulticastLoopbackMode| is slightly
+ // different between Windows and Unix-like systems. The inconsistency only
+ // happens when there are more than one applications on the same host
+ // joined to the same multicast group while having different settings on
+ // multicast loopback mode. On Windows, the applications with loopback off
+ // will not RECEIVE the loopback packets; while on Unix-like systems, the
+ // applications with loopback off will not SEND the loopback packets to
+ // other applications on the same host. See MSDN: http://goo.gl/6vqbj
+ bool multicast_loopback_mode = true;
+ // Sets the OS send buffer size (in bytes) for the socket. This is the
+ // SO_SNDBUF socket option. This socket option matters less for UDP socket (as
+ // compared to TCP), because in theory all UDP data written to the kernel
+ // should directly go out to the network. The kernel usually doesn't need to
+ // buffer send data. Default value is 0, in which case, OS's default value
+ // will be used.
+ int32 send_buffer_size = 0;
+ // Sets the OS receive buffer size (in bytes) for the socket. This is the
+ // SO_RCVBUF socket option. The kernel allocates this much to hold the data
+ // arriving into this socket between the time when data arrives over the
+ // network and when it is read by UDPSocketReceiver. If buffer is full,
+ // new packets will be discarded. Default value is 0, in which case, OS's
+ // default value will be used.
+ int32 receive_buffer_size = 0;
+};
+
+// UDPSocket is an interface that exposes UDP socket functionalities.
+// UDPSocketReceiver is an interface that allows consumers to consume data
+// received by the UDPSocket. The typical flow of using the interfaces is:
+// - Acquire a UDPSocket interface pointer and optionally supply a non-null
+// UDPSocketReceiverPtr. If consumers are not interested in received data, a
+// null UDPSocketReceiverPtr is acceptable.
+// - Use either Bind() or Connect() before datagrams can be sent or received.
+// - (optional) Invoke setters (e.g. SetBroadcast()).
+// - Send / request to receive datagrams. Received datagrams will be delivered
+// to the bound receiver's OnReceived() call.
+// - Close the socket by destroying the interface pointer.
+interface UDPSocket {
+ // Binds the address/port for this socket to |local_addr|. Caller can use port
+ // 0 to let the OS pick an available port. If |socket_options| is not null,
+ // configures the socket with the options before binding the socket.
+ // Returns net::OK and the real local address used on success and a negative
+ // net error code on failure.
+ Bind(net.interfaces.IPEndPoint local_addr, UDPSocketOptions? socket_options)
+ => (int32 result, net.interfaces.IPEndPoint? local_addr_out);
+
+ // Connects the socket to |remote_addr|. This automatically binds the socket
+ // to an available local port, so this cannot be used with Bind().
+ // If |socket_options| is not null, configures the socket with the options
+ // before connecting the socket.
+ // The address family of the local socket will be of the same
+ // net.interfaces.AddressFamily as |remote_addr|. Returns net::OK and the
+ // local address of socket on success. Subsequent packets received will be
+ // from |remote_addr|. Returns a negative net error code on failure.
+ Connect(net.interfaces.IPEndPoint remote_addr,
+ UDPSocketOptions? socket_options) =>
+ (int32 result, net.interfaces.IPEndPoint? local_addr_out);
+
+ // Allows or disallows sending and receiving packets to and from broadcast
+ // addresses. Returns a net error code. Should only be called after Bind().
+ SetBroadcast(bool broadcast) => (int32 result);
+
+ // Joins a multicast group. |group_address| is the group address to join,
+ // could be either an IPv4 or IPv6 address. Returns a net error code.
+ // See RFC 1112 for details on multicast.
+ JoinGroup(net.interfaces.IPAddress group_address) => (int32 result);
+
+ // Leaves the multicast group. |group_address| is the group address to leave,
+ // could be either an IPv4 or IPv6 address. If the socket hasn't joined the
+ // group, this call will be ignored. It's optional to leave the multicast
+ // group before destroying the socket. Returns a net error code.
+ LeaveGroup(net.interfaces.IPAddress group_address) => (int32 result);
+
+ // Notifies that the receiver is ready to accept |number| of datagrams.
+ // Correspondingly, OnReceived() of the UDPSocketReceiver interface will be
+ // called |number| times (errors also count), unless the connection is closed
+ // before that. The implementation may return net::ERR_INSUFFICIENT_RESOURCES
+ // in an OnReceived() callback if the service doesn't have enough resource to
+ // complete the operation. For example, if the implementation queues the
+ // requests internally, net::ERR_INSUFFICIENT_RESOURCES can be returned if the
+ // queue doesn't have any space to accept new ReceiveMore().
+ //
+ // It is allowed to call this method again before the previous request is
+ // completely satisfied. For example:
+ // service->ReceiveMore(3);
+ // ...
+ // // OnReceived() is called.
+ // // OnReceived() is called.
+ // ...
+ // service->ReceiveMore(3);
+ // // The client expects 4 more calls to OnReceived().
+ //
+ // Please note that how ReceiveMore() is used will affect performance
+ // significantly. For example:
+ // // Approach 1:
+ // service->ReceiveMore(3);
+ // // OnReceived() is called.
+ // // OnReceived() is called.
+ // // OnReceived() is called.
+ //
+ // // Approach 2:
+ // service->ReceiveMore(1);
+ // // OnReceived() is called.
+ // service->ReceiveMore(1);
+ // // OnReceived() is called.
+ // service->ReceiveMore(1);
+ // // OnReceived() is called.
+ //
+ // It is very likely that approach 1 will perform better than approach 2,
+ // because in approach 2 getting every datagram takes at least the time of a
+ // round trip to the service side. Default buffer size of 64KiB will be
+ // allocated to receive each datagram.
+ ReceiveMore(uint32 num_additional_datagrams);
+
+ // Same as ReceiveMore(), but with an ability to set the buffer size used for
+ // receiving each datagram. Note that |buffer_size| is the application-side
+ // buffer which is different from UDPSocketOptions::receive_buffer_size which
+ // is the OS-side buffer. |buffer_size| larger than 64KiB will be capped at
+ // 64KiB as the limit on data length of a IPv4 UDP packet is 65,507 and 65,535
+ // for IPv6.
+ ReceiveMoreWithBufferSize(
+ uint32 num_additional_datagrams, uint32 buffer_size);
+
+ // Sends data to a particular destination, |dest_addr|. Should only be used
+ // after Bind(). There is currently no limit on the size of |data|, other
+ // than the restrictions on datagram size specified in the IP layer (e.g.
+ // 65507 bytes for IPv4) . Consumers need to be aware that sending data in
+ // larger chunks will result in higher memory usage. Upon successfully handing
+ // the data to the OS, |result| is net::OK. On failure, it is a network error
+ // code, including (but not limited to):
+ // - net::ERR_INSUFFICIENT_RESOURCES: The service doesn't have
+ // sufficient resource to complete the operation. When this happens, the
+ // requests will be failed quickly (which might happen before the completion
+ // of requests that were sent earlier).
+ SendTo(net.interfaces.IPEndPoint dest_addr,
+ mojo.common.mojom.ReadOnlyBuffer data,
+ MutableNetworkTrafficAnnotationTag traffic_annotation)
+ => (int32 result);
+
+ // Same as SendTo(), except this method sends data to the destination
+ // specified in an earlier Connect(). This method should only be called after
+ // a successful Connect().
+ Send(mojo.common.mojom.ReadOnlyBuffer data,
+ MutableNetworkTrafficAnnotationTag traffic_annotation)
+ => (int32 result);
+
+ // Closes the socket. Connect() or Bind() can be used after Close().
+ Close();
+};
+
+// An interface the consumers of UDPSocket can implement to listen for incoming
+// packets. This interface is to be used together when requesting a UDPSocket.
+interface UDPSocketReceiver {
+ // Invoked when data is received.
+ // - When UDPSocket is used with Bind():
+ // On success, |result| is net::OK. |src_addr| indicates the address of the
+ // sender. |data| contains the received data.
+ // On failure, |result| is a negative network error code. |data| is null.
+ // |src_addr| might be null.
+ // - When UDPSocket is used with Connect():
+ // |src_addr| is always null. Data are always received from the remote
+ // address specified in Connect().
+ // On success, |result| is net::OK. |data| contains the received data.
+ // On failure, |result| is a negative network error code. |data| is null.
+ //
+ // Note that in both cases, |data| can be an empty buffer when |result| is
+ // net::OK, which indicates a zero-byte payload.
+ OnReceived(int32 result,
+ net.interfaces.IPEndPoint? src_addr,
+ mojo.common.mojom.ReadOnlyBuffer? data);
+};
diff --git a/chromium/services/network/public/interfaces/url_loader.mojom b/chromium/services/network/public/mojom/url_loader.mojom
index d953ba621bc..52b11649b06 100644
--- a/chromium/services/network/public/interfaces/url_loader.mojom
+++ b/chromium/services/network/public/mojom/url_loader.mojom
@@ -11,6 +11,9 @@ struct URLRequest;
struct URLResponseHead;
[Native]
+struct SSLCertRequestInfo;
+
+[Native]
struct SSLInfo;
[Native]
@@ -22,6 +25,9 @@ struct CORSErrorStatus;
[Native]
struct URLLoaderCompletionStatus;
+[Native]
+struct X509Certificate;
+
// This enum corresponds to net::RequestPriority. See its comments for details.
enum RequestPriority {
kThrottled = 0,
@@ -34,6 +40,11 @@ enum RequestPriority {
// Destroying a URLLoader will cancel the associated request.
interface URLLoader {
+ // If a disconnection is initiated by the client side, it may send the
+ // following disconnection reason, along with an application-defined string
+ // description, to notify the service side.
+ const uint32 kClientDisconnectReason = 1;
+
// If the associated request has |auto_follow_redirects| set to false,
// then upon receiving an URLResponse with a non-NULL |redirect_url| field,
// |FollowRedirect| may be called to load the URL indicated by the redirect.
@@ -53,12 +64,21 @@ interface URLLoader {
// intra priority value is maintained.
SetPriority(RequestPriority priority, int32 intra_priority_value);
- // If a URLLoader fetches the resource from network, it should handle these
- // methods to pause/resume reading the response body from network. Otherwise,
- // these methods could be no-ops.
+ // If the resource is being fetched from the network,
+ // PauseReadingBodyFromNet() pauses fetching the response body. It is okay to
+ // call this method before fetching the body starts, too.
+ // ResumeReadingBodyFromNet() resumes fetching the body if it has been paused.
+ //
+ // Note that PauseReadingBodyFromNet() is asynchronous and only gurantees to
+ // pause if the response body is fetched from the network. This means:
+ // - any data in flight before PauseReadingBodyFromNet() is processed will
+ // still be passed to the client data pipe.
+ // - a response body not from the network, e.g. from blob, may not be paused
+ // at all.
//
- // It is allowed to call Pause/ResumeReadingBodyFromNet before response body
- // is available.
+ // Redundant calls to these methods are ingored. It is not required to match
+ // pause and resume calls. It is not an error to resume a non-paused request,
+ // or pause a request multiple times.
PauseReadingBodyFromNet();
ResumeReadingBodyFromNet();
};
@@ -70,7 +90,6 @@ interface URLLoader {
interface DownloadedTempFile {
};
-
interface URLLoaderClient {
// Called when the response head is received.
// |downloaded_file| is non-null in the 'download_to_file' case.
diff --git a/chromium/services/network/public/interfaces/url_loader_factory.mojom b/chromium/services/network/public/mojom/url_loader_factory.mojom
index 6308b65c026..6308b65c026 100644
--- a/chromium/services/network/public/interfaces/url_loader_factory.mojom
+++ b/chromium/services/network/public/mojom/url_loader_factory.mojom
diff --git a/chromium/services/network/resource_scheduler.cc b/chromium/services/network/resource_scheduler.cc
new file mode 100644
index 00000000000..54f5305d953
--- /dev/null
+++ b/chromium/services/network/resource_scheduler.cc
@@ -0,0 +1,1311 @@
+// 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 "services/network/resource_scheduler.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/optional.h"
+#include "base/sequenced_task_runner.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/supports_user_data.h"
+#include "base/trace_event/trace_event.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/load_flags.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_server_properties.h"
+#include "net/nqe/network_quality_estimator.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "services/network/public/cpp/features.h"
+#include "url/scheme_host_port.h"
+
+namespace network {
+
+namespace {
+
+// When kPrioritySupportedRequestsDelayable is enabled, requests for
+// H2/QUIC/SPDY resources can be delayed by the ResourceScheduler just as
+// HTTP/1.1 resources are. It has good impact on performance, but breaks
+// expected behavior of H2. See intent-to-unship:
+// https://groups.google.com/a/chromium.org/forum/#!topic/blink-
+// dev/ChqGX8UyHz8. We're keeping it around for finch trials to compare
+// alternatives to.
+const base::Feature kPrioritySupportedRequestsDelayable{
+ "PrioritySupportedRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// When enabled, low-priority H2 and QUIC requests are throttled, but only
+// when the parser is in head.
+const base::Feature kHeadPrioritySupportedRequestsDelayable{
+ "HeadPriorityRequestsDelayable", base::FEATURE_DISABLED_BY_DEFAULT};
+
+// In the event that many resource requests are started quickly, this feature
+// will periodically yield (e.g., delaying starting of requests) by posting a
+// task and waiting for the task to run to resume. This allows other
+// operations that rely on the IO thread (e.g., already running network
+// requests) to make progress.
+const base::Feature kNetworkSchedulerYielding{
+ "NetworkSchedulerYielding", base::FEATURE_DISABLED_BY_DEFAULT};
+const char kMaxRequestsBeforeYieldingParam[] = "MaxRequestsBeforeYieldingParam";
+const int kMaxRequestsBeforeYieldingDefault = 5;
+const char kYieldMsParam[] = "MaxYieldMs";
+const int kYieldMsDefault = 0;
+
+// Based on the field trial parameters, this feature will override the value of
+// the maximum number of delayable requests allowed in flight. The number of
+// delayable requests allowed in flight will be based on the network's
+// effective connection type ranges and the
+// corresponding number of delayable requests in flight specified in the
+// experiment configuration. Based on field trial parameters, this experiment
+// may also throttle delayable requests based on the number of non-delayable
+// requests in-flight times a weighting factor.
+const base::Feature kThrottleDelayable{"ThrottleDelayable",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+enum StartMode { START_SYNC, START_ASYNC };
+
+// Flags identifying various attributes of the request that are used
+// when making scheduling decisions.
+using RequestAttributes = uint8_t;
+const RequestAttributes kAttributeNone = 0x00;
+const RequestAttributes kAttributeInFlight = 0x01;
+const RequestAttributes kAttributeDelayable = 0x02;
+const RequestAttributes kAttributeLayoutBlocking = 0x04;
+
+// Reasons why pending requests may be started. For logging only.
+enum class RequestStartTrigger {
+ NONE,
+ COMPLETION_PRE_BODY,
+ COMPLETION_POST_BODY,
+ BODY_REACHED,
+ CLIENT_KILL,
+ SPDY_PROXY_DETECTED,
+ REQUEST_REPRIORITIZED,
+ START_WAS_YIELDED,
+};
+
+const char* RequestStartTriggerString(RequestStartTrigger trigger) {
+ switch (trigger) {
+ case RequestStartTrigger::NONE:
+ return "NONE";
+ case RequestStartTrigger::COMPLETION_PRE_BODY:
+ return "COMPLETION_PRE_BODY";
+ case RequestStartTrigger::COMPLETION_POST_BODY:
+ return "COMPLETION_POST_BODY";
+ case RequestStartTrigger::BODY_REACHED:
+ return "BODY_REACHED";
+ case RequestStartTrigger::CLIENT_KILL:
+ return "CLIENT_KILL";
+ case RequestStartTrigger::SPDY_PROXY_DETECTED:
+ return "SPDY_PROXY_DETECTED";
+ case RequestStartTrigger::REQUEST_REPRIORITIZED:
+ return "REQUEST_REPRIORITIZED";
+ case RequestStartTrigger::START_WAS_YIELDED:
+ return "START_WAS_YIELDED";
+ }
+ NOTREACHED();
+ return "Unknown";
+}
+
+} // namespace
+
+// The maximum number of delayable requests to allow to be in-flight at any
+// point in time (across all hosts).
+static const size_t kDefaultMaxNumDelayableRequestsPerClient = 10;
+
+// The maximum number of requests to allow be in-flight at any point in time per
+// host.
+static const size_t kMaxNumDelayableRequestsPerHostPerClient = 6;
+
+// The maximum number of delayable requests to allow to be in-flight at any
+// point in time while in the layout-blocking phase of loading.
+static const size_t kMaxNumDelayableWhileLayoutBlockingPerClient = 1;
+
+// The priority level above which resources are considered layout-blocking if
+// the html_body has not started.
+static const net::RequestPriority kLayoutBlockingPriorityThreshold =
+ net::MEDIUM;
+
+// The priority level below which resources are considered to be delayable.
+static const net::RequestPriority kDelayablePriorityThreshold = net::MEDIUM;
+
+// The number of in-flight layout-blocking requests above which all delayable
+// requests should be blocked.
+static const size_t kInFlightNonDelayableRequestCountPerClientThreshold = 1;
+
+struct ResourceScheduler::RequestPriorityParams {
+ RequestPriorityParams()
+ : priority(net::DEFAULT_PRIORITY), intra_priority(0) {}
+
+ RequestPriorityParams(net::RequestPriority priority, int intra_priority)
+ : priority(priority), intra_priority(intra_priority) {}
+
+ bool operator==(const RequestPriorityParams& other) const {
+ return (priority == other.priority) &&
+ (intra_priority == other.intra_priority);
+ }
+
+ bool operator!=(const RequestPriorityParams& other) const {
+ return !(*this == other);
+ }
+
+ bool GreaterThan(const RequestPriorityParams& other) const {
+ if (priority != other.priority)
+ return priority > other.priority;
+ return intra_priority > other.intra_priority;
+ }
+
+ net::RequestPriority priority;
+ int intra_priority;
+};
+
+class ResourceScheduler::RequestQueue {
+ public:
+ typedef std::multiset<ScheduledResourceRequestImpl*, ScheduledResourceSorter>
+ NetQueue;
+
+ RequestQueue() : fifo_ordering_ids_(0) {}
+ ~RequestQueue() {}
+
+ // Adds |request| to the queue with given |priority|.
+ void Insert(ScheduledResourceRequestImpl* request);
+
+ // Removes |request| from the queue.
+ void Erase(ScheduledResourceRequestImpl* request) {
+ PointerMap::iterator it = pointers_.find(request);
+ CHECK(it != pointers_.end());
+ queue_.erase(it->second);
+ pointers_.erase(it);
+ }
+
+ NetQueue::iterator GetNextHighestIterator() { return queue_.begin(); }
+
+ NetQueue::iterator End() { return queue_.end(); }
+
+ // Returns true if |request| is queued.
+ bool IsQueued(ScheduledResourceRequestImpl* request) const {
+ return base::ContainsKey(pointers_, request);
+ }
+
+ // Returns true if no requests are queued.
+ bool IsEmpty() const { return queue_.size() == 0; }
+
+ private:
+ typedef std::map<ScheduledResourceRequestImpl*, NetQueue::iterator>
+ PointerMap;
+
+ uint32_t MakeFifoOrderingId() {
+ fifo_ordering_ids_ += 1;
+ return fifo_ordering_ids_;
+ }
+
+ // Used to create an ordering ID for scheduled resources so that resources
+ // with same priority/intra_priority stay in fifo order.
+ uint32_t fifo_ordering_ids_;
+
+ NetQueue queue_;
+ PointerMap pointers_;
+};
+
+ResourceScheduler::ScheduledResourceRequest::ScheduledResourceRequest() {}
+ResourceScheduler::ScheduledResourceRequest::~ScheduledResourceRequest() {}
+
+void ResourceScheduler::ScheduledResourceRequest::RunResumeCallback() {
+ std::move(resume_callback_).Run();
+}
+
+// This is the handle we return to the ResourceDispatcherHostImpl so it can
+// interact with the request.
+class ResourceScheduler::ScheduledResourceRequestImpl
+ : public ScheduledResourceRequest {
+ public:
+ ScheduledResourceRequestImpl(const ClientId& client_id,
+ net::URLRequest* request,
+ ResourceScheduler* scheduler,
+ const RequestPriorityParams& priority,
+ bool is_async)
+ : client_id_(client_id),
+ request_(request),
+ ready_(false),
+ deferred_(false),
+ is_async_(is_async),
+ attributes_(kAttributeNone),
+ scheduler_(scheduler),
+ priority_(priority),
+ fifo_ordering_(0),
+ peak_delayable_requests_in_flight_(0u),
+ host_port_pair_(net::HostPortPair::FromURL(request->url())),
+ weak_ptr_factory_(this) {
+ DCHECK(!request_->GetUserData(kUserDataKey));
+ request_->SetUserData(kUserDataKey, std::make_unique<UnownedPointer>(this));
+ }
+
+ ~ScheduledResourceRequestImpl() override {
+ if ((attributes_ & kAttributeLayoutBlocking) == kAttributeLayoutBlocking) {
+ UMA_HISTOGRAM_COUNTS_100(
+ "ResourceScheduler.PeakDelayableRequestsInFlight.LayoutBlocking",
+ peak_delayable_requests_in_flight_);
+ }
+ if (!((attributes_ & kAttributeDelayable) == kAttributeDelayable)) {
+ UMA_HISTOGRAM_COUNTS_100(
+ "ResourceScheduler.PeakDelayableRequestsInFlight.NonDelayable",
+ peak_delayable_requests_in_flight_);
+ }
+ request_->RemoveUserData(kUserDataKey);
+ scheduler_->RemoveRequest(this);
+ }
+
+ static ScheduledResourceRequestImpl* ForRequest(net::URLRequest* request) {
+ UnownedPointer* pointer =
+ static_cast<UnownedPointer*>(request->GetUserData(kUserDataKey));
+ return pointer ? pointer->get() : nullptr;
+ }
+
+ // Starts the request. If |start_mode| is START_ASYNC, the request will not
+ // be started immediately.
+ void Start(StartMode start_mode) {
+ DCHECK(!ready_);
+
+ // If the request was cancelled, do nothing.
+ if (!request_->status().is_success())
+ return;
+
+ // If the request was deferred, need to start it. Otherwise, will just not
+ // defer starting it in the first place, and the value of |start_mode|
+ // makes no difference.
+ if (deferred_) {
+ // If can't start the request synchronously, post a task to start the
+ // request.
+ if (start_mode == START_ASYNC) {
+ scheduler_->task_runner()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&ScheduledResourceRequestImpl::Start,
+ weak_ptr_factory_.GetWeakPtr(), START_SYNC));
+ return;
+ }
+ deferred_ = false;
+ RunResumeCallback();
+ }
+
+ ready_ = true;
+ }
+
+ void UpdateDelayableRequestsInFlight(size_t delayable_requests_in_flight) {
+ peak_delayable_requests_in_flight_ = std::max(
+ peak_delayable_requests_in_flight_, delayable_requests_in_flight);
+ }
+
+ void set_request_priority_params(const RequestPriorityParams& priority) {
+ priority_ = priority;
+ }
+ const RequestPriorityParams& get_request_priority_params() const {
+ return priority_;
+ }
+ const ClientId& client_id() const { return client_id_; }
+ net::URLRequest* url_request() { return request_; }
+ const net::URLRequest* url_request() const { return request_; }
+ bool is_async() const { return is_async_; }
+ uint32_t fifo_ordering() const { return fifo_ordering_; }
+ void set_fifo_ordering(uint32_t fifo_ordering) {
+ fifo_ordering_ = fifo_ordering;
+ }
+ RequestAttributes attributes() const { return attributes_; }
+ void set_attributes(RequestAttributes attributes) {
+ attributes_ = attributes;
+ }
+ const net::HostPortPair& host_port_pair() const { return host_port_pair_; }
+
+ private:
+ class UnownedPointer : public base::SupportsUserData::Data {
+ public:
+ explicit UnownedPointer(ScheduledResourceRequestImpl* pointer)
+ : pointer_(pointer) {}
+
+ ScheduledResourceRequestImpl* get() const { return pointer_; }
+
+ private:
+ ScheduledResourceRequestImpl* const pointer_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnownedPointer);
+ };
+
+ static const void* const kUserDataKey;
+
+ // ScheduledResourceRequest implemnetation
+ void WillStartRequest(bool* defer) override { deferred_ = *defer = !ready_; }
+
+ const ClientId client_id_;
+ net::URLRequest* request_;
+ bool ready_;
+ bool deferred_;
+ bool is_async_;
+ RequestAttributes attributes_;
+ ResourceScheduler* scheduler_;
+ RequestPriorityParams priority_;
+ uint32_t fifo_ordering_;
+
+ // Maximum number of delayable requests in-flight when |this| was in-flight.
+ size_t peak_delayable_requests_in_flight_;
+ // Cached to excessive recomputation in ShouldKeepSearching.
+ const net::HostPortPair host_port_pair_;
+
+ base::WeakPtrFactory<ResourceScheduler::ScheduledResourceRequestImpl>
+ weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScheduledResourceRequestImpl);
+};
+
+const void* const
+ ResourceScheduler::ScheduledResourceRequestImpl::kUserDataKey =
+ &ResourceScheduler::ScheduledResourceRequestImpl::kUserDataKey;
+
+bool ResourceScheduler::ScheduledResourceSorter::operator()(
+ const ScheduledResourceRequestImpl* a,
+ const ScheduledResourceRequestImpl* b) const {
+ // Want the set to be ordered first by decreasing priority, then by
+ // decreasing intra_priority.
+ // ie. with (priority, intra_priority)
+ // [(1, 0), (1, 0), (0, 100), (0, 0)]
+ if (a->get_request_priority_params() != b->get_request_priority_params())
+ return a->get_request_priority_params().GreaterThan(
+ b->get_request_priority_params());
+
+ // If priority/intra_priority is the same, fall back to fifo ordering.
+ // std::multiset doesn't guarantee this until c++11.
+ return a->fifo_ordering() < b->fifo_ordering();
+}
+
+void ResourceScheduler::RequestQueue::Insert(
+ ScheduledResourceRequestImpl* request) {
+ DCHECK(!base::ContainsKey(pointers_, request));
+ request->set_fifo_ordering(MakeFifoOrderingId());
+ pointers_[request] = queue_.insert(request);
+}
+
+// Each client represents a tab.
+class ResourceScheduler::Client {
+ public:
+ Client(const net::NetworkQualityEstimator* const network_quality_estimator,
+ ResourceScheduler* resource_scheduler)
+ : deprecated_is_loaded_(false),
+ deprecated_has_html_body_(false),
+ using_spdy_proxy_(false),
+ in_flight_delayable_count_(0),
+ total_layout_blocking_count_(0),
+ num_skipped_scans_due_to_scheduled_start_(0),
+ started_requests_since_yielding_(0),
+ did_scheduler_yield_(false),
+ network_quality_estimator_(network_quality_estimator),
+ max_delayable_requests_(
+ resource_scheduler->throttle_delayable_
+ .GetParamsForNetworkQuality(network_quality_estimator)
+ .max_delayable_requests),
+ resource_scheduler_(resource_scheduler),
+ weak_ptr_factory_(this) {
+ if (IsRendererSideResourceSchedulerEnabled()) {
+ // In this case, "layout blocking" concept is moved to the renderer side,
+ // so the shceduler works always with the normal mode.
+ deprecated_has_html_body_ = true;
+ }
+ }
+
+ ~Client() {}
+
+ void ScheduleRequest(const net::URLRequest& url_request,
+ ScheduledResourceRequestImpl* request) {
+ SetRequestAttributes(request, DetermineRequestAttributes(request));
+ ShouldStartReqResult should_start = ShouldStartRequest(request);
+ if (should_start == START_REQUEST) {
+ // New requests can be started synchronously without issue.
+ StartRequest(request, START_SYNC, RequestStartTrigger::NONE);
+ } else {
+ pending_requests_.Insert(request);
+ if (should_start == YIELD_SCHEDULER)
+ did_scheduler_yield_ = true;
+ }
+ }
+
+ void RemoveRequest(ScheduledResourceRequestImpl* request) {
+ if (pending_requests_.IsQueued(request)) {
+ pending_requests_.Erase(request);
+ DCHECK(!base::ContainsKey(in_flight_requests_, request));
+ } else {
+ EraseInFlightRequest(request);
+
+ // Removing this request may have freed up another to load.
+ LoadAnyStartablePendingRequests(
+ deprecated_has_html_body_ ? RequestStartTrigger::COMPLETION_POST_BODY
+ : RequestStartTrigger::COMPLETION_PRE_BODY);
+ }
+ }
+
+ RequestSet StartAndRemoveAllRequests() {
+ // First start any pending requests so that they will be moved into
+ // in_flight_requests_. This may exceed the limits
+ // kDefaultMaxNumDelayableRequestsPerClient and
+ // kMaxNumDelayableRequestsPerHostPerClient, so this method must not do
+ // anything that depends on those limits before calling
+ // ClearInFlightRequests() below.
+ while (!pending_requests_.IsEmpty()) {
+ ScheduledResourceRequestImpl* request =
+ *pending_requests_.GetNextHighestIterator();
+ pending_requests_.Erase(request);
+ // Starting requests asynchronously ensures no side effects, and avoids
+ // starting a bunch of requests that may be about to be deleted.
+ StartRequest(request, START_ASYNC, RequestStartTrigger::CLIENT_KILL);
+ }
+ RequestSet unowned_requests;
+ for (RequestSet::iterator it = in_flight_requests_.begin();
+ it != in_flight_requests_.end(); ++it) {
+ unowned_requests.insert(*it);
+ (*it)->set_attributes(kAttributeNone);
+ }
+ ClearInFlightRequests();
+ return unowned_requests;
+ }
+
+ bool deprecated_is_loaded() const { return deprecated_is_loaded_; }
+
+ void DeprecatedOnLoadingStateChanged(bool is_loaded) {
+ deprecated_is_loaded_ = is_loaded;
+ }
+
+ void DeprecatedOnNavigate() {
+ deprecated_has_html_body_ = false;
+ if (IsRendererSideResourceSchedulerEnabled()) {
+ // In this case, "layout blocking" concept is moved to the renderer side,
+ // so the shceduler works always with the normal mode.
+ deprecated_has_html_body_ = true;
+ }
+
+ deprecated_is_loaded_ = false;
+ max_delayable_requests_ =
+ resource_scheduler_->throttle_delayable_
+ .GetParamsForNetworkQuality(network_quality_estimator_)
+ .max_delayable_requests;
+ }
+
+ void DeprecatedOnWillInsertBody() {
+ // Can be called multiple times per RVH in the case of out-of-process
+ // iframes.
+ if (deprecated_has_html_body_)
+ return;
+ deprecated_has_html_body_ = true;
+ LoadAnyStartablePendingRequests(RequestStartTrigger::BODY_REACHED);
+ }
+
+ void OnReceivedSpdyProxiedHttpResponse() {
+ if (!using_spdy_proxy_) {
+ using_spdy_proxy_ = true;
+ LoadAnyStartablePendingRequests(RequestStartTrigger::SPDY_PROXY_DETECTED);
+ }
+ }
+
+ void ReprioritizeRequest(ScheduledResourceRequestImpl* request,
+ RequestPriorityParams old_priority_params,
+ RequestPriorityParams new_priority_params) {
+ request->url_request()->SetPriority(new_priority_params.priority);
+ request->set_request_priority_params(new_priority_params);
+ SetRequestAttributes(request, DetermineRequestAttributes(request));
+ if (!pending_requests_.IsQueued(request)) {
+ DCHECK(base::ContainsKey(in_flight_requests_, request));
+ // Request has already started.
+ return;
+ }
+
+ pending_requests_.Erase(request);
+ pending_requests_.Insert(request);
+
+ if (new_priority_params.priority > old_priority_params.priority) {
+ // Check if this request is now able to load at its new priority.
+ ScheduleLoadAnyStartablePendingRequests(
+ RequestStartTrigger::REQUEST_REPRIORITIZED);
+ }
+ }
+
+ private:
+ enum ShouldStartReqResult {
+ DO_NOT_START_REQUEST_AND_STOP_SEARCHING,
+ DO_NOT_START_REQUEST_AND_KEEP_SEARCHING,
+ START_REQUEST,
+ YIELD_SCHEDULER
+ };
+
+ // Records the metrics related to number of requests in flight.
+ void RecordRequestCountMetrics() const {
+ UMA_HISTOGRAM_COUNTS_100("ResourceScheduler.RequestsCount.All",
+ in_flight_requests_.size());
+ UMA_HISTOGRAM_COUNTS_100("ResourceScheduler.RequestsCount.Delayable",
+ in_flight_delayable_count_);
+ UMA_HISTOGRAM_COUNTS_100(
+ "ResourceScheduler.RequestsCount.NonDelayable",
+ in_flight_requests_.size() - in_flight_delayable_count_);
+ UMA_HISTOGRAM_COUNTS_100(
+ "ResourceScheduler.RequestsCount.TotalLayoutBlocking",
+ total_layout_blocking_count_);
+ }
+
+ void InsertInFlightRequest(ScheduledResourceRequestImpl* request) {
+ in_flight_requests_.insert(request);
+ SetRequestAttributes(request, DetermineRequestAttributes(request));
+ RecordRequestCountMetrics();
+
+ if (RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) {
+ // Notify all in-flight with the new count of in-flight delayable
+ // requests.
+ for (RequestSet::const_iterator it = in_flight_requests_.begin();
+ it != in_flight_requests_.end(); ++it) {
+ (*it)->UpdateDelayableRequestsInFlight(in_flight_delayable_count_);
+ }
+ }
+
+ if (RequestAttributesAreSet(request->attributes(),
+ kAttributeLayoutBlocking) ||
+ !RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) {
+ // |request| is either a layout blocking or a non-delayable request.
+ request->UpdateDelayableRequestsInFlight(in_flight_delayable_count_);
+ }
+ }
+
+ void EraseInFlightRequest(ScheduledResourceRequestImpl* request) {
+ size_t erased = in_flight_requests_.erase(request);
+ DCHECK_EQ(1u, erased);
+ // Clear any special state that we were tracking for this request.
+ SetRequestAttributes(request, kAttributeNone);
+ }
+
+ void ClearInFlightRequests() {
+ in_flight_requests_.clear();
+ in_flight_delayable_count_ = 0;
+ total_layout_blocking_count_ = 0;
+ }
+
+ size_t CountRequestsWithAttributes(
+ const RequestAttributes attributes,
+ ScheduledResourceRequestImpl* current_request) {
+ size_t matching_request_count = 0;
+ for (RequestSet::const_iterator it = in_flight_requests_.begin();
+ it != in_flight_requests_.end(); ++it) {
+ if (RequestAttributesAreSet((*it)->attributes(), attributes))
+ matching_request_count++;
+ }
+ if (!RequestAttributesAreSet(attributes, kAttributeInFlight)) {
+ bool current_request_is_pending = false;
+ for (RequestQueue::NetQueue::const_iterator it =
+ pending_requests_.GetNextHighestIterator();
+ it != pending_requests_.End(); ++it) {
+ if (RequestAttributesAreSet((*it)->attributes(), attributes))
+ matching_request_count++;
+ if (*it == current_request)
+ current_request_is_pending = true;
+ }
+ // Account for the current request if it is not in one of the lists yet.
+ if (current_request &&
+ !base::ContainsKey(in_flight_requests_, current_request) &&
+ !current_request_is_pending) {
+ if (RequestAttributesAreSet(current_request->attributes(), attributes))
+ matching_request_count++;
+ }
+ }
+ return matching_request_count;
+ }
+
+ bool RequestAttributesAreSet(RequestAttributes request_attributes,
+ RequestAttributes matching_attributes) const {
+ return (request_attributes & matching_attributes) == matching_attributes;
+ }
+
+ void SetRequestAttributes(ScheduledResourceRequestImpl* request,
+ RequestAttributes attributes) {
+ RequestAttributes old_attributes = request->attributes();
+ if (old_attributes == attributes)
+ return;
+
+ if (RequestAttributesAreSet(old_attributes,
+ kAttributeInFlight | kAttributeDelayable)) {
+ in_flight_delayable_count_--;
+ }
+ if (RequestAttributesAreSet(old_attributes, kAttributeLayoutBlocking))
+ total_layout_blocking_count_--;
+
+ if (RequestAttributesAreSet(attributes,
+ kAttributeInFlight | kAttributeDelayable)) {
+ in_flight_delayable_count_++;
+ }
+ if (RequestAttributesAreSet(attributes, kAttributeLayoutBlocking))
+ total_layout_blocking_count_++;
+
+ request->set_attributes(attributes);
+ DCHECK_EQ(CountRequestsWithAttributes(
+ kAttributeInFlight | kAttributeDelayable, request),
+ in_flight_delayable_count_);
+ DCHECK_EQ(CountRequestsWithAttributes(kAttributeLayoutBlocking, request),
+ total_layout_blocking_count_);
+ }
+
+ RequestAttributes DetermineRequestAttributes(
+ ScheduledResourceRequestImpl* request) {
+ RequestAttributes attributes = kAttributeNone;
+
+ if (base::ContainsKey(in_flight_requests_, request))
+ attributes |= kAttributeInFlight;
+
+ if (RequestAttributesAreSet(request->attributes(),
+ kAttributeLayoutBlocking)) {
+ // If a request is already marked as layout-blocking make sure to keep the
+ // attribute across redirects.
+ attributes |= kAttributeLayoutBlocking;
+ } else if (!deprecated_has_html_body_ &&
+ request->url_request()->priority() >
+ kLayoutBlockingPriorityThreshold) {
+ // Requests that are above the non_delayable threshold before the HTML
+ // body has been parsed are inferred to be layout-blocking.
+ attributes |= kAttributeLayoutBlocking;
+ } else if (request->url_request()->priority() <
+ kDelayablePriorityThreshold) {
+ if (resource_scheduler_->priority_requests_delayable() ||
+ (resource_scheduler_->head_priority_requests_delayable() &&
+ !deprecated_has_html_body_)) {
+ // Resources below the delayable priority threshold that are considered
+ // delayable.
+ attributes |= kAttributeDelayable;
+ } else {
+ // Resources below the delayable priority threshold that are being
+ // requested from a server that does not support native prioritization
+ // are considered delayable.
+ url::SchemeHostPort scheme_host_port(request->url_request()->url());
+ net::HttpServerProperties& http_server_properties =
+ *request->url_request()->context()->http_server_properties();
+ if (!http_server_properties.SupportsRequestPriority(scheme_host_port))
+ attributes |= kAttributeDelayable;
+ }
+ }
+
+ return attributes;
+ }
+
+ bool ShouldKeepSearching(const net::HostPortPair& active_request_host) const {
+ size_t same_host_count = 0;
+ for (RequestSet::const_iterator it = in_flight_requests_.begin();
+ it != in_flight_requests_.end(); ++it) {
+ if (active_request_host.Equals((*it)->host_port_pair())) {
+ same_host_count++;
+ if (same_host_count >= kMaxNumDelayableRequestsPerHostPerClient)
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void StartRequest(ScheduledResourceRequestImpl* request,
+ StartMode start_mode,
+ RequestStartTrigger trigger) {
+ if (resource_scheduler_->yielding_scheduler_enabled()) {
+ started_requests_since_yielding_ += 1;
+ if (started_requests_since_yielding_ == 1) {
+ // This is the first started request since last yielding. Post a task to
+ // reset the counter and start any yielded tasks if necessary. We post
+ // this now instead of when we first yield so that if there is a pause
+ // between requests the counter is reset.
+ resource_scheduler_->task_runner()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&Client::ResumeIfYielded,
+ weak_ptr_factory_.GetWeakPtr()),
+ resource_scheduler_->yield_time());
+ }
+ }
+
+ // Only log on requests that were blocked by the ResourceScheduler.
+ if (start_mode == START_ASYNC) {
+ DCHECK_NE(RequestStartTrigger::NONE, trigger);
+ request->url_request()->net_log().AddEvent(
+ net::NetLogEventType::RESOURCE_SCHEDULER_REQUEST_STARTED,
+ net::NetLog::StringCallback("trigger",
+ RequestStartTriggerString(trigger)));
+ }
+ // Record the number of delayable requests in-flight when a non-delayable
+ // request starts.
+ if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable)) {
+ UMA_HISTOGRAM_COUNTS_100(
+ "ResourceScheduler.NumDelayableRequestsInFlightAtStart.NonDelayable",
+ in_flight_delayable_count_);
+ }
+ InsertInFlightRequest(request);
+ request->Start(start_mode);
+ }
+
+ // ShouldStartRequest is the main scheduling algorithm.
+ //
+ // Requests are evaluated on five attributes:
+ //
+ // 1. Non-delayable requests:
+ // * Synchronous requests.
+ // * Non-HTTP[S] requests.
+ //
+ // 2. Requests to request-priority-capable origin servers.
+ //
+ // 3. High-priority requests:
+ // * Higher priority requests (>= net::LOW).
+ //
+ // 4. Layout-blocking requests:
+ // * High-priority requests (> net::LOW) initiated before the renderer has
+ // a <body>.
+ //
+ // 5. Low priority requests
+ //
+ // The following rules are followed:
+ //
+ // All types of requests:
+ // * Non-delayable, High-priority and request-priority capable requests are
+ // issued immediately.
+ // * Low priority requests are delayable.
+ // * While kInFlightNonDelayableRequestCountPerClientThreshold
+ // layout-blocking requests are loading or the body tag has not yet been
+ // parsed, limit the number of delayable requests that may be in flight
+ // to kMaxNumDelayableWhileLayoutBlockingPerClient.
+ // * If no high priority or layout-blocking requests are in flight, start
+ // loading delayable requests.
+ // * Never exceed 10 delayable requests in flight per client.
+ // * Never exceed 6 delayable requests for a given host.
+
+ ShouldStartReqResult ShouldStartRequest(
+ ScheduledResourceRequestImpl* request) const {
+ if (!resource_scheduler_->enabled())
+ return START_REQUEST;
+
+ const net::URLRequest& url_request = *request->url_request();
+ // Syncronous requests could block the entire render, which could impact
+ // user-observable Clients.
+ if (!request->is_async())
+ return START_REQUEST;
+
+ // TODO(simonjam): This may end up causing disk contention. We should
+ // experiment with throttling if that happens.
+ if (!url_request.url().SchemeIsHTTPOrHTTPS())
+ return START_REQUEST;
+
+ const net::HostPortPair& host_port_pair = request->host_port_pair();
+
+ bool priority_delayable =
+ resource_scheduler_->priority_requests_delayable() ||
+ (resource_scheduler_->head_priority_requests_delayable() &&
+ !deprecated_has_html_body_);
+
+ if (!priority_delayable) {
+ if (using_spdy_proxy_ && url_request.url().SchemeIs(url::kHttpScheme))
+ return ShouldStartOrYieldRequest(request);
+
+ url::SchemeHostPort scheme_host_port(url_request.url());
+
+ net::HttpServerProperties& http_server_properties =
+ *url_request.context()->http_server_properties();
+ // TODO(willchan): We should really improve this algorithm as described in
+ // https://crbug.com/164101. Also, theoretically we should not count a
+ // request-priority capable request against the delayable requests limit.
+ if (http_server_properties.SupportsRequestPriority(scheme_host_port))
+ return ShouldStartOrYieldRequest(request);
+ }
+
+ // Non-delayable requests.
+ if (!RequestAttributesAreSet(request->attributes(), kAttributeDelayable))
+ return START_REQUEST;
+
+ // Delayable requests.
+ DCHECK_GE(in_flight_requests_.size(), in_flight_delayable_count_);
+ size_t num_non_delayable_requests_weighted = static_cast<size_t>(
+ resource_scheduler_->throttle_delayable_
+ .GetParamsForNetworkQuality(network_quality_estimator_)
+ .non_delayable_weight *
+ (in_flight_requests_.size() - in_flight_delayable_count_));
+ if ((in_flight_delayable_count_ + num_non_delayable_requests_weighted >=
+ max_delayable_requests_)) {
+ return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
+ }
+
+ if (ShouldKeepSearching(host_port_pair)) {
+ // There may be other requests for other hosts that may be allowed,
+ // so keep checking.
+ return DO_NOT_START_REQUEST_AND_KEEP_SEARCHING;
+ }
+
+ // The in-flight requests consist of layout-blocking requests,
+ // normal requests and delayable requests. Everything except for
+ // delayable requests is handled above here so this is deciding what to
+ // do with a delayable request while we are in the layout-blocking phase
+ // of loading.
+ if (!deprecated_has_html_body_ || total_layout_blocking_count_ != 0) {
+ size_t non_delayable_requests_in_flight_count =
+ in_flight_requests_.size() - in_flight_delayable_count_;
+ if (non_delayable_requests_in_flight_count >
+ kInFlightNonDelayableRequestCountPerClientThreshold) {
+ // Too many higher priority in-flight requests to allow lower priority
+ // requests through.
+ return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
+ }
+ if (in_flight_requests_.size() > 0 &&
+ (in_flight_delayable_count_ >=
+ kMaxNumDelayableWhileLayoutBlockingPerClient)) {
+ // Block the request if at least one request is in flight and the
+ // number of in-flight delayable requests has hit the configured
+ // limit.
+ return DO_NOT_START_REQUEST_AND_STOP_SEARCHING;
+ }
+ }
+
+ return START_REQUEST;
+ }
+
+ // It is common for a burst of messages to come from the renderer which
+ // trigger starting pending requests. Naively, this would result in O(n*m)
+ // behavior for n pending requests and m <= n messages, as
+ // LoadAnyStartablePendingRequest is O(n) for n pending requests. To solve
+ // this, just post a task to the end of the queue to call the method,
+ // coalescing the m messages into a single call to
+ // LoadAnyStartablePendingRequests.
+ // TODO(csharrison): Reconsider this if IPC batching becomes an easy to use
+ // pattern.
+ void ScheduleLoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
+ if (num_skipped_scans_due_to_scheduled_start_ == 0) {
+ TRACE_EVENT0("loading", "ScheduleLoadAnyStartablePendingRequests");
+ resource_scheduler_->task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&Client::LoadAnyStartablePendingRequests,
+ weak_ptr_factory_.GetWeakPtr(), trigger));
+ }
+ num_skipped_scans_due_to_scheduled_start_ += 1;
+ }
+
+ void ResumeIfYielded() {
+ bool yielded = did_scheduler_yield_;
+ started_requests_since_yielding_ = 0;
+ did_scheduler_yield_ = false;
+
+ if (yielded)
+ LoadAnyStartablePendingRequests(RequestStartTrigger::START_WAS_YIELDED);
+ }
+
+ // For a request that is ready to start, return START_REQUEST if the
+ // scheduler doesn't need to yield, else YIELD_SCHEDULER.
+ ShouldStartReqResult ShouldStartOrYieldRequest(
+ ScheduledResourceRequestImpl* request) const {
+ DCHECK_GE(started_requests_since_yielding_, 0);
+
+ // Don't yield if:
+ // 1. The yielding scheduler isn't enabled
+ // 2. The resource is high priority
+ // 3. There haven't been enough recent requests to warrant yielding.
+ if (!resource_scheduler_->yielding_scheduler_enabled() ||
+ request->url_request()->priority() >= kDelayablePriorityThreshold ||
+ started_requests_since_yielding_ <
+ resource_scheduler_->max_requests_before_yielding()) {
+ return START_REQUEST;
+ }
+ return YIELD_SCHEDULER;
+ }
+
+ void LoadAnyStartablePendingRequests(RequestStartTrigger trigger) {
+ // We iterate through all the pending requests, starting with the highest
+ // priority one. For each entry, one of three things can happen:
+ // 1) We start the request, remove it from the list, and keep checking.
+ // 2) We do NOT start the request, but ShouldStartRequest() signals us that
+ // there may be room for other requests, so we keep checking and leave
+ // the previous request still in the list.
+ // 3) We do not start the request, same as above, but StartRequest() tells
+ // us there's no point in checking any further requests.
+ TRACE_EVENT0("loading", "LoadAnyStartablePendingRequests");
+ if (num_skipped_scans_due_to_scheduled_start_ > 0) {
+ UMA_HISTOGRAM_COUNTS_1M("ResourceScheduler.NumSkippedScans.ScheduleStart",
+ num_skipped_scans_due_to_scheduled_start_);
+ }
+ num_skipped_scans_due_to_scheduled_start_ = 0;
+ RequestQueue::NetQueue::iterator request_iter =
+ pending_requests_.GetNextHighestIterator();
+
+ while (request_iter != pending_requests_.End()) {
+ ScheduledResourceRequestImpl* request = *request_iter;
+ ShouldStartReqResult query_result = ShouldStartRequest(request);
+
+ if (query_result == START_REQUEST) {
+ pending_requests_.Erase(request);
+ StartRequest(request, START_ASYNC, trigger);
+
+ // StartRequest can modify the pending list, so we (re)start evaluation
+ // from the currently highest priority request. Avoid copying a singular
+ // iterator, which would trigger undefined behavior.
+ if (pending_requests_.GetNextHighestIterator() ==
+ pending_requests_.End())
+ break;
+ request_iter = pending_requests_.GetNextHighestIterator();
+ } else if (query_result == DO_NOT_START_REQUEST_AND_KEEP_SEARCHING) {
+ ++request_iter;
+ continue;
+ } else if (query_result == YIELD_SCHEDULER) {
+ did_scheduler_yield_ = true;
+ break;
+ } else {
+ DCHECK(query_result == DO_NOT_START_REQUEST_AND_STOP_SEARCHING);
+ break;
+ }
+ }
+ }
+
+ bool deprecated_is_loaded_;
+ // Tracks if the main HTML parser has reached the body which marks the end of
+ // layout-blocking resources.
+ // This is disabled and the is always true when kRendererSideResourceScheduler
+ // is enabled.
+ bool deprecated_has_html_body_;
+ bool using_spdy_proxy_;
+ RequestQueue pending_requests_;
+ RequestSet in_flight_requests_;
+ // The number of delayable in-flight requests.
+ size_t in_flight_delayable_count_;
+ // The number of layout-blocking in-flight requests.
+ size_t total_layout_blocking_count_;
+
+ // The number of LoadAnyStartablePendingRequests scans that were skipped due
+ // to smarter task scheduling around reprioritization.
+ int num_skipped_scans_due_to_scheduled_start_;
+
+ // The number of started requests since the last ResumeIfYielded task was
+ // run.
+ int started_requests_since_yielding_;
+
+ // If the scheduler had to yield the start of a request since the last
+ // ResumeIfYielded task was run.
+ bool did_scheduler_yield_;
+
+ // Network quality estimator for network aware resource scheudling. This may
+ // be null.
+ const net::NetworkQualityEstimator* const network_quality_estimator_;
+
+ // The value of the maximum number of delayable requests in flight. This gets
+ // recalculated every time an |OnNavigate| event is triggered.
+ size_t max_delayable_requests_;
+
+ // A pointer to the resource scheduler which contains the resource scheduling
+ // configuration.
+ ResourceScheduler* resource_scheduler_;
+
+ base::WeakPtrFactory<ResourceScheduler::Client> weak_ptr_factory_;
+};
+
+ResourceScheduler::ResourceScheduler(bool enabled)
+ : enabled_(enabled),
+ priority_requests_delayable_(
+ base::FeatureList::IsEnabled(kPrioritySupportedRequestsDelayable)),
+ head_priority_requests_delayable_(base::FeatureList::IsEnabled(
+ kHeadPrioritySupportedRequestsDelayable)),
+ yielding_scheduler_enabled_(
+ base::FeatureList::IsEnabled(kNetworkSchedulerYielding)),
+ max_requests_before_yielding_(base::GetFieldTrialParamByFeatureAsInt(
+ kNetworkSchedulerYielding,
+ kMaxRequestsBeforeYieldingParam,
+ kMaxRequestsBeforeYieldingDefault)),
+ yield_time_(base::TimeDelta::FromMilliseconds(
+ base::GetFieldTrialParamByFeatureAsInt(kNetworkSchedulerYielding,
+ kYieldMsParam,
+ kYieldMsDefault))),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ // Don't run the two experiments together.
+ if (priority_requests_delayable_ && head_priority_requests_delayable_)
+ priority_requests_delayable_ = false;
+}
+
+ResourceScheduler::~ResourceScheduler() {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ DCHECK(unowned_requests_.empty());
+ DCHECK(client_map_.empty());
+}
+
+std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
+ResourceScheduler::ScheduleRequest(int child_id,
+ int route_id,
+ bool is_async,
+ net::URLRequest* url_request) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ClientId client_id = MakeClientId(child_id, route_id);
+ std::unique_ptr<ScheduledResourceRequestImpl> request(
+ new ScheduledResourceRequestImpl(
+ client_id, url_request, this,
+ RequestPriorityParams(url_request->priority(), 0), is_async));
+
+ ClientMap::iterator it = client_map_.find(client_id);
+ if (it == client_map_.end()) {
+ // There are several ways this could happen:
+ // 1. <a ping> requests don't have a route_id.
+ // 2. Most unittests don't send the IPCs needed to register Clients.
+ // 3. The tab is closed while a RequestResource IPC is in flight.
+ unowned_requests_.insert(request.get());
+ request->Start(START_SYNC);
+ return std::move(request);
+ }
+
+ Client* client = it->second;
+ client->ScheduleRequest(*url_request, request.get());
+ return std::move(request);
+}
+
+void ResourceScheduler::RemoveRequest(ScheduledResourceRequestImpl* request) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (base::ContainsKey(unowned_requests_, request)) {
+ unowned_requests_.erase(request);
+ return;
+ }
+
+ ClientMap::iterator client_it = client_map_.find(request->client_id());
+ if (client_it == client_map_.end()) {
+ return;
+ }
+
+ Client* client = client_it->second;
+ client->RemoveRequest(request);
+}
+
+void ResourceScheduler::OnClientCreated(
+ int child_id,
+ int route_id,
+ const net::NetworkQualityEstimator* const network_quality_estimator) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ClientId client_id = MakeClientId(child_id, route_id);
+ DCHECK(!base::ContainsKey(client_map_, client_id));
+
+ Client* client = new Client(network_quality_estimator, this);
+ client_map_[client_id] = client;
+}
+
+void ResourceScheduler::OnClientDeleted(int child_id, int route_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ClientId client_id = MakeClientId(child_id, route_id);
+ ClientMap::iterator it = client_map_.find(client_id);
+ DCHECK(it != client_map_.end());
+
+ Client* client = it->second;
+ // ResourceDispatcherHost cancels all requests except for cross-renderer
+ // navigations, async revalidations and detachable requests after
+ // OnClientDeleted() returns.
+ RequestSet client_unowned_requests = client->StartAndRemoveAllRequests();
+ for (RequestSet::iterator request_it = client_unowned_requests.begin();
+ request_it != client_unowned_requests.end(); ++request_it) {
+ unowned_requests_.insert(*request_it);
+ }
+
+ delete client;
+ client_map_.erase(it);
+}
+
+void ResourceScheduler::DeprecatedOnLoadingStateChanged(int child_id,
+ int route_id,
+ bool is_loaded) {
+ Client* client = GetClient(child_id, route_id);
+ DCHECK(client);
+ client->DeprecatedOnLoadingStateChanged(is_loaded);
+}
+
+void ResourceScheduler::DeprecatedOnNavigate(int child_id, int route_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ClientId client_id = MakeClientId(child_id, route_id);
+
+ ClientMap::iterator it = client_map_.find(client_id);
+ if (it == client_map_.end()) {
+ // The client was likely deleted shortly before we received this IPC.
+ return;
+ }
+
+ Client* client = it->second;
+ client->DeprecatedOnNavigate();
+}
+
+void ResourceScheduler::DeprecatedOnWillInsertBody(int child_id, int route_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ClientId client_id = MakeClientId(child_id, route_id);
+
+ ClientMap::iterator it = client_map_.find(client_id);
+ if (it == client_map_.end()) {
+ // The client was likely deleted shortly before we received this IPC.
+ return;
+ }
+
+ Client* client = it->second;
+ client->DeprecatedOnWillInsertBody();
+}
+
+void ResourceScheduler::OnReceivedSpdyProxiedHttpResponse(int child_id,
+ int route_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ ClientId client_id = MakeClientId(child_id, route_id);
+
+ ClientMap::iterator client_it = client_map_.find(client_id);
+ if (client_it == client_map_.end()) {
+ return;
+ }
+
+ Client* client = client_it->second;
+ client->OnReceivedSpdyProxiedHttpResponse();
+}
+
+bool ResourceScheduler::DeprecatedHasLoadingClients() const {
+ for (const auto& client : client_map_) {
+ if (!client.second->deprecated_is_loaded())
+ return true;
+ }
+ return false;
+}
+
+ResourceScheduler::Client* ResourceScheduler::GetClient(int child_id,
+ int route_id) {
+ ClientId client_id = MakeClientId(child_id, route_id);
+ ClientMap::iterator client_it = client_map_.find(client_id);
+ if (client_it == client_map_.end()) {
+ return nullptr;
+ }
+ return client_it->second;
+}
+
+void ResourceScheduler::ReprioritizeRequest(net::URLRequest* request,
+ net::RequestPriority new_priority,
+ int new_intra_priority_value) {
+ if (request->load_flags() & net::LOAD_IGNORE_LIMITS) {
+ // Requests with the IGNORE_LIMITS flag must stay at MAXIMUM_PRIORITY.
+ return;
+ }
+
+ auto* scheduled_resource_request =
+ ScheduledResourceRequestImpl::ForRequest(request);
+
+ // Downloads don't use the resource scheduler.
+ if (!scheduled_resource_request) {
+ request->SetPriority(new_priority);
+ return;
+ }
+
+ RequestPriorityParams new_priority_params(new_priority,
+ new_intra_priority_value);
+ RequestPriorityParams old_priority_params =
+ scheduled_resource_request->get_request_priority_params();
+
+ if (old_priority_params == new_priority_params)
+ return;
+
+ ClientMap::iterator client_it =
+ client_map_.find(scheduled_resource_request->client_id());
+ if (client_it == client_map_.end()) {
+ // The client was likely deleted shortly before we received this IPC.
+ request->SetPriority(new_priority_params.priority);
+ scheduled_resource_request->set_request_priority_params(
+ new_priority_params);
+ return;
+ }
+
+ Client* client = client_it->second;
+ client->ReprioritizeRequest(scheduled_resource_request, old_priority_params,
+ new_priority_params);
+}
+
+void ResourceScheduler::ReprioritizeRequest(net::URLRequest* request,
+ net::RequestPriority new_priority) {
+ int current_intra_priority = 0;
+ auto* existing_request = ScheduledResourceRequestImpl::ForRequest(request);
+ if (existing_request) {
+ current_intra_priority =
+ existing_request->get_request_priority_params().intra_priority;
+ }
+ ReprioritizeRequest(request, new_priority, current_intra_priority);
+}
+
+ResourceScheduler::ClientId ResourceScheduler::MakeClientId(int child_id,
+ int route_id) {
+ return (static_cast<ResourceScheduler::ClientId>(child_id) << 32) | route_id;
+}
+
+ResourceScheduler::ThrottleDelayable::ThrottleDelayable()
+ : params_for_network_quality_container_(
+ GetParamsForNetworkQualityContainer()) {}
+
+ResourceScheduler::ThrottleDelayable::~ThrottleDelayable() {}
+
+ResourceScheduler::ParamsForNetworkQuality
+ResourceScheduler::ThrottleDelayable::GetParamsForNetworkQuality(
+ const net::NetworkQualityEstimator* network_quality_estimator) const {
+ if (network_quality_estimator) {
+ net::EffectiveConnectionType effective_connection_type =
+ network_quality_estimator->GetEffectiveConnectionType();
+
+ for (const auto& range : params_for_network_quality_container_) {
+ if (effective_connection_type == range.effective_connection_type) {
+ return range;
+ }
+ }
+ }
+
+ return ResourceScheduler::ParamsForNetworkQuality{
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+ kDefaultMaxNumDelayableRequestsPerClient, 0.0};
+}
+
+ResourceScheduler::ParamsForNetworkQualityContainer
+ResourceScheduler::ThrottleDelayable::GetParamsForNetworkQualityContainer() {
+ static const char kMaxDelayableRequestsBase[] = "MaxDelayableRequests";
+ static const char kEffectiveConnectionTypeBase[] = "EffectiveConnectionType";
+ static const char kNonDelayableWeightBase[] = "NonDelayableWeight";
+
+ ParamsForNetworkQualityContainer result;
+ if (!base::FeatureList::IsEnabled(kThrottleDelayable))
+ return result;
+
+ int config_param_index = 1;
+ while (true) {
+ size_t max_delayable_requests;
+
+ if (!base::StringToSizeT(
+ base::GetFieldTrialParamValueByFeature(
+ kThrottleDelayable, kMaxDelayableRequestsBase +
+ base::IntToString(config_param_index)),
+ &max_delayable_requests)) {
+ DCHECK_LE(result.size(), 20u);
+ return result;
+ }
+
+ base::Optional<net::EffectiveConnectionType> effective_connection_type =
+ net::GetEffectiveConnectionTypeForName(
+ base::GetFieldTrialParamValueByFeature(
+ kThrottleDelayable, kEffectiveConnectionTypeBase +
+ base::IntToString(config_param_index)));
+ if (!effective_connection_type)
+ return result;
+
+ double non_delayable_weight;
+ if (!base::StringToDouble(
+ base::GetFieldTrialParamValueByFeature(
+ kThrottleDelayable, kNonDelayableWeightBase +
+ base::IntToString(config_param_index)),
+ &non_delayable_weight)) {
+ return result;
+ }
+
+ result.push_back({effective_connection_type.value(), max_delayable_requests,
+ non_delayable_weight});
+ config_param_index++;
+ }
+}
+
+bool ResourceScheduler::IsRendererSideResourceSchedulerEnabled() {
+ // We are assuming that kRendererSideResourceScheduler will be shipped when
+ // launching Network Service, so let's act as if
+ // kRendererSideResourceScheduler is enabled when kNetworkService is enabled.
+ return base::FeatureList::IsEnabled(
+ features::kRendererSideResourceScheduler) ||
+ base::FeatureList::IsEnabled(features::kNetworkService);
+}
+
+} // namespace network
diff --git a/chromium/services/network/resource_scheduler.h b/chromium/services/network/resource_scheduler.h
new file mode 100644
index 00000000000..af91cbaac2a
--- /dev/null
+++ b/chromium/services/network/resource_scheduler.h
@@ -0,0 +1,300 @@
+// 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 SERVICES_NETWORK_RESOURCE_SCHEDULER_H_
+#define SERVICES_NETWORK_RESOURCE_SCHEDULER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/component_export.h"
+#include "base/feature_list.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequence_checker.h"
+#include "base/time/time.h"
+#include "net/base/priority_queue.h"
+#include "net/base/request_priority.h"
+#include "net/nqe/effective_connection_type.h"
+
+namespace base {
+class SequencedTaskRunner;
+}
+
+namespace net {
+class URLRequest;
+class NetworkQualityEstimator;
+} // namespace net
+
+namespace network {
+
+// There is one ResourceScheduler. All renderer-initiated HTTP requests are
+// expected to pass through it.
+//
+// There are two types of input to the scheduler:
+// 1. Requests to start, cancel, or finish fetching a resource.
+// 2. Notifications for renderer events, such as new tabs, navigation and
+// painting.
+//
+// These input come from different threads, so they may not be in sync. The UI
+// thread is considered the authority on renderer lifetime, which means some
+// IPCs may be meaningless if they arrive after the UI thread signals a renderer
+// has been deleted.
+//
+// The ResourceScheduler tracks many Clients, which should correlate with tabs.
+// A client is uniquely identified by its child_id and route_id.
+//
+// Each Client may have many Requests in flight. Requests are uniquely
+// identified within a Client by its ScheduledResourceRequest.
+//
+// Users should call ScheduleRequest() to notify this ResourceScheduler of a new
+// request. The returned ResourceThrottle should be destroyed when the load
+// finishes or is canceled, before the net::URLRequest.
+//
+// The scheduler may defer issuing the request via the ResourceThrottle
+// interface or it may alter the request's priority by calling set_priority() on
+// the URLRequest.
+class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceScheduler {
+ public:
+ class ScheduledResourceRequest {
+ public:
+ ScheduledResourceRequest();
+ virtual ~ScheduledResourceRequest();
+ virtual void WillStartRequest(bool* defer) = 0;
+
+ void set_resume_callback(base::OnceClosure callback) {
+ resume_callback_ = std::move(callback);
+ }
+ void RunResumeCallback();
+
+ private:
+ base::OnceClosure resume_callback_;
+ };
+ // A struct that stores the Network Quality values and loading parameters when
+ // the observed Network Quality matches the specified network quality value.
+ struct ParamsForNetworkQuality {
+ // The observed Effective Connection Type (ECT) should be
+ // |effective_connection_type| for the loading parameters specified in this
+ // struct to apply.
+ net::EffectiveConnectionType effective_connection_type;
+ // The maximum number of delayable requests allowed.
+ size_t max_delayable_requests;
+ // The weight of a non-delayable request when counting the effective number
+ // of non-delayable requests in-flight.
+ double non_delayable_weight;
+ };
+ typedef std::vector<ParamsForNetworkQuality> ParamsForNetworkQualityContainer;
+
+ explicit ResourceScheduler(bool enabled);
+ ~ResourceScheduler();
+
+ // Requests that this ResourceScheduler schedule, and eventually loads, the
+ // specified |url_request|. Caller should delete the returned ResourceThrottle
+ // when the load completes or is canceled, before |url_request| is deleted.
+ std::unique_ptr<ScheduledResourceRequest> ScheduleRequest(
+ int child_id,
+ int route_id,
+ bool is_async,
+ net::URLRequest* url_request);
+
+ // Signals from the UI thread, posted as tasks on the IO thread:
+
+ // Called when a renderer is created. |network_quality_estimator| is allowed
+ // to be null.
+ void OnClientCreated(
+ int child_id,
+ int route_id,
+ const net::NetworkQualityEstimator* const network_quality_estimator);
+
+ // Called when a renderer is destroyed.
+ void OnClientDeleted(int child_id, int route_id);
+
+ // Called when a renderer stops or restarts loading.
+ // Do not call this function when the network service is enabled.
+ void DeprecatedOnLoadingStateChanged(int child_id,
+ int route_id,
+ bool is_loaded);
+
+ // Signals from IPC messages directly from the renderers:
+
+ // Called when a client navigates to a new main document.
+ // Do not call this function when the network service is enabled.
+ void DeprecatedOnNavigate(int child_id, int route_id);
+
+ // Called when the client has parsed the <body> element. This is a signal that
+ // resource loads won't interfere with first paint.
+ // Do not call this function when the network service is enabled.
+ void DeprecatedOnWillInsertBody(int child_id, int route_id);
+
+ // Signals from the IO thread:
+
+ // Called when we received a response to a http request that was served
+ // from a proxy using SPDY.
+ void OnReceivedSpdyProxiedHttpResponse(int child_id, int route_id);
+
+ // Client functions:
+
+ // Returns true if at least one client is currently loading.
+ // Do not call this function when the network service is enabled.
+ bool DeprecatedHasLoadingClients() const;
+
+ // Updates the priority for |request|. Modifies request->priority(), and may
+ // start the request loading if it wasn't already started.
+ // If the scheduler does not know about the request, |new_priority| is set but
+ // |intra_priority_value| is ignored.
+ void ReprioritizeRequest(net::URLRequest* request,
+ net::RequestPriority new_priority,
+ int intra_priority_value);
+ // Same as above, but keeps the existing intra priority value.
+ void ReprioritizeRequest(net::URLRequest* request,
+ net::RequestPriority new_priority);
+
+ // Public for tests.
+ static ParamsForNetworkQualityContainer
+ GetParamsForNetworkQualityContainerForTests() {
+ return ThrottleDelayable::GetParamsForNetworkQualityContainer();
+ }
+
+ bool priority_requests_delayable() const {
+ return priority_requests_delayable_;
+ }
+ bool head_priority_requests_delayable() const {
+ return head_priority_requests_delayable_;
+ }
+ bool yielding_scheduler_enabled() const {
+ return yielding_scheduler_enabled_;
+ }
+ int max_requests_before_yielding() const {
+ return max_requests_before_yielding_;
+ }
+ base::TimeDelta yield_time() const { return yield_time_; }
+ base::SequencedTaskRunner* task_runner() { return task_runner_.get(); }
+
+ // Testing setters
+ void SetMaxRequestsBeforeYieldingForTesting(
+ int max_requests_before_yielding) {
+ max_requests_before_yielding_ = max_requests_before_yielding;
+ }
+ void SetYieldTimeForTesting(base::TimeDelta yield_time) {
+ yield_time_ = yield_time;
+ }
+ void SetTaskRunnerForTesting(
+ scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner) {
+ task_runner_ = std::move(sequenced_task_runner);
+ }
+
+ bool enabled() const { return enabled_; }
+
+ static bool IsRendererSideResourceSchedulerEnabled();
+
+ private:
+ class Client;
+ class RequestQueue;
+ class ScheduledResourceRequestImpl;
+ struct RequestPriorityParams;
+ struct ScheduledResourceSorter {
+ bool operator()(const ScheduledResourceRequestImpl* a,
+ const ScheduledResourceRequestImpl* b) const;
+ };
+
+ // Experiment parameters and helper functions for varying the maximum number
+ // of delayable requests in-flight based on the observed Effective Connection
+ // Type (ECT), or in the presence of non-delayable requests in-flight.
+ class ThrottleDelayable {
+ public:
+ ThrottleDelayable();
+ ~ThrottleDelayable();
+
+ // Returns the parameters for resource loading based on the current
+ // value of the network quality and the parameters set by ThrottleDelayable
+ // experiment.
+ ParamsForNetworkQuality GetParamsForNetworkQuality(
+ const net::NetworkQualityEstimator* network_quality_estimator) const;
+
+ private:
+ // Friend for tests.
+ friend class ResourceScheduler;
+
+ // Reads experiment parameters and creates a vector of
+ // |ParamsForNetworkQualityContainer| to populate
+ // |params_for_network_quality_container_|. It looks for configuration
+ // parameters with sequential numeric suffixes, and stops looking after the
+ // first failure to find an experimetal parameter. A sample configuration is
+ // given below:
+ // "EffectiveConnectionType1": "Slow-2G",
+ // "MaxDelayableRequests1": "6",
+ // "NonDelayableWeight1": "2.0",
+ // "EffectiveConnectionType2": "3G",
+ // "MaxDelayableRequests2": "12",
+ // "NonDelayableWeight2": "3.0",
+ // This config implies that when Effective Connection Type (ECT) is Slow-2G,
+ // then the maximum number of non-delayable requests should be
+ // limited to 6, and the non-delayable request weight should be set to 2.
+ // When ECT is 3G, it should be limited to 12. For all other values of ECT,
+ // the default values should be used.
+ static ParamsForNetworkQualityContainer
+ GetParamsForNetworkQualityContainer();
+
+ // The number of delayable requests in-flight for different ranges of the
+ // network quality.
+ const ParamsForNetworkQualityContainer
+ params_for_network_quality_container_;
+ };
+
+ typedef int64_t ClientId;
+ typedef std::map<ClientId, Client*> ClientMap;
+ typedef std::set<ScheduledResourceRequestImpl*> RequestSet;
+
+ // Called when a ScheduledResourceRequest is destroyed.
+ void RemoveRequest(ScheduledResourceRequestImpl* request);
+
+ // Returns the client ID for the given |child_id| and |route_id| combo.
+ ClientId MakeClientId(int child_id, int route_id);
+
+ // Returns the client for the given |child_id| and |route_id| combo.
+ Client* GetClient(int child_id, int route_id);
+
+ ClientMap client_map_;
+ RequestSet unowned_requests_;
+
+ // Whether or not to enable ResourceScheduling. This will almost always be
+ // enabled, except for some C++ headless embedders who may implement their own
+ // resource scheduling via protocol handlers.
+ const bool enabled_;
+
+ // True if requests to servers that support priorities (e.g., H2/QUIC) can
+ // be delayed.
+ bool priority_requests_delayable_;
+
+ // True if requests to servers that support priorities (e.g., H2/QUIC) can
+ // be delayed while the parser is in head.
+ bool head_priority_requests_delayable_;
+
+ // True if the scheduler should yield between several successive calls to
+ // start resource requests.
+ bool yielding_scheduler_enabled_;
+ int max_requests_before_yielding_;
+ base::TimeDelta yield_time_;
+
+ const ThrottleDelayable throttle_delayable_;
+
+ // The TaskRunner to post tasks on. Can be overridden for tests.
+ scoped_refptr<base::SequencedTaskRunner> task_runner_;
+
+ SEQUENCE_CHECKER(sequence_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceScheduler);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_RESOURCE_SCHEDULER_H_
diff --git a/chromium/services/network/resource_scheduler_client.cc b/chromium/services/network/resource_scheduler_client.cc
new file mode 100644
index 00000000000..38098de5f11
--- /dev/null
+++ b/chromium/services/network/resource_scheduler_client.cc
@@ -0,0 +1,45 @@
+// Copyright 2018 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/network/resource_scheduler_client.h"
+
+#include "net/url_request/url_request_context.h"
+#include "services/network/network_context.h"
+
+namespace network {
+
+ResourceSchedulerClient::ResourceSchedulerClient(
+ int child_id,
+ int route_id,
+ ResourceScheduler* resource_scheduler,
+ net::NetworkQualityEstimator* estimator)
+ : child_id_(child_id),
+ route_id_(route_id),
+ resource_scheduler_(resource_scheduler) {
+ resource_scheduler_->OnClientCreated(child_id_, route_id_, estimator);
+}
+
+ResourceSchedulerClient::~ResourceSchedulerClient() {
+ resource_scheduler_->OnClientDeleted(child_id_, route_id_);
+}
+
+std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
+ResourceSchedulerClient::ScheduleRequest(bool is_async,
+ net::URLRequest* url_request) {
+ return resource_scheduler_->ScheduleRequest(child_id_, route_id_, is_async,
+ url_request);
+}
+
+void ResourceSchedulerClient::ReprioritizeRequest(
+ net::URLRequest* request,
+ net::RequestPriority new_priority,
+ int intra_priority_value) {
+ resource_scheduler_->ReprioritizeRequest(request, new_priority,
+ intra_priority_value);
+}
+void ResourceSchedulerClient::OnReceivedSpdyProxiedHttpResponse() {
+ resource_scheduler_->OnReceivedSpdyProxiedHttpResponse(child_id_, route_id_);
+}
+
+} // namespace network
diff --git a/chromium/services/network/resource_scheduler_client.h b/chromium/services/network/resource_scheduler_client.h
new file mode 100644
index 00000000000..beefc2ec23b
--- /dev/null
+++ b/chromium/services/network/resource_scheduler_client.h
@@ -0,0 +1,55 @@
+// Copyright 2018 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 SERVICES_NETWORK_RESOURCE_SCHEDULER_CLIENT_H_
+#define SERVICES_NETWORK_RESOURCE_SCHEDULER_CLIENT_H_
+
+#include "base/memory/ref_counted.h"
+#include "net/base/request_priority.h"
+#include "services/network/resource_scheduler.h"
+
+namespace net {
+class URLRequest;
+class NetworkQualityEstimator;
+} // namespace net
+
+namespace network {
+
+// ResourceSchedulerClient represents ResourceScheduler::Client. At this
+// moment it uses two integers (child_id and route_id) to specify a client
+// for compatibility with content/browser/loader users, but this should be
+// changed to a less error-prone interface once Network Service is launched.
+// A ResourceSchedulerClient instance can be shared, but it must not outlive
+// the associated ResourceScheduler. Failing to keep the contract will be
+// detected by a DCHECK in ResourceScheduler's destructor which checks if all
+// clients are removed.
+class COMPONENT_EXPORT(NETWORK_SERVICE) ResourceSchedulerClient final
+ : public base::RefCounted<ResourceSchedulerClient> {
+ public:
+ ResourceSchedulerClient(int child_id,
+ int route_id,
+ ResourceScheduler* resource_scheduler,
+ net::NetworkQualityEstimator* estimator);
+
+ std::unique_ptr<ResourceScheduler::ScheduledResourceRequest> ScheduleRequest(
+ bool is_async,
+ net::URLRequest* url_request);
+ void ReprioritizeRequest(net::URLRequest* request,
+ net::RequestPriority new_priority,
+ int intra_priority_value);
+ void OnReceivedSpdyProxiedHttpResponse();
+
+ private:
+ friend class base::RefCounted<ResourceSchedulerClient>;
+ ~ResourceSchedulerClient();
+
+ const int child_id_;
+ const int route_id_;
+ ResourceScheduler* const resource_scheduler_;
+
+ DISALLOW_COPY_AND_ASSIGN(ResourceSchedulerClient);
+};
+} // namespace network
+
+#endif // SERVICES_NETWORK_RESOURCE_SCHEDULER_CLIENT_H_
diff --git a/chromium/services/network/resource_scheduler_unittest.cc b/chromium/services/network/resource_scheduler_unittest.cc
new file mode 100644
index 00000000000..99cdd3ddd74
--- /dev/null
+++ b/chromium/services/network/resource_scheduler_unittest.cc
@@ -0,0 +1,2014 @@
+// 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 "services/network/resource_scheduler.h"
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/field_trial_param_associator.h"
+#include "base/metrics/field_trial_params.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/test/histogram_tester.h"
+#include "base/test/mock_entropy_provider.h"
+#include "base/test/scoped_feature_list.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/timer/mock_timer.h"
+#include "base/timer/timer.h"
+#include "net/base/host_port_pair.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/nqe/network_quality_estimator_test_util.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_test_util.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/scheme_host_port.h"
+
+using std::string;
+
+namespace network {
+
+namespace {
+
+class TestRequestFactory;
+
+const int kChildId = 30;
+const int kRouteId = 75;
+const int kChildId2 = 43;
+const int kRouteId2 = 67;
+const int kBackgroundChildId = 35;
+const int kBackgroundRouteId = 43;
+
+// Sync below with cc file.
+const char kPrioritySupportedRequestsDelayable[] =
+ "PrioritySupportedRequestsDelayable";
+const char kHeadPrioritySupportedRequestsDelayable[] =
+ "HeadPriorityRequestsDelayable";
+const char kNetworkSchedulerYielding[] = "NetworkSchedulerYielding";
+const size_t kMaxNumDelayableRequestsPerHostPerClient = 6;
+
+void ConfigureYieldFieldTrial(
+ int max_requests_before_yielding,
+ int max_yield_ms,
+ base::test::ScopedFeatureList* scoped_feature_list) {
+ const std::string kTrialName = "TrialName";
+ const std::string kGroupName = "GroupName"; // Value not used
+ const std::string kNetworkSchedulerYielding = "NetworkSchedulerYielding";
+
+ scoped_refptr<base::FieldTrial> trial =
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+
+ std::map<std::string, std::string> params;
+ params["MaxRequestsBeforeYieldingParam"] =
+ base::IntToString(max_requests_before_yielding);
+ params["MaxYieldMs"] = base::IntToString(max_yield_ms);
+ base::FieldTrialParamAssociator::GetInstance()->AssociateFieldTrialParams(
+ kTrialName, kGroupName, params);
+
+ std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
+ feature_list->RegisterFieldTrialOverride(
+ kNetworkSchedulerYielding, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+ trial.get());
+ scoped_feature_list->InitWithFeatureList(std::move(feature_list));
+}
+
+class TestRequest {
+ public:
+ TestRequest(std::unique_ptr<net::URLRequest> url_request,
+ std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
+ scheduled_request,
+ ResourceScheduler* scheduler)
+ : started_(false),
+ url_request_(std::move(url_request)),
+ scheduled_request_(std::move(scheduled_request)),
+ scheduler_(scheduler) {
+ scheduled_request_->set_resume_callback(
+ base::BindRepeating(&TestRequest::Resume, base::Unretained(this)));
+ }
+ virtual ~TestRequest() {
+ // The URLRequest must still be valid when the ScheduledResourceRequest is
+ // destroyed, so that it can unregister itself.
+ scheduled_request_.reset();
+ }
+
+ bool started() const { return started_; }
+
+ void Start() {
+ bool deferred = false;
+ scheduled_request_->WillStartRequest(&deferred);
+ started_ = !deferred;
+ }
+
+ void ChangePriority(net::RequestPriority new_priority, int intra_priority) {
+ scheduler_->ReprioritizeRequest(url_request_.get(), new_priority,
+ intra_priority);
+ }
+
+ const net::URLRequest* url_request() const { return url_request_.get(); }
+
+ virtual void Resume() { started_ = true; }
+
+ private:
+ bool started_;
+ std::unique_ptr<net::URLRequest> url_request_;
+ std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
+ scheduled_request_;
+ ResourceScheduler* scheduler_;
+};
+
+class CancelingTestRequest : public TestRequest {
+ public:
+ CancelingTestRequest(
+ std::unique_ptr<net::URLRequest> url_request,
+ std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
+ scheduled_request,
+ ResourceScheduler* scheduler)
+ : TestRequest(std::move(url_request),
+ std::move(scheduled_request),
+ scheduler) {}
+
+ void set_request_to_cancel(std::unique_ptr<TestRequest> request_to_cancel) {
+ request_to_cancel_ = std::move(request_to_cancel);
+ }
+
+ private:
+ void Resume() override {
+ TestRequest::Resume();
+ request_to_cancel_.reset();
+ }
+
+ std::unique_ptr<TestRequest> request_to_cancel_;
+};
+
+class ResourceSchedulerTest : public testing::Test {
+ protected:
+ ResourceSchedulerTest() : field_trial_list_(nullptr) {
+ InitializeScheduler();
+ context_.set_http_server_properties(&http_server_properties_);
+ context_.set_network_quality_estimator(&network_quality_estimator_);
+ }
+
+ ~ResourceSchedulerTest() override { CleanupScheduler(); }
+
+ // Done separately from construction to allow for modification of command
+ // line flags in tests.
+ void InitializeScheduler(bool enabled = true) {
+ CleanupScheduler();
+
+ // Destroys previous scheduler, also destroys any previously created
+ // mock_timer_.
+ scheduler_.reset(new ResourceScheduler(enabled));
+
+ scheduler_->OnClientCreated(kChildId, kRouteId,
+ &network_quality_estimator_);
+ scheduler_->OnClientCreated(kBackgroundChildId, kBackgroundRouteId,
+ &network_quality_estimator_);
+ }
+
+ void CleanupScheduler() {
+ if (scheduler_) {
+ scheduler_->OnClientDeleted(kChildId, kRouteId);
+ scheduler_->OnClientDeleted(kBackgroundChildId, kBackgroundRouteId);
+ }
+ }
+
+ std::unique_ptr<net::URLRequest> NewURLRequestWithChildAndRoute(
+ const char* url,
+ net::RequestPriority priority,
+ int child_id,
+ int route_id) {
+ std::unique_ptr<net::URLRequest> url_request(context_.CreateRequest(
+ GURL(url), priority, nullptr, TRAFFIC_ANNOTATION_FOR_TESTS));
+ return url_request;
+ }
+
+ std::unique_ptr<net::URLRequest> NewURLRequest(
+ const char* url,
+ net::RequestPriority priority) {
+ return NewURLRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
+ }
+
+ std::unique_ptr<TestRequest> NewRequestWithRoute(
+ const char* url,
+ net::RequestPriority priority,
+ int route_id) {
+ return NewRequestWithChildAndRoute(url, priority, kChildId, route_id);
+ }
+
+ std::unique_ptr<TestRequest> NewRequestWithChildAndRoute(
+ const char* url,
+ net::RequestPriority priority,
+ int child_id,
+ int route_id) {
+ return GetNewTestRequest(url, priority, child_id, route_id, true);
+ }
+
+ std::unique_ptr<TestRequest> NewRequest(const char* url,
+ net::RequestPriority priority) {
+ return NewRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
+ }
+
+ std::unique_ptr<TestRequest> NewBackgroundRequest(
+ const char* url,
+ net::RequestPriority priority) {
+ return NewRequestWithChildAndRoute(url, priority, kBackgroundChildId,
+ kBackgroundRouteId);
+ }
+
+ std::unique_ptr<TestRequest> NewSyncRequest(const char* url,
+ net::RequestPriority priority) {
+ return NewSyncRequestWithChildAndRoute(url, priority, kChildId, kRouteId);
+ }
+
+ std::unique_ptr<TestRequest> NewBackgroundSyncRequest(
+ const char* url,
+ net::RequestPriority priority) {
+ return NewSyncRequestWithChildAndRoute(url, priority, kBackgroundChildId,
+ kBackgroundRouteId);
+ }
+
+ std::unique_ptr<TestRequest> NewSyncRequestWithChildAndRoute(
+ const char* url,
+ net::RequestPriority priority,
+ int child_id,
+ int route_id) {
+ return GetNewTestRequest(url, priority, child_id, route_id, false);
+ }
+
+ std::unique_ptr<TestRequest> GetNewTestRequest(const char* url,
+ net::RequestPriority priority,
+ int child_id,
+ int route_id,
+ bool is_async) {
+ std::unique_ptr<net::URLRequest> url_request(
+ NewURLRequestWithChildAndRoute(url, priority, child_id, route_id));
+ auto scheduled_request = scheduler_->ScheduleRequest(
+ child_id, route_id, is_async, url_request.get());
+ auto request = std::make_unique<TestRequest>(
+ std::move(url_request), std::move(scheduled_request), scheduler());
+ request->Start();
+ return request;
+ }
+
+ void ChangeRequestPriority(TestRequest* request,
+ net::RequestPriority new_priority,
+ int intra_priority = 0) {
+ request->ChangePriority(new_priority, intra_priority);
+ }
+
+ void FireCoalescingTimer() {
+ EXPECT_TRUE(mock_timer_->IsRunning());
+ mock_timer_->Fire();
+ }
+
+ void RequestLimitOverrideConfigTestHelper(bool experiment_status) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ InitializeThrottleDelayableExperiment(&scoped_feature_list,
+ experiment_status, 0.0);
+
+ // Set the effective connection type to Slow-2G, which is slower than the
+ // threshold configured in |InitializeMaxDelayableRequestsExperiment|. Needs
+ // to be done before initializing the scheduler because the client is
+ // created on the call to |InitializeScheduler|, which is where the initial
+ // limits for the delayable requests in flight are computed.
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ // Initialize the scheduler.
+ InitializeScheduler();
+
+ // For 2G, the typical values of RTT and bandwidth should result in the
+ // override taking effect with the experiment enabled. For this case, the
+ // new limit is 2. The limit will matter only once the page has a body,
+ // since delayable requests are not loaded before that.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high2", net::HIGHEST));
+ EXPECT_TRUE(high2->started());
+
+ // Should match the configuration set by
+ // |InitializeMaxDelayableRequestsExperiment|
+ const int kOverriddenNumRequests = 2;
+
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+ // Queue the maximum number of delayable requests that should be started
+ // before the resource scheduler starts throttling delayable requests.
+ for (int i = 0; i < kOverriddenNumRequests; ++i) {
+ std::string url = "http://host/low" + base::IntToString(i);
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_TRUE(lows_singlehost[i]->started());
+ }
+
+ std::unique_ptr<TestRequest> second_last_singlehost(
+ NewRequest("http://host/s_last", net::LOWEST));
+ std::unique_ptr<TestRequest> last_singlehost(
+ NewRequest("http://host/last", net::LOWEST));
+
+ if (experiment_status) {
+ // Experiment enabled, hence requests should be limited.
+ // Second last should not start because there are |kOverridenNumRequests|
+ // delayable requests already in-flight.
+ EXPECT_FALSE(second_last_singlehost->started());
+
+ // Completion of a delayable request must result in starting of the
+ // second-last request.
+ lows_singlehost.erase(lows_singlehost.begin());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(second_last_singlehost->started());
+ EXPECT_FALSE(last_singlehost->started());
+
+ // Completion of another delayable request must result in starting of the
+ // last request.
+ lows_singlehost.erase(lows_singlehost.begin());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(last_singlehost->started());
+ } else {
+ // Requests should start because the default limit is 10.
+ EXPECT_TRUE(second_last_singlehost->started());
+ EXPECT_TRUE(last_singlehost->started());
+ }
+ }
+
+ void InitializeThrottleDelayableExperiment(
+ base::test::ScopedFeatureList* scoped_feature_list,
+ bool lower_delayable_count_enabled,
+ double non_delayable_weight) {
+ std::map<std::string, std::string> params;
+ bool experiment_enabled = false;
+ if (lower_delayable_count_enabled) {
+ experiment_enabled = true;
+ params["EffectiveConnectionType1"] = "Slow-2G";
+ params["MaxDelayableRequests1"] = "2";
+ params["NonDelayableWeight1"] = "0.0";
+
+ params["EffectiveConnectionType2"] = "3G";
+ params["MaxDelayableRequests2"] = "4";
+ params["NonDelayableWeight2"] = "0.0";
+ }
+
+ if (non_delayable_weight > 0.0) {
+ experiment_enabled = true;
+ params["EffectiveConnectionType1"] = "Slow-2G";
+ if (params["MaxDelayableRequests1"] == "")
+ params["MaxDelayableRequests1"] = "10";
+ params["NonDelayableWeight1"] =
+ base::NumberToString(non_delayable_weight);
+ }
+
+ base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
+ const char kTrialName[] = "TrialName";
+ const char kGroupName[] = "GroupName";
+
+ ASSERT_TRUE(
+ base::AssociateFieldTrialParams(kTrialName, kGroupName, params));
+ base::FieldTrial* field_trial =
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+ ASSERT_TRUE(field_trial);
+
+ std::unique_ptr<base::FeatureList> feature_list(
+ std::make_unique<base::FeatureList>());
+ feature_list->RegisterFieldTrialOverride(
+ "ThrottleDelayable",
+ experiment_enabled ? base::FeatureList::OVERRIDE_ENABLE_FEATURE
+ : base::FeatureList::OVERRIDE_DISABLE_FEATURE,
+ field_trial);
+ scoped_feature_list->InitWithFeatureList(std::move(feature_list));
+
+ ResourceScheduler::ParamsForNetworkQualityContainer
+ params_network_quality_container =
+ ResourceScheduler::GetParamsForNetworkQualityContainerForTests();
+
+ if (!lower_delayable_count_enabled && non_delayable_weight <= 0.0) {
+ ASSERT_EQ(0u, params_network_quality_container.size());
+ return;
+ }
+
+ // Check that the configuration was parsed and stored correctly.
+ ASSERT_EQ(lower_delayable_count_enabled ? 2u : 1u,
+ params_network_quality_container.size());
+
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ params_network_quality_container[0].effective_connection_type);
+ EXPECT_EQ(non_delayable_weight > 0.0 ? 10u : 2u,
+ params_network_quality_container[0].max_delayable_requests);
+ EXPECT_EQ(non_delayable_weight > 0.0 ? non_delayable_weight : 0.0,
+ params_network_quality_container[0].non_delayable_weight);
+
+ if (lower_delayable_count_enabled) {
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_3G,
+ params_network_quality_container[1].effective_connection_type);
+ EXPECT_EQ(4u, params_network_quality_container[1].max_delayable_requests);
+ EXPECT_EQ(0.0, params_network_quality_container[1].non_delayable_weight);
+ }
+ }
+
+ void ReadConfigTestHelper(size_t num_ranges) {
+ const char kTrialName[] = "TrialName";
+ const char kGroupName[] = "GroupName";
+ const char kThrottleDelayable[] = "ThrottleDelayable";
+
+ base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
+ base::test::ScopedFeatureList scoped_feature_list;
+ std::map<std::string, std::string> params;
+ for (size_t index = 1; index <= num_ranges; index++) {
+ std::string index_str = base::NumberToString(index);
+ params["EffectiveConnectionType" + index_str] =
+ net::GetNameForEffectiveConnectionType(
+ static_cast<net::EffectiveConnectionType>(1 + index));
+ params["MaxDelayableRequests" + index_str] = index_str + "0";
+ params["NonDelayableWeight" + index_str] = "0";
+ }
+
+ base::AssociateFieldTrialParams(kTrialName, kGroupName, params);
+ base::FieldTrial* field_trial =
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+ std::unique_ptr<base::FeatureList> feature_list(
+ std::make_unique<base::FeatureList>());
+ feature_list->RegisterFieldTrialOverride(
+ kThrottleDelayable, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+ field_trial);
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
+
+ ResourceScheduler::ParamsForNetworkQualityContainer
+ params_network_quality_container =
+ ResourceScheduler::GetParamsForNetworkQualityContainerForTests();
+
+ // Check that the configuration was parsed and stored correctly.
+ ASSERT_EQ(params_network_quality_container.size(), num_ranges);
+ for (size_t index = 1; index <= num_ranges; index++) {
+ EXPECT_EQ(1 + index,
+ static_cast<size_t>(params_network_quality_container[index - 1]
+ .effective_connection_type));
+ EXPECT_EQ(
+ index * 10u,
+ params_network_quality_container[index - 1].max_delayable_requests);
+ EXPECT_EQ(
+ 0, params_network_quality_container[index - 1].non_delayable_weight);
+ }
+ }
+
+ void NonDelayableThrottlesDelayableHelper(double non_delayable_weight) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ // Should be in sync with .cc.
+ const int kDefaultMaxNumDelayableRequestsPerClient = 10;
+ // Initialize the experiment.
+ InitializeThrottleDelayableExperiment(&scoped_feature_list, false,
+ non_delayable_weight);
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+
+ InitializeScheduler();
+ // Limit will only trigger after the page has a body.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ // Start one non-delayable request.
+ std::unique_ptr<TestRequest> non_delayable_request(
+ NewRequest("http://host/medium", net::MEDIUM));
+ // Start |kDefaultMaxNumDelayableRequestsPerClient - 1 *
+ // |non_delayable_weight| delayable requests. They should all start.
+ std::vector<std::unique_ptr<TestRequest>> delayable_requests;
+ for (int i = 0;
+ i < kDefaultMaxNumDelayableRequestsPerClient - non_delayable_weight;
+ ++i) {
+ delayable_requests.push_back(NewRequest(
+ base::StringPrintf("http://host%d/low", i).c_str(), net::LOWEST));
+ EXPECT_TRUE(delayable_requests.back()->started());
+ }
+ // The next delayable request should not start.
+ std::unique_ptr<TestRequest> last_low(
+ NewRequest("http://lasthost/low", net::LOWEST));
+ EXPECT_FALSE(last_low->started());
+ }
+
+ ResourceScheduler* scheduler() { return scheduler_.get(); }
+
+ base::MessageLoop message_loop_;
+ std::unique_ptr<ResourceScheduler> scheduler_;
+ base::MockTimer* mock_timer_;
+ net::HttpServerPropertiesImpl http_server_properties_;
+ net::TestNetworkQualityEstimator network_quality_estimator_;
+ net::TestURLRequestContext context_;
+ base::FieldTrialList field_trial_list_;
+};
+
+TEST_F(ResourceSchedulerTest, OneIsolatedLowRequest) {
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/1", net::LOWEST));
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInserted) {
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_TRUE(high->started());
+ EXPECT_TRUE(low->started());
+ EXPECT_FALSE(low2->started());
+
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(low2->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low2->started());
+}
+
+TEST_F(ResourceSchedulerTest, OneLowLoadsUntilCriticalComplete) {
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_TRUE(high->started());
+ EXPECT_TRUE(low->started());
+ EXPECT_FALSE(low2->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(low2->started());
+
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low2->started());
+}
+
+TEST_F(ResourceSchedulerTest, MediumDoesNotBlockCriticalComplete) {
+ // kLayoutBlockingPriorityThreshold determines what priority level above which
+ // requests are considered layout-blocking and must be completed before the
+ // critical loading period is complete. It is currently set to net::MEDIUM.
+ std::unique_ptr<TestRequest> medium(
+ NewRequest("http://host/low", net::MEDIUM));
+ std::unique_ptr<TestRequest> lowest(
+ NewRequest("http://host/lowest", net::LOWEST));
+ std::unique_ptr<TestRequest> lowest2(
+ NewRequest("http://host/lowest", net::LOWEST));
+ EXPECT_TRUE(medium->started());
+ EXPECT_TRUE(lowest->started());
+ EXPECT_FALSE(lowest2->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(lowest2->started());
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerYieldsOnSpdy) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
+ InitializeScheduler();
+
+ // The second low-priority request should yield.
+ scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
+
+ // Set a custom yield time.
+ scheduler_->SetYieldTimeForTesting(base::TimeDelta::FromMilliseconds(42));
+
+ // Use a testing task runner so that we can control time.
+ auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+ scheduler_->SetTaskRunnerForTesting(task_runner);
+
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ std::unique_ptr<TestRequest> request2(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ std::unique_ptr<TestRequest> request3(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+
+ // Just before the yield task runs, only the first request should have
+ // started.
+ task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(41));
+ EXPECT_TRUE(request->started());
+ EXPECT_FALSE(request2->started());
+ EXPECT_FALSE(request3->started());
+
+ // Yield is done, run the next task.
+ task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+ EXPECT_TRUE(request2->started());
+ EXPECT_FALSE(request3->started());
+
+ // Just before the yield task runs, only the first two requests should have
+ // started.
+ task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(41));
+ EXPECT_FALSE(request3->started());
+
+ // Yield is done, run the next task.
+ task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+ EXPECT_TRUE(request3->started());
+}
+
+// Same as SchedulerYieldsOnSpdy but uses FieldTrial Parameters for
+// configuration.
+TEST_F(ResourceSchedulerTest, SchedulerYieldFieldTrialParams) {
+ base::test::ScopedFeatureList scoped_feature_list;
+
+ ConfigureYieldFieldTrial(1 /* requests before yielding */,
+ 42 /* yield time */, &scoped_feature_list);
+ InitializeScheduler();
+
+ // Make sure the parameters were properly set.
+ EXPECT_EQ(42, scheduler_->yield_time().InMilliseconds());
+ EXPECT_EQ(1, scheduler_->max_requests_before_yielding());
+
+ // Use a testing task runner so that we can control time.
+ auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+ scheduler_->SetTaskRunnerForTesting(task_runner);
+
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ std::unique_ptr<TestRequest> request2(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+
+ // Just before the yield task runs, only the first request should have
+ // started.
+ task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(41));
+ EXPECT_TRUE(request->started());
+ EXPECT_FALSE(request2->started());
+
+ // Yield is done, run the next task.
+ task_runner->FastForwardBy(base::TimeDelta::FromMilliseconds(1));
+ EXPECT_TRUE(request2->started());
+}
+
+TEST_F(ResourceSchedulerTest, YieldingDisabled) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("", kNetworkSchedulerYielding);
+ InitializeScheduler();
+
+ // We're setting a yield parameter, but no yielding will happen since it's
+ // disabled.
+ scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
+
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ std::unique_ptr<TestRequest> request2(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ EXPECT_TRUE(request->started());
+ EXPECT_TRUE(request2->started());
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldH1) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
+ InitializeScheduler();
+
+ // Use a testing task runner so that we can control time.
+ auto task_runner = base::MakeRefCounted<base::TestMockTimeTaskRunner>();
+ scheduler_->SetTaskRunnerForTesting(task_runner);
+
+ // Yield after each request.
+ scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
+ scheduler_->SetYieldTimeForTesting(base::TimeDelta::FromMilliseconds(42));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("https://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> request2(
+ NewRequest("https://host/low", net::LOWEST));
+
+ EXPECT_TRUE(request->started());
+ EXPECT_FALSE(request2->started());
+
+ // Finish the first task so that the second can start.
+ request = nullptr;
+
+ // Run tasks without advancing time, if there were yielding the next task
+ // wouldn't start.
+ task_runner->RunUntilIdle();
+
+ // The next task started, so there was no yielding.
+ EXPECT_TRUE(request2->started());
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldAltSchemes) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
+ InitializeScheduler();
+
+ // Yield after each request.
+ scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
+ scheduler_->SetYieldTimeForTesting(base::TimeDelta::FromMilliseconds(42));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("yyy://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> request2(
+ NewRequest("zzz://host/low", net::LOWEST));
+
+ EXPECT_TRUE(request->started());
+ EXPECT_TRUE(request2->started());
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerDoesNotYieldSyncRequests) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kNetworkSchedulerYielding, "");
+ InitializeScheduler();
+
+ // The second low-priority request should yield.
+ scheduler_->SetMaxRequestsBeforeYieldingForTesting(1);
+
+ // Use spdy so that we don't throttle.
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ std::unique_ptr<TestRequest> request2(
+ NewRequest("https://spdyhost/low", net::LOWEST)); // yields
+
+ // Add a synchronous request, it shouldn't yield.
+ std::unique_ptr<TestRequest> sync_request(
+ NewSyncRequest("http://spdyhost/low", net::LOWEST));
+
+ EXPECT_TRUE(request->started());
+ EXPECT_FALSE(request2->started());
+ EXPECT_TRUE(sync_request->started()); // The sync request started.
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(request2->started());
+}
+
+TEST_F(ResourceSchedulerTest, OneLowLoadsUntilBodyInsertedExceptSpdy) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("",
+ kPrioritySupportedRequestsDelayable);
+ InitializeScheduler();
+
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low_spdy(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ EXPECT_TRUE(high->started());
+ EXPECT_TRUE(low->started());
+ EXPECT_FALSE(low2->started());
+ EXPECT_TRUE(low_spdy->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low2->started());
+}
+
+TEST_F(ResourceSchedulerTest,
+ OneLowLoadsUntilBodyInsertedEvenSpdyWhenDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kPrioritySupportedRequestsDelayable,
+ "");
+
+ InitializeScheduler();
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low_spdy(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ EXPECT_TRUE(high->started());
+ EXPECT_TRUE(low->started());
+ EXPECT_FALSE(low2->started());
+ EXPECT_FALSE(low_spdy->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low2->started());
+ EXPECT_TRUE(low_spdy->started());
+}
+
+TEST_F(ResourceSchedulerTest, MaxRequestsPerHostForSpdyWhenNotDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("",
+ kPrioritySupportedRequestsDelayable);
+
+ InitializeScheduler();
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+
+ // Add more than max-per-host low-priority requests.
+ std::vector<std::unique_ptr<TestRequest>> requests;
+ for (size_t i = 0; i < kMaxNumDelayableRequestsPerHostPerClient + 1; ++i)
+ requests.push_back(NewRequest("https://spdyhost/low", net::LOWEST));
+
+ // No throttling.
+ for (const auto& request : requests)
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, MaxRequestsPerHostForSpdyWhenDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ kPrioritySupportedRequestsDelayable,
+ kHeadPrioritySupportedRequestsDelayable);
+
+ InitializeScheduler();
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+
+ // Body has been reached.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Add more than max-per-host low-priority requests.
+ std::vector<std::unique_ptr<TestRequest>> requests;
+ for (size_t i = 0; i < kMaxNumDelayableRequestsPerHostPerClient + 1; ++i)
+ requests.push_back(NewRequest("https://spdyhost/low", net::LOWEST));
+
+ // Only kMaxNumDelayableRequestsPerHostPerClient in body.
+ for (size_t i = 0; i < requests.size(); ++i) {
+ if (i < kMaxNumDelayableRequestsPerHostPerClient)
+ EXPECT_TRUE(requests[i]->started());
+ else
+ EXPECT_FALSE(requests[i]->started());
+ }
+}
+
+TEST_F(ResourceSchedulerTest, MaxRequestsPerHostForSpdyWhenHeadDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ kHeadPrioritySupportedRequestsDelayable,
+ kPrioritySupportedRequestsDelayable);
+
+ InitializeScheduler();
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+
+ // Body has been reached.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Add more than max-per-host low-priority requests.
+ std::vector<std::unique_ptr<TestRequest>> requests;
+ for (size_t i = 0; i < kMaxNumDelayableRequestsPerHostPerClient + 1; ++i)
+ requests.push_back(NewRequest("https://spdyhost/low", net::LOWEST));
+
+ // No throttling.
+ for (const auto& request : requests)
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, ThrottlesHeadWhenHeadDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ kHeadPrioritySupportedRequestsDelayable,
+ kPrioritySupportedRequestsDelayable);
+
+ InitializeScheduler();
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+
+ // Add more than max-per-host low-priority requests.
+ std::vector<std::unique_ptr<TestRequest>> requests;
+ for (size_t i = 0; i < kMaxNumDelayableRequestsPerHostPerClient + 1; ++i)
+ requests.push_back(NewRequest("https://spdyhost/low", net::LOWEST));
+
+ // While in head, only one low-priority request is allowed.
+ for (size_t i = 0u; i < requests.size(); ++i) {
+ if (i == 0u)
+ EXPECT_TRUE(requests[i]->started());
+ else
+ EXPECT_FALSE(requests[i]->started());
+ }
+
+ // Body has been reached.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+
+ // No throttling.
+ for (const auto& request : requests)
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, MaxRequestsPerHostForSpdyProxyWhenNotDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("",
+ kPrioritySupportedRequestsDelayable);
+
+ InitializeScheduler();
+
+ // Body has been reached.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Add more than max-per-host low-priority requests.
+ std::vector<std::unique_ptr<TestRequest>> requests;
+ for (size_t i = 0; i < kMaxNumDelayableRequestsPerHostPerClient + 1; ++i)
+ requests.push_back(NewRequest("http://host/low", net::LOWEST));
+
+ // Now the scheduler realizes these requests are for a spdy proxy.
+ scheduler()->OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+
+ // No throttling.
+ for (const auto& request : requests)
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, MaxRequestsPerHostForSpdyProxyWhenDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ kPrioritySupportedRequestsDelayable,
+ kHeadPrioritySupportedRequestsDelayable);
+
+ InitializeScheduler();
+
+ // Body has been reached.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Add more than max-per-host low-priority requests.
+ std::vector<std::unique_ptr<TestRequest>> requests;
+ for (size_t i = 0; i < kMaxNumDelayableRequestsPerHostPerClient + 1; ++i)
+ requests.push_back(NewRequest("http://host/low", net::LOWEST));
+
+ // Now the scheduler realizes these requests are for a spdy proxy.
+ scheduler()->OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+
+ // Only kMaxNumDelayableRequestsPerHostPerClient in body.
+ for (size_t i = 0; i < requests.size(); ++i) {
+ if (i < kMaxNumDelayableRequestsPerHostPerClient)
+ EXPECT_TRUE(requests[i]->started());
+ else
+ EXPECT_FALSE(requests[i]->started());
+ }
+}
+
+TEST_F(ResourceSchedulerTest, MaxRequestsPerHostForSpdyProxyWhenHeadDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ kHeadPrioritySupportedRequestsDelayable,
+ kPrioritySupportedRequestsDelayable);
+
+ InitializeScheduler();
+
+ // Body has been reached.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Add more than max-per-host low-priority requests.
+ std::vector<std::unique_ptr<TestRequest>> requests;
+ for (size_t i = 0; i < kMaxNumDelayableRequestsPerHostPerClient + 1; ++i)
+ requests.push_back(NewRequest("http://host/low", net::LOWEST));
+
+ // Now the scheduler realizes these requests are for a spdy proxy.
+ scheduler()->OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+
+ // No throttling.
+ for (const auto& request : requests)
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, ThrottlesHeadForSpdyProxyWhenHeadDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(
+ kHeadPrioritySupportedRequestsDelayable,
+ kPrioritySupportedRequestsDelayable);
+
+ InitializeScheduler();
+
+ // Add more than max-per-host low-priority requests.
+ std::vector<std::unique_ptr<TestRequest>> requests;
+ for (size_t i = 0; i < kMaxNumDelayableRequestsPerHostPerClient + 1; ++i)
+ requests.push_back(NewRequest("http://host/low", net::LOWEST));
+
+ // Now the scheduler realizes these requests are for a spdy proxy.
+ scheduler()->OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+
+ // While in head, only one low-priority request is allowed.
+ for (size_t i = 0u; i < requests.size(); ++i) {
+ if (i == 0u)
+ EXPECT_TRUE(requests[i]->started());
+ else
+ EXPECT_FALSE(requests[i]->started());
+ }
+
+ // Body has been reached.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+
+ // No throttling.
+ for (const auto& request : requests)
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, SpdyLowBlocksOtherLowUntilBodyInserted) {
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("https", "spdyhost", 443), true);
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low_spdy(
+ NewRequest("https://spdyhost/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_TRUE(high->started());
+ EXPECT_TRUE(low_spdy->started());
+ EXPECT_FALSE(low->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low->started());
+}
+
+TEST_F(ResourceSchedulerTest, NavigationResetsState) {
+ base::HistogramTester histogram_tester;
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+
+ {
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(
+ NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(
+ NewRequest("http://host/low", net::LOWEST));
+ EXPECT_TRUE(high->started());
+ EXPECT_TRUE(low->started());
+ EXPECT_FALSE(low2->started());
+ }
+
+ histogram_tester.ExpectTotalCount("ResourceScheduler.RequestsCount.All", 2);
+ EXPECT_THAT(
+ histogram_tester.GetAllSamples("ResourceScheduler.RequestsCount.All"),
+ testing::ElementsAre(base::Bucket(1, 1), base::Bucket(2, 1)));
+
+ histogram_tester.ExpectTotalCount("ResourceScheduler.RequestsCount.Delayable",
+ 2);
+ histogram_tester.ExpectTotalCount(
+ "ResourceScheduler.RequestsCount.NonDelayable", 2);
+ histogram_tester.ExpectTotalCount(
+ "ResourceScheduler.RequestsCount.TotalLayoutBlocking", 2);
+
+ histogram_tester.ExpectUniqueSample(
+ "ResourceScheduler.PeakDelayableRequestsInFlight.LayoutBlocking", 1, 1);
+ histogram_tester.ExpectUniqueSample(
+ "ResourceScheduler.PeakDelayableRequestsInFlight.NonDelayable", 1, 1);
+}
+
+TEST_F(ResourceSchedulerTest, BackgroundRequestStartsImmediately) {
+ const int route_id = 0; // Indicates a background request.
+ std::unique_ptr<TestRequest> request(
+ NewRequestWithRoute("http://host/1", net::LOWEST, route_id));
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, MoreThanOneHighRequestBlocksDelayableRequests) {
+ // If there are more than kInFlightNonDelayableRequestCountThreshold (=1)
+ // high-priority / non-delayable requests, block all low priority fetches and
+ // allow them through one at a time once the number of high priority requests
+ // drops.
+ std::unique_ptr<TestRequest> high1(
+ NewRequest("http://host/high1", net::HIGHEST));
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high2", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_TRUE(high1->started());
+ EXPECT_TRUE(high2->started());
+ EXPECT_FALSE(low->started());
+ EXPECT_FALSE(low2->started());
+
+ high1.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low->started());
+ EXPECT_FALSE(low2->started());
+}
+
+TEST_F(ResourceSchedulerTest, CancelOtherRequestsWhileResuming) {
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low1(
+ NewRequest("http://host/low1", net::LOWEST));
+
+ std::unique_ptr<net::URLRequest> url_request(
+ NewURLRequest("http://host/low2", net::LOWEST));
+ auto scheduled_request =
+ scheduler()->ScheduleRequest(kChildId, kRouteId, true, url_request.get());
+ std::unique_ptr<CancelingTestRequest> low2(new CancelingTestRequest(
+ std::move(url_request), std::move(scheduled_request), scheduler()));
+ low2->Start();
+
+ std::unique_ptr<TestRequest> low3(
+ NewRequest("http://host/low3", net::LOWEST));
+ low2->set_request_to_cancel(std::move(low3));
+ std::unique_ptr<TestRequest> low4(
+ NewRequest("http://host/low4", net::LOWEST));
+
+ EXPECT_TRUE(high->started());
+ EXPECT_FALSE(low2->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low1->started());
+ EXPECT_TRUE(low2->started());
+ EXPECT_TRUE(low4->started());
+}
+
+TEST_F(ResourceSchedulerTest, LimitedNumberOfDelayableRequestsInFlight) {
+ // The yielding feature will sometimes yield requests before they get a
+ // chance to start, which conflicts this test. So disable the feature.
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("", kNetworkSchedulerYielding);
+
+ // We only load low priority resources if there's a body.
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Throw in one high priority request to make sure that's not a factor.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should match the .cc.
+ const int kMaxNumDelayableRequestsPerHost = 6;
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+ // Queue up to the per-host limit (we subtract the current high-pri request).
+ for (int i = 0; i < kMaxNumDelayableRequestsPerHost - 1; ++i) {
+ string url = "http://host/low" + base::IntToString(i);
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_TRUE(lows_singlehost[i]->started());
+ }
+
+ std::unique_ptr<TestRequest> second_last_singlehost(
+ NewRequest("http://host/last", net::LOWEST));
+ std::unique_ptr<TestRequest> last_singlehost(
+ NewRequest("http://host/s_last", net::LOWEST));
+
+ EXPECT_FALSE(second_last_singlehost->started());
+
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(second_last_singlehost->started());
+ EXPECT_FALSE(last_singlehost->started());
+
+ lows_singlehost.erase(lows_singlehost.begin());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(last_singlehost->started());
+
+ // Queue more requests from different hosts until we reach the total limit.
+ int expected_slots_left = kDefaultMaxNumDelayableRequestsPerClient -
+ kMaxNumDelayableRequestsPerHost;
+ EXPECT_GT(expected_slots_left, 0);
+ std::vector<std::unique_ptr<TestRequest>> lows_different_host;
+ base::RunLoop().RunUntilIdle();
+ for (int i = 0; i < expected_slots_left; ++i) {
+ string url = "http://host" + base::IntToString(i) + "/low";
+ lows_different_host.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_TRUE(lows_different_host[i]->started());
+ }
+
+ std::unique_ptr<TestRequest> last_different_host(
+ NewRequest("http://host_new/last", net::LOWEST));
+ EXPECT_FALSE(last_different_host->started());
+}
+
+TEST_F(ResourceSchedulerTest, RaisePriorityAndStart) {
+ // Dummies to enforce scheduling.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/req", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
+ EXPECT_FALSE(request->started());
+
+ ChangeRequestPriority(request.get(), net::HIGHEST);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, RaisePriorityInQueue) {
+ // Dummies to enforce scheduling.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::IDLE));
+ std::unique_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
+ EXPECT_FALSE(request->started());
+ EXPECT_FALSE(idle->started());
+
+ ChangeRequestPriority(request.get(), net::LOWEST);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request->started());
+ EXPECT_FALSE(idle->started());
+
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should match the .cc.
+ std::vector<std::unique_ptr<TestRequest>> lows;
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient - 1; ++i) {
+ string url = "http://host/low" + base::IntToString(i);
+ lows.push_back(NewRequest(url.c_str(), net::LOWEST));
+ }
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_TRUE(request->started());
+ EXPECT_FALSE(idle->started());
+}
+
+TEST_F(ResourceSchedulerTest, LowerPriority) {
+ // Dummies to enforce scheduling.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
+ std::unique_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
+ EXPECT_FALSE(request->started());
+ EXPECT_FALSE(idle->started());
+
+ ChangeRequestPriority(request.get(), net::IDLE);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request->started());
+ EXPECT_FALSE(idle->started());
+
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should match the .cc.
+ // 2 fewer filler requests: 1 for the "low" dummy at the start, and 1 for the
+ // one at the end, which will be tested.
+ const int kNumFillerRequests = kDefaultMaxNumDelayableRequestsPerClient - 2;
+ std::vector<std::unique_ptr<TestRequest>> lows;
+ for (int i = 0; i < kNumFillerRequests; ++i) {
+ string url = "http://host" + base::IntToString(i) + "/low";
+ lows.push_back(NewRequest(url.c_str(), net::LOWEST));
+ }
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+
+ EXPECT_FALSE(request->started());
+ EXPECT_TRUE(idle->started());
+}
+
+TEST_F(ResourceSchedulerTest, ReprioritizedRequestGoesToBackOfQueue) {
+ // Dummies to enforce scheduling.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
+ std::unique_ptr<TestRequest> idle(NewRequest("http://host/idle", net::IDLE));
+ EXPECT_FALSE(request->started());
+ EXPECT_FALSE(idle->started());
+
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should match the .cc.
+ std::vector<std::unique_ptr<TestRequest>> lows;
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient; ++i) {
+ string url = "http://host/low" + base::IntToString(i);
+ lows.push_back(NewRequest(url.c_str(), net::LOWEST));
+ }
+
+ ChangeRequestPriority(request.get(), net::IDLE);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request->started());
+ EXPECT_FALSE(idle->started());
+
+ ChangeRequestPriority(request.get(), net::LOWEST);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request->started());
+ EXPECT_FALSE(idle->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request->started());
+ EXPECT_FALSE(idle->started());
+}
+
+TEST_F(ResourceSchedulerTest, HigherIntraPriorityGoesToFrontOfQueue) {
+ // Dummies to enforce scheduling.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should match the .cc.
+ std::vector<std::unique_ptr<TestRequest>> lows;
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient; ++i) {
+ string url = "http://host/low" + base::IntToString(i);
+ lows.push_back(NewRequest(url.c_str(), net::IDLE));
+ }
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::IDLE));
+ EXPECT_FALSE(request->started());
+
+ ChangeRequestPriority(request.get(), net::IDLE, 1);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request->started());
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ high.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, NonHTTPSchedulesImmediately) {
+ // Dummies to enforce scheduling.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("chrome-extension://req", net::LOWEST));
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, SpdyProxySchedulesImmediately) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("",
+ kPrioritySupportedRequestsDelayable);
+ InitializeScheduler();
+
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::IDLE));
+ EXPECT_FALSE(request->started());
+
+ scheduler()->OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(request->started());
+
+ std::unique_ptr<TestRequest> after(
+ NewRequest("http://host/after", net::IDLE));
+ EXPECT_TRUE(after->started());
+}
+
+TEST_F(ResourceSchedulerTest, SpdyProxyDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kPrioritySupportedRequestsDelayable,
+ "");
+ InitializeScheduler();
+
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/low", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::IDLE));
+ EXPECT_FALSE(request->started());
+
+ scheduler()->OnReceivedSpdyProxiedHttpResponse(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_FALSE(request->started());
+
+ std::unique_ptr<TestRequest> after(
+ NewRequest("http://host/after", net::IDLE));
+ EXPECT_FALSE(after->started());
+}
+
+TEST_F(ResourceSchedulerTest, NewSpdyHostInDelayableRequests) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine("",
+ kPrioritySupportedRequestsDelayable);
+ InitializeScheduler();
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should match the .cc.
+
+ std::unique_ptr<TestRequest> low1_spdy(
+ NewRequest("http://spdyhost1:8080/low", net::LOWEST));
+ // Cancel a request after we learn the server supports SPDY.
+ std::vector<std::unique_ptr<TestRequest>> lows;
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient - 1; ++i) {
+ string url = "http://host" + base::IntToString(i) + "/low";
+ lows.push_back(NewRequest(url.c_str(), net::LOWEST));
+ }
+ std::unique_ptr<TestRequest> low1(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_FALSE(low1->started());
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("http", "spdyhost1", 8080), true);
+ low1_spdy.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low1->started());
+
+ low1.reset();
+ base::RunLoop().RunUntilIdle();
+ std::unique_ptr<TestRequest> low2_spdy(
+ NewRequest("http://spdyhost2:8080/low", net::IDLE));
+ // Reprioritize a request after we learn the server supports SPDY.
+ EXPECT_TRUE(low2_spdy->started());
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("http", "spdyhost2", 8080), true);
+ ChangeRequestPriority(low2_spdy.get(), net::LOWEST);
+ base::RunLoop().RunUntilIdle();
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_TRUE(low2->started());
+}
+
+TEST_F(ResourceSchedulerTest, NewDelayableSpdyHostInDelayableRequests) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ scoped_feature_list.InitFromCommandLine(kPrioritySupportedRequestsDelayable,
+ "");
+ InitializeScheduler();
+
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should match the .cc.
+
+ std::unique_ptr<TestRequest> low1_spdy(
+ NewRequest("http://spdyhost1:8080/low", net::LOWEST));
+ // Cancel a request after we learn the server supports SPDY.
+ std::vector<std::unique_ptr<TestRequest>> lows;
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient - 1; ++i) {
+ string url = "http://host" + base::IntToString(i) + "/low";
+ lows.push_back(NewRequest(url.c_str(), net::LOWEST));
+ }
+ std::unique_ptr<TestRequest> low1(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_FALSE(low1->started());
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("http", "spdyhost1", 8080), true);
+ low1_spdy.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(low1->started());
+
+ low1.reset();
+ base::RunLoop().RunUntilIdle();
+ std::unique_ptr<TestRequest> low2_spdy(
+ NewRequest("http://spdyhost2:8080/low", net::IDLE));
+ // Reprioritize a request after we learn the server supports SPDY.
+ EXPECT_TRUE(low2_spdy->started());
+ http_server_properties_.SetSupportsSpdy(
+ url::SchemeHostPort("http", "spdyhost2", 8080), true);
+ ChangeRequestPriority(low2_spdy.get(), net::LOWEST);
+ base::RunLoop().RunUntilIdle();
+ std::unique_ptr<TestRequest> low2(NewRequest("http://host/low", net::LOWEST));
+ EXPECT_FALSE(low2->started());
+}
+
+// Async revalidations which are not started when the tab is closed must be
+// started at some point, or they will hang around forever and prevent other
+// async revalidations to the same URL from being issued.
+TEST_F(ResourceSchedulerTest, RequestStartedAfterClientDeleted) {
+ scheduler_->OnClientCreated(kChildId2, kRouteId2,
+ &network_quality_estimator_);
+ std::unique_ptr<TestRequest> high(NewRequestWithChildAndRoute(
+ "http://host/high", net::HIGHEST, kChildId2, kRouteId2));
+ std::unique_ptr<TestRequest> lowest1(NewRequestWithChildAndRoute(
+ "http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
+ std::unique_ptr<TestRequest> lowest2(NewRequestWithChildAndRoute(
+ "http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
+ EXPECT_FALSE(lowest2->started());
+
+ scheduler_->OnClientDeleted(kChildId2, kRouteId2);
+ high.reset();
+ lowest1.reset();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(lowest2->started());
+}
+
+// The ResourceScheduler::Client destructor calls
+// LoadAnyStartablePendingRequests(), which may start some pending requests.
+// This test is to verify that requests will be started at some point
+// even if they were not started by the destructor.
+TEST_F(ResourceSchedulerTest, RequestStartedAfterClientDeletedManyDelayable) {
+ scheduler_->OnClientCreated(kChildId2, kRouteId2,
+ &network_quality_estimator_);
+ std::unique_ptr<TestRequest> high(NewRequestWithChildAndRoute(
+ "http://host/high", net::HIGHEST, kChildId2, kRouteId2));
+ const int kDefaultMaxNumDelayableRequestsPerClient = 10;
+ std::vector<std::unique_ptr<TestRequest>> delayable_requests;
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient + 1; ++i) {
+ delayable_requests.push_back(NewRequestWithChildAndRoute(
+ "http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
+ }
+ std::unique_ptr<TestRequest> lowest(NewRequestWithChildAndRoute(
+ "http://host/lowest", net::LOWEST, kChildId2, kRouteId2));
+ EXPECT_FALSE(lowest->started());
+
+ scheduler_->OnClientDeleted(kChildId2, kRouteId2);
+ high.reset();
+ delayable_requests.clear();
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(lowest->started());
+}
+
+// Tests that the maximum number of delayable requests is overridden when the
+// experiment is enabled.
+TEST_F(ResourceSchedulerTest, RequestLimitOverrideEnabled) {
+ RequestLimitOverrideConfigTestHelper(true);
+}
+
+// Tests that the maximum number of delayable requests is not overridden when
+// the experiment is disabled.
+TEST_F(ResourceSchedulerTest, RequestLimitOverrideDisabled) {
+ RequestLimitOverrideConfigTestHelper(false);
+}
+
+// Test that the limit is not overridden when the effective connection type is
+// not equal to any of the values provided in the experiment configuration.
+TEST_F(ResourceSchedulerTest, RequestLimitOverrideOutsideECTRange) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ InitializeThrottleDelayableExperiment(&scoped_feature_list, true, 0.0);
+ InitializeScheduler();
+ for (net::EffectiveConnectionType ect :
+ {net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN,
+ net::EFFECTIVE_CONNECTION_TYPE_OFFLINE,
+ net::EFFECTIVE_CONNECTION_TYPE_4G}) {
+ // Set the effective connection type to a value for which the experiment
+ // should not be run.
+ network_quality_estimator_.set_effective_connection_type(ect);
+
+ // The limit will matter only once the page has a body, since delayable
+ // requests are not loaded before that.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ // Should be in sync with resource_scheduler.cc.
+ const int kDefaultMaxNumDelayableRequestsPerClient = 10;
+
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+ // Queue up to the maximum limit. Use different host names to prevent the
+ // per host limit from kicking in.
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low";
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_TRUE(lows_singlehost[i]->started());
+ }
+
+ std::unique_ptr<TestRequest> last_singlehost(
+ NewRequest("http://host/last", net::LOWEST));
+
+ // Last should not start because the maximum requests that can be in-flight
+ // have already started.
+ EXPECT_FALSE(last_singlehost->started());
+ }
+}
+
+// Test that a change in network conditions midway during loading does not
+// change the behavior of the resource scheduler.
+TEST_F(ResourceSchedulerTest, RequestLimitOverrideFixedForPageLoad) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ InitializeThrottleDelayableExperiment(&scoped_feature_list, true, 0.0);
+ // ECT value is in range for which the limit is overridden to 2.
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ InitializeScheduler();
+
+ // The limit will matter only once the page has a body, since delayable
+ // requests are not loaded before that.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ // Should be based on the value set by
+ // |InitializeMaxDelayableRequestsExperiment| for the given range.
+ const int kOverriddenNumRequests = 2;
+
+ std::vector<std::unique_ptr<TestRequest>> lows_singlehost;
+ // Queue up to the overridden limit.
+ for (int i = 0; i < kOverriddenNumRequests; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low";
+ lows_singlehost.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_TRUE(lows_singlehost[i]->started());
+ }
+
+ std::unique_ptr<TestRequest> second_last_singlehost(
+ NewRequest("http://host/slast", net::LOWEST));
+
+ // This new request should not start because the limit has been reached.
+ EXPECT_FALSE(second_last_singlehost->started());
+ lows_singlehost.erase(lows_singlehost.begin());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(second_last_singlehost->started());
+
+ // Change the ECT to go outside the experiment buckets and change the network
+ // type to 4G. This should not affect the limit calculated at the beginning of
+ // the page load.
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_4G);
+ base::RunLoop().RunUntilIdle();
+
+ std::unique_ptr<TestRequest> last_singlehost(
+ NewRequest("http://host/last", net::LOWEST));
+
+ // Last should not start because the limit should not have changed.
+ EXPECT_FALSE(last_singlehost->started());
+
+ // The limit should change when there is a new page navigation.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ base::RunLoop().RunUntilIdle();
+ EXPECT_TRUE(last_singlehost->started());
+}
+
+// Test that when the network quality changes such that the new limit is lower,
+// and an |DeprecatedOnNavigate| event occurs, the new delayable requests don't
+// start until the number of requests in flight have gone below the new limit.
+TEST_F(ResourceSchedulerTest, RequestLimitReducedAcrossPageLoads) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ InitializeThrottleDelayableExperiment(&scoped_feature_list, true, 0.0);
+ // ECT value is in range for which the limit is overridden to 4.
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_3G);
+ InitializeScheduler();
+
+ // The limit will matter only once the page has a body, since delayable
+ // requests are not loaded before that.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Throw in one high priority request to ensure that it does not matter once
+ // a body exists.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ // The number of delayable requests allowed for the first page load.
+ const int kNumDelayableHigh = 4;
+ // The number of delayable requests allowed for the second page load.
+ const int kNumDelayableLow = 2;
+
+ std::vector<std::unique_ptr<TestRequest>> delayable_first_page;
+ // Queue up to the overridden limit.
+ for (int i = 0; i < kNumDelayableHigh; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low1";
+ delayable_first_page.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_TRUE(delayable_first_page[i]->started());
+ }
+ // Change the network quality so that the ECT value is in range for which the
+ // limit is overridden to 2. The effective connection type is set to
+ // Slow-2G.
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+ // Trigger a navigation event which will recompute limits. Also insert a body,
+ // because the limit matters only after the body exists.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+
+ // Ensure that high priority requests still start.
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high2", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+
+ // Generate requests from second page. None of them should start because the
+ // new limit is |kNumDelayableLow| and there are already |kNumDelayableHigh|
+ // requests in flight.
+ std::vector<std::unique_ptr<TestRequest>> delayable_second_page;
+ for (int i = 0; i < kNumDelayableLow; ++i) {
+ // Keep unique hostnames to prevent the per host limit from kicking in.
+ std::string url = "http://host" + base::IntToString(i) + "/low2";
+ delayable_second_page.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_FALSE(delayable_second_page[i]->started());
+ }
+
+ // Finish 2 requests from first page load.
+ for (int i = 0; i < kNumDelayableHigh - kNumDelayableLow; ++i) {
+ delayable_first_page.pop_back();
+ }
+ base::RunLoop().RunUntilIdle();
+
+ // Nothing should start because there are already |kNumDelayableLow| requests
+ // in flight.
+ for (int i = 0; i < kNumDelayableLow; ++i) {
+ EXPECT_FALSE(delayable_second_page[i]->started());
+ }
+
+ // Remove all requests from the first page.
+ delayable_first_page.clear();
+ base::RunLoop().RunUntilIdle();
+
+ // Check that the requests from page 2 have started, since now there are 2
+ // empty slots.
+ for (int i = 0; i < kNumDelayableLow; ++i) {
+ EXPECT_TRUE(delayable_second_page[i]->started());
+ }
+
+ // No new delayable request should start since there are already
+ // |kNumDelayableLow| requests in flight.
+ std::string url =
+ "http://host" + base::IntToString(kNumDelayableLow) + "/low3";
+ delayable_second_page.push_back(NewRequest(url.c_str(), net::LOWEST));
+ EXPECT_FALSE(delayable_second_page.back()->started());
+}
+
+// Test that a configuration without any ECT ranges is read correctly. In this
+// case, the resource scheduler will fall back to the default limit.
+TEST_F(ResourceSchedulerTest, ReadValidConfigTest0) {
+ ReadConfigTestHelper(0);
+}
+
+// Test that a configuration with 1 range is read correctly.
+TEST_F(ResourceSchedulerTest, ReadValidConfigTest1) {
+ ReadConfigTestHelper(1);
+}
+
+// Test that a configuration with 2 ranges is read correctly.
+TEST_F(ResourceSchedulerTest, ReadValidConfigTest2) {
+ ReadConfigTestHelper(2);
+}
+
+// Test that a configuration with 3 ranges is read correctly.
+TEST_F(ResourceSchedulerTest, ReadValidConfigTest3) {
+ ReadConfigTestHelper(3);
+}
+
+// Test that a configuration with bad strings does not break the parser, and
+// the parser stops reading the configuration after it encounters the first
+// missing index.
+TEST_F(ResourceSchedulerTest, ReadInvalidConfigTest) {
+ base::FieldTrialParamAssociator::GetInstance()->ClearAllParamsForTesting();
+ const char kTrialName[] = "TrialName";
+ const char kGroupName[] = "GroupName";
+ const char kThrottleDelayable[] = "ThrottleDelayable";
+
+ base::test::ScopedFeatureList scoped_feature_list;
+ std::map<std::string, std::string> params;
+ // Skip configuration parameters for index 2 to test that the parser stops
+ // when it cannot find the parameters for an index.
+ for (int range_index : {1, 3, 4}) {
+ std::string index_str = base::IntToString(range_index);
+ params["EffectiveConnectionType" + index_str] = "Slow-2G";
+ params["MaxDelayableRequests" + index_str] = index_str + "0";
+ params["NonDelayableWeight" + index_str] = "0";
+ }
+ // Add some bad configuration strigs to ensure that the parser does not break.
+ params["BadConfigParam1"] = "100";
+ params["BadConfigParam2"] = "100";
+
+ base::AssociateFieldTrialParams(kTrialName, kGroupName, params);
+ base::FieldTrial* field_trial =
+ base::FieldTrialList::CreateFieldTrial(kTrialName, kGroupName);
+ std::unique_ptr<base::FeatureList> feature_list(
+ std::make_unique<base::FeatureList>());
+ feature_list->RegisterFieldTrialOverride(
+ kThrottleDelayable, base::FeatureList::OVERRIDE_ENABLE_FEATURE,
+ field_trial);
+ scoped_feature_list.InitWithFeatureList(std::move(feature_list));
+
+ ResourceScheduler::ParamsForNetworkQualityContainer
+ params_network_quality_container =
+ ResourceScheduler::GetParamsForNetworkQualityContainerForTests();
+
+ // Only the first configuration parameter must be read because a match was not
+ // found for index 2. The configuration parameters with index 3 and 4 must be
+ // ignored, even though they are valid configuration parameters.
+ EXPECT_EQ(1u, params_network_quality_container.size());
+ EXPECT_EQ(net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
+ params_network_quality_container[0].effective_connection_type);
+ EXPECT_EQ(10u, params_network_quality_container[0].max_delayable_requests);
+ EXPECT_EQ(0.0, params_network_quality_container[0].non_delayable_weight);
+}
+
+// Test that the default limit is used for delayable requests when the
+// experiment is enabled, but the current effective connection type is higher
+// than the maximum effective connection type set in the experiment
+// configuration.
+TEST_F(ResourceSchedulerTest, NonDelayableThrottlesDelayableOutsideECT) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ const double kNonDelayableWeight = 2.0;
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should be in sync with cc.
+ // Initialize the experiment with |kNonDelayableWeight| as the weight of
+ // non-delayable requests.
+ InitializeThrottleDelayableExperiment(&scoped_feature_list, false,
+ kNonDelayableWeight);
+ // Experiment should not run when the effective connection type is faster
+ // than 2G.
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_3G);
+ // Limit will only trigger after the page has a body.
+
+ InitializeScheduler();
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ // Insert one non-delayable request. This should not affect the number of
+ // delayable requests started.
+ std::unique_ptr<TestRequest> medium(
+ NewRequest("http://host/medium", net::MEDIUM));
+ ASSERT_TRUE(medium->started());
+ // Start |kDefaultMaxNumDelayableRequestsPerClient| delayable requests and
+ // verify that they all started.
+ std::vector<std::unique_ptr<TestRequest>> delayable_requests;
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient; ++i) {
+ delayable_requests.push_back(NewRequest(
+ base::StringPrintf("http://host%d/low", i).c_str(), net::LOWEST));
+ EXPECT_TRUE(delayable_requests.back()->started());
+ }
+}
+
+// Test that delayable requests are throttled by the right amount as the number
+// of non-delayable requests in-flight change.
+TEST_F(ResourceSchedulerTest, NonDelayableThrottlesDelayableVaryNonDelayable) {
+ base::test::ScopedFeatureList scoped_feature_list;
+ const double kNonDelayableWeight = 2.0;
+ const int kDefaultMaxNumDelayableRequestsPerClient =
+ 10; // Should be in sync with cc.
+ // Initialize the experiment with |kNonDelayableWeight| as the weight of
+ // non-delayable requests.
+ InitializeThrottleDelayableExperiment(&scoped_feature_list, false,
+ kNonDelayableWeight);
+ network_quality_estimator_.set_effective_connection_type(
+ net::EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
+
+ InitializeScheduler();
+ // Limit will only trigger after the page has a body.
+ scheduler()->DeprecatedOnNavigate(kChildId, kRouteId);
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ for (int num_non_delayable = 0; num_non_delayable < 10; ++num_non_delayable) {
+ base::RunLoop().RunUntilIdle();
+ // Start the non-delayable requests.
+ std::vector<std::unique_ptr<TestRequest>> non_delayable_requests;
+ for (int i = 0; i < num_non_delayable; ++i) {
+ non_delayable_requests.push_back(NewRequest(
+ base::StringPrintf("http://host%d/medium", i).c_str(), net::MEDIUM));
+ ASSERT_TRUE(non_delayable_requests.back()->started());
+ }
+ // Start |kDefaultMaxNumDelayableRequestsPerClient| - |num_non_delayable| *
+ // |kNonDelayableWeight| delayable requests. They should all start.
+ std::vector<std::unique_ptr<TestRequest>> delayable_requests;
+ for (int i = 0; i < kDefaultMaxNumDelayableRequestsPerClient -
+ num_non_delayable * kNonDelayableWeight;
+ ++i) {
+ delayable_requests.push_back(NewRequest(
+ base::StringPrintf("http://host%d/low", i).c_str(), net::LOWEST));
+ EXPECT_TRUE(delayable_requests.back()->started());
+ }
+ // The next delayable request should not start.
+ std::unique_ptr<TestRequest> last_low(
+ NewRequest("http://lasthost/low", net::LOWEST));
+ EXPECT_FALSE(last_low->started());
+ }
+}
+
+// Test that the default limit is used for delayable requests in the presence of
+// non-delayable requests when the non-delayable request weight is zero.
+TEST_F(ResourceSchedulerTest, NonDelayableThrottlesDelayableWeight0) {
+ NonDelayableThrottlesDelayableHelper(0.0);
+}
+
+// Test that each non-delayable request in-flight results in the reduction of
+// one in the limit of delayable requests in-flight when the non-delayable
+// request weight is 1.
+TEST_F(ResourceSchedulerTest, NonDelayableThrottlesDelayableWeight1) {
+ NonDelayableThrottlesDelayableHelper(1.0);
+}
+
+// Test that each non-delayable request in-flight results in the reduction of
+// three in the limit of delayable requests in-flight when the non-delayable
+// request weight is 3.
+TEST_F(ResourceSchedulerTest, NonDelayableThrottlesDelayableWeight3) {
+ NonDelayableThrottlesDelayableHelper(3.0);
+}
+
+// Test that UMA counts are recorded for the number of delayable requests
+// in-flight when a non-delayable request starts.
+TEST_F(ResourceSchedulerTest, NumDelayableAtStartOfNonDelayableUMA) {
+ std::unique_ptr<base::HistogramTester> histogram_tester(
+ new base::HistogramTester);
+ scheduler()->DeprecatedOnWillInsertBody(kChildId, kRouteId);
+ // Check that 0 is recorded when a non-delayable request starts and there are
+ // no delayable requests in-flight.
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ EXPECT_TRUE(high->started());
+ histogram_tester->ExpectUniqueSample(
+ "ResourceScheduler.NumDelayableRequestsInFlightAtStart.NonDelayable", 0,
+ 1);
+ histogram_tester.reset(new base::HistogramTester);
+ // Check that nothing is recorded when delayable request is started in the
+ // presence of a non-delayable request.
+ std::unique_ptr<TestRequest> low1(
+ NewRequest("http://host/low1", net::LOWEST));
+ EXPECT_TRUE(low1->started());
+ histogram_tester->ExpectTotalCount(
+ "ResourceScheduler.NumDelayableRequestsInFlightAtStart.NonDelayable", 0);
+ // Check that nothing is recorded when a delayable request is started in the
+ // presence of another delayable request.
+ std::unique_ptr<TestRequest> low2(
+ NewRequest("http://host/low2", net::LOWEST));
+ histogram_tester->ExpectTotalCount(
+ "ResourceScheduler.NumDelayableRequestsInFlightAtStart.NonDelayable", 0);
+ // Check that UMA is recorded when a non-delayable startes in the presence of
+ // delayable requests and that the correct value is recorded.
+ std::unique_ptr<TestRequest> high2(
+ NewRequest("http://host/high2", net::HIGHEST));
+ histogram_tester->ExpectUniqueSample(
+ "ResourceScheduler.NumDelayableRequestsInFlightAtStart.NonDelayable", 2,
+ 1);
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerEnabled) {
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/req", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
+
+ EXPECT_FALSE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, SchedulerDisabled) {
+ InitializeScheduler(false);
+
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/req", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
+
+ // Normally |request| wouldn't start immediately due to the |high| priority
+ // request, but when the scheduler is disabled it starts immediately.
+ EXPECT_TRUE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, MultipleInstances_1) {
+ // In some circumstances there may exist multiple instances.
+ ResourceScheduler another_scheduler(false);
+
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/req", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(
+ NewRequest("http://host/req", net::LOWEST));
+
+ // Though |another_scheduler| is disabled, this request should be throttled
+ // as it's handled by |scheduler_| which is active.
+ EXPECT_FALSE(request->started());
+}
+
+TEST_F(ResourceSchedulerTest, MultipleInstances_2) {
+ ResourceScheduler another_scheduler(true);
+ another_scheduler.OnClientCreated(kChildId, kRouteId,
+ &network_quality_estimator_);
+
+ std::unique_ptr<TestRequest> high(
+ NewRequest("http://host/high", net::HIGHEST));
+ std::unique_ptr<TestRequest> low(NewRequest("http://host/req", net::LOWEST));
+
+ std::unique_ptr<TestRequest> request(NewRequestWithChildAndRoute(
+ "http://host/req", net::LOWEST, kChildId, kRouteId));
+
+ EXPECT_FALSE(request->started());
+
+ {
+ std::unique_ptr<net::URLRequest> url_request(NewURLRequestWithChildAndRoute(
+ "http://host/another", net::LOWEST, kChildId, kRouteId));
+ auto scheduled_request = another_scheduler.ScheduleRequest(
+ kChildId, kRouteId, true, url_request.get());
+ auto another_request = std::make_unique<TestRequest>(
+ std::move(url_request), std::move(scheduled_request),
+ &another_scheduler);
+ another_request->Start();
+
+ // This should not be throttled as it's handled by |another_scheduler|.
+ EXPECT_TRUE(another_request->started());
+ }
+
+ another_scheduler.OnClientDeleted(kChildId, kRouteId);
+}
+
+} // unnamed namespace
+
+} // namespace network
diff --git a/chromium/services/network/restricted_cookie_manager.cc b/chromium/services/network/restricted_cookie_manager.cc
new file mode 100644
index 00000000000..cd8db58b901
--- /dev/null
+++ b/chromium/services/network/restricted_cookie_manager.cc
@@ -0,0 +1,131 @@
+// 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 "services/network/restricted_cookie_manager.h"
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/string_util.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/message.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_options.h"
+#include "net/cookies/cookie_store.h"
+
+namespace network {
+
+RestrictedCookieManager::RestrictedCookieManager(net::CookieStore* cookie_store,
+ int render_process_id,
+ int render_frame_id)
+ : cookie_store_(cookie_store),
+ render_process_id_(render_process_id),
+ render_frame_id_(render_frame_id),
+ weak_ptr_factory_(this) {}
+
+RestrictedCookieManager::~RestrictedCookieManager() = default;
+
+void RestrictedCookieManager::GetAllForUrl(
+ const GURL& url,
+ const GURL& site_for_cookies,
+ mojom::CookieManagerGetOptionsPtr options,
+ GetAllForUrlCallback callback) {
+ // TODO(pwnall): Replicate the call to
+ // ChildProcessSecurityPolicy::CanAccessDataForOrigin() in
+ // RenderFrameMessageFilter::GetCookies.
+
+ net::CookieOptions net_options;
+ if (net::registry_controlled_domains::SameDomainOrHost(
+ url, site_for_cookies,
+ net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)) {
+ // TODO(mkwst): This check ought to further distinguish between frames
+ // initiated in a strict or lax same-site context.
+ net_options.set_same_site_cookie_mode(
+ net::CookieOptions::SameSiteCookieMode::INCLUDE_STRICT_AND_LAX);
+ } else {
+ net_options.set_same_site_cookie_mode(
+ net::CookieOptions::SameSiteCookieMode::DO_NOT_INCLUDE);
+ }
+
+ cookie_store_->GetCookieListWithOptionsAsync(
+ url, net_options,
+ base::BindOnce(&RestrictedCookieManager::CookieListToGetAllForUrlCallback,
+ weak_ptr_factory_.GetWeakPtr(), url, site_for_cookies,
+ std::move(options), std::move(callback)));
+}
+
+void RestrictedCookieManager::CookieListToGetAllForUrlCallback(
+ const GURL& url,
+ const GURL& site_for_cookies,
+ mojom::CookieManagerGetOptionsPtr options,
+ GetAllForUrlCallback callback,
+ const net::CookieList& cookie_list) {
+ // TODO(pwnall): Replicate the security checks in
+ // RenderFrameMessageFilter::CheckPolicyForCookies
+
+ // Avoid unused member warnings until these are used for security checks.
+ (void)(render_frame_id_);
+ (void)(render_process_id_);
+
+ std::vector<net::CanonicalCookie> result;
+ result.reserve(cookie_list.size());
+ mojom::CookieMatchType match_type = options->match_type;
+ const std::string& match_name = options->name;
+ for (size_t i = 0; i < cookie_list.size(); ++i) {
+ const net::CanonicalCookie& cookie = cookie_list[i];
+ const std::string& cookie_name = cookie.Name();
+
+ if (match_type == mojom::CookieMatchType::EQUALS) {
+ if (cookie_name != match_name)
+ continue;
+ } else if (match_type == mojom::CookieMatchType::STARTS_WITH) {
+ if (!base::StartsWith(cookie_name, match_name,
+ base::CompareCase::SENSITIVE)) {
+ continue;
+ }
+ } else {
+ NOTREACHED();
+ }
+ result.emplace_back(cookie);
+ }
+ std::move(callback).Run(std::move(result));
+}
+
+void RestrictedCookieManager::SetCanonicalCookie(
+ const net::CanonicalCookie& cookie,
+ const GURL& url,
+ const GURL& site_for_cookies,
+ SetCanonicalCookieCallback callback) {
+ // TODO(pwnall): Replicate the call to
+ // ChildProcessSecurityPolicy::CanAccessDataForOrigin() in
+ // RenderFrameMessageFilter::SetCookie.
+
+ // TODO(pwnall): Validate the CanonicalCookie fields.
+ // TODO(pwnall): Replicate the AllowSetCookie check in
+ // RenderFrameMessageFilter::SetCookie.
+ base::Time now = base::Time::NowFromSystemTime();
+ // TODO(pwnall): Reason about whether it makes sense to allow a renderer to
+ // set these fields.
+ net::CookieSameSite cookie_same_site_mode = net::CookieSameSite::STRICT_MODE;
+ net::CookiePriority cookie_priority = net::COOKIE_PRIORITY_DEFAULT;
+ auto sanitized_cookie = std::make_unique<net::CanonicalCookie>(
+ cookie.Name(), cookie.Value(), cookie.Domain(), cookie.Path(), now,
+ cookie.ExpiryDate(), now, cookie.IsSecure(), cookie.IsHttpOnly(),
+ cookie_same_site_mode, cookie_priority);
+
+ // TODO(pwnall): secure_source should depend on url, and might depend on the
+ // renderer.
+ bool secure_source = true;
+ bool modify_http_only = false;
+ cookie_store_->SetCanonicalCookieAsync(std::move(sanitized_cookie),
+ secure_source, modify_http_only,
+ std::move(callback));
+}
+
+} // namespace network
diff --git a/chromium/services/network/restricted_cookie_manager.h b/chromium/services/network/restricted_cookie_manager.h
new file mode 100644
index 00000000000..026605038f0
--- /dev/null
+++ b/chromium/services/network/restricted_cookie_manager.h
@@ -0,0 +1,73 @@
+// 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 SERVICES_NETWORK_RESTRICTED_COOKIE_MANAGER_H_
+#define SERVICES_NETWORK_RESTRICTED_COOKIE_MANAGER_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "net/cookies/canonical_cookie.h"
+#include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
+#include "url/gurl.h"
+
+namespace net {
+class CookieStore;
+} // namespace net
+
+namespace network {
+
+// RestrictedCookieManager implementation.
+//
+// Instances of this class must be created and used on the I/O thread. Instances
+// are created by CreateMojoService() and are bound to the lifetimes of the
+// mojo connections that they serve, via mojo::StrongBinding.
+class COMPONENT_EXPORT(NETWORK_SERVICE) RestrictedCookieManager
+ : public mojom::RestrictedCookieManager {
+ public:
+ RestrictedCookieManager(net::CookieStore* cookie_store,
+ int render_process_id,
+ int render_frame_id);
+ ~RestrictedCookieManager() override;
+
+ // Implements CookieStore.getAll() in the Async Cookies API.
+ //
+ // This method is also used as the backend for CookieStore.get() and
+ // CookieStore.has().
+ void GetAllForUrl(const GURL& url,
+ const GURL& site_for_cookies,
+ mojom::CookieManagerGetOptionsPtr options,
+ GetAllForUrlCallback callback) override;
+
+ void SetCanonicalCookie(const net::CanonicalCookie& cookie,
+ const GURL& url,
+ const GURL& site_for_cookies,
+ SetCanonicalCookieCallback callback) override;
+
+ private:
+ // Feeds a net::CookieList to a GetAllForUrl() callback.
+ void CookieListToGetAllForUrlCallback(
+ const GURL& url,
+ const GURL& site_for_cookies,
+ mojom::CookieManagerGetOptionsPtr options,
+ GetAllForUrlCallback callback,
+ const net::CookieList& cookie_list);
+
+ net::CookieStore* cookie_store_;
+ const int render_process_id_;
+ const int render_frame_id_;
+
+ base::WeakPtrFactory<RestrictedCookieManager> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(RestrictedCookieManager);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_RESTRICTED_COOKIE_MANAGER_H_
diff --git a/chromium/services/network/restricted_cookie_manager_unittest.cc b/chromium/services/network/restricted_cookie_manager_unittest.cc
new file mode 100644
index 00000000000..de4fd40383b
--- /dev/null
+++ b/chromium/services/network/restricted_cookie_manager_unittest.cc
@@ -0,0 +1,240 @@
+// 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 "services/network/restricted_cookie_manager.h"
+
+#include <algorithm>
+
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/time/time.h"
+#include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/cookies/cookie_store.h"
+#include "net/cookies/cookie_store_test_callbacks.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+// Synchronous proxies to a wrapped RestrictedCookieManager's methods.
+class RestrictedCookieManagerSync {
+ public:
+ // Caller must guarantee that |*cookie_service| outlives the
+ // SynchronousCookieManager.
+ explicit RestrictedCookieManagerSync(
+ mojom::RestrictedCookieManager* cookie_service)
+ : cookie_service_(cookie_service) {}
+ ~RestrictedCookieManagerSync() {}
+
+ std::vector<net::CanonicalCookie> GetAllForUrl(
+ const GURL& url,
+ const GURL& site_for_cookies,
+ mojom::CookieManagerGetOptionsPtr options) {
+ base::RunLoop run_loop;
+ std::vector<net::CanonicalCookie> cookies;
+ cookie_service_->GetAllForUrl(
+ url, site_for_cookies, std::move(options),
+ base::BindOnce(&RestrictedCookieManagerSync::GetAllForUrlCallback,
+ &run_loop, &cookies));
+ run_loop.Run();
+ return cookies;
+ }
+
+ bool SetCanonicalCookie(const net::CanonicalCookie& cookie,
+ const GURL& url,
+ const GURL& site_for_cookies) {
+ base::RunLoop run_loop;
+ bool result = false;
+ cookie_service_->SetCanonicalCookie(
+ cookie, url, site_for_cookies,
+ base::BindOnce(&RestrictedCookieManagerSync::SetCanonicalCookieCallback,
+ &run_loop, &result));
+ run_loop.Run();
+ return result;
+ }
+
+ private:
+ static void GetAllForUrlCallback(
+ base::RunLoop* run_loop,
+ std::vector<net::CanonicalCookie>* cookies_out,
+ const std::vector<net::CanonicalCookie>& cookies) {
+ *cookies_out = cookies;
+ run_loop->Quit();
+ }
+
+ static void SetCanonicalCookieCallback(base::RunLoop* run_loop,
+ bool* result_out,
+ bool result) {
+ *result_out = result;
+ run_loop->Quit();
+ }
+
+ mojom::RestrictedCookieManager* cookie_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(RestrictedCookieManagerSync);
+};
+
+class RestrictedCookieManagerTest : public testing::Test {
+ public:
+ RestrictedCookieManagerTest()
+ : cookie_monster_(nullptr, nullptr),
+ service_(std::make_unique<RestrictedCookieManager>(&cookie_monster_,
+ MSG_ROUTING_NONE,
+ MSG_ROUTING_NONE)),
+ binding_(service_.get(), mojo::MakeRequest(&service_ptr_)) {
+ sync_service_ =
+ std::make_unique<RestrictedCookieManagerSync>(service_ptr_.get());
+ }
+ ~RestrictedCookieManagerTest() override {}
+
+ // Set a canonical cookie directly into the store.
+ bool SetCanonicalCookie(const net::CanonicalCookie& cookie,
+ bool secure_source,
+ bool can_modify_httponly) {
+ net::ResultSavingCookieCallback<bool> callback;
+ cookie_monster_.SetCanonicalCookieAsync(
+ std::make_unique<net::CanonicalCookie>(cookie), secure_source,
+ can_modify_httponly,
+ base::BindOnce(&net::ResultSavingCookieCallback<bool>::Run,
+ base::Unretained(&callback)));
+ callback.WaitUntilDone();
+ return callback.result();
+ }
+
+ // Simplified helper for SetCanonicalCookie.
+ //
+ // Creates a CanonicalCookie that is not secure, not http-only,
+ // and not restricted to first parties. Crashes if the creation fails.
+ void SetSessionCookie(const char* name,
+ const char* value,
+ const char* domain,
+ const char* path) {
+ CHECK(SetCanonicalCookie(
+ net::CanonicalCookie(name, value, domain, path, base::Time(),
+ base::Time(), base::Time(), /* secure = */ false,
+ /* httponly = */ false,
+ net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_DEFAULT),
+ /* secure_source = */ true, /* can_modify_httponly = */ true));
+ }
+
+ protected:
+ base::MessageLoopForIO message_loop_;
+ net::CookieMonster cookie_monster_;
+ std::unique_ptr<RestrictedCookieManager> service_;
+ mojom::RestrictedCookieManagerPtr service_ptr_;
+ mojo::Binding<mojom::RestrictedCookieManager> binding_;
+ std::unique_ptr<RestrictedCookieManagerSync> sync_service_;
+};
+
+namespace {
+
+bool CompareCanonicalCookies(const net::CanonicalCookie& c1,
+ const net::CanonicalCookie& c2) {
+ return c1.FullCompare(c2);
+}
+
+} // anonymous namespace
+
+TEST_F(RestrictedCookieManagerTest, GetAllForUrlBlankFilter) {
+ SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
+ SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
+ SetSessionCookie("other-cookie-name", "other-cookie-value", "not-example.com",
+ "/");
+
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "";
+ options->match_type = mojom::CookieMatchType::STARTS_WITH;
+ std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
+ GURL("http://example.com/test/"), GURL("http://example.com"),
+ std::move(options));
+
+ ASSERT_EQ(2u, cookies.size());
+ std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
+
+ EXPECT_EQ("cookie-name", cookies[0].Name());
+ EXPECT_EQ("cookie-value", cookies[0].Value());
+
+ EXPECT_EQ("cookie-name-2", cookies[1].Name());
+ EXPECT_EQ("cookie-value-2", cookies[1].Value());
+}
+
+TEST_F(RestrictedCookieManagerTest, GetAllForUrlEmptyFilter) {
+ SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
+
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "";
+ options->match_type = mojom::CookieMatchType::EQUALS;
+ std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
+ GURL("http://example.com/test/"), GURL("http://example.com"),
+ std::move(options));
+
+ ASSERT_EQ(0u, cookies.size());
+ std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
+}
+
+TEST_F(RestrictedCookieManagerTest, GetAllForUrlEqualsMatch) {
+ SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
+ SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
+
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "cookie-name";
+ options->match_type = mojom::CookieMatchType::EQUALS;
+ std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
+ GURL("http://example.com/test/"), GURL("http://example.com"),
+ std::move(options));
+
+ ASSERT_EQ(1u, cookies.size());
+
+ EXPECT_EQ("cookie-name", cookies[0].Name());
+ EXPECT_EQ("cookie-value", cookies[0].Value());
+}
+
+TEST_F(RestrictedCookieManagerTest, GetAllForUrlStartsWithMatch) {
+ SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
+ SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
+ SetSessionCookie("cookie-name-2b", "cookie-value-2b", "example.com", "/");
+ SetSessionCookie("cookie-name-3b", "cookie-value-3b", "example.com", "/");
+
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "cookie-name-2";
+ options->match_type = mojom::CookieMatchType::STARTS_WITH;
+ std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
+ GURL("http://example.com/test/"), GURL("http://example.com"),
+ std::move(options));
+
+ ASSERT_EQ(2u, cookies.size());
+ std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
+
+ EXPECT_EQ("cookie-name-2", cookies[0].Name());
+ EXPECT_EQ("cookie-value-2", cookies[0].Value());
+
+ EXPECT_EQ("cookie-name-2b", cookies[1].Name());
+ EXPECT_EQ("cookie-value-2b", cookies[1].Value());
+}
+
+TEST_F(RestrictedCookieManagerTest, SetCanonicalCookie) {
+ EXPECT_TRUE(sync_service_->SetCanonicalCookie(
+ net::CanonicalCookie(
+ "new-name", "new-value", "example.com", "/", base::Time(),
+ base::Time(), base::Time(), /* secure = */ false,
+ /* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
+ net::COOKIE_PRIORITY_DEFAULT),
+ GURL("http://example.com/test/"), GURL("http://example.com")));
+
+ auto options = mojom::CookieManagerGetOptions::New();
+ options->name = "new-name";
+ options->match_type = mojom::CookieMatchType::EQUALS;
+ std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
+ GURL("http://example.com/test/"), GURL("http://example.com"),
+ std::move(options));
+
+ ASSERT_EQ(1u, cookies.size());
+
+ EXPECT_EQ("new-name", cookies[0].Name());
+ EXPECT_EQ("new-value", cookies[0].Value());
+}
+
+} // namespace network
diff --git a/chromium/services/network/throttling/network_conditions.cc b/chromium/services/network/throttling/network_conditions.cc
new file mode 100644
index 00000000000..71cd4ac0e52
--- /dev/null
+++ b/chromium/services/network/throttling/network_conditions.cc
@@ -0,0 +1,30 @@
+// 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/network/throttling/network_conditions.h"
+
+namespace network {
+
+NetworkConditions::NetworkConditions() : NetworkConditions(false) {}
+
+NetworkConditions::NetworkConditions(bool offline)
+ : NetworkConditions(offline, 0, 0, 0) {}
+
+NetworkConditions::NetworkConditions(bool offline,
+ double latency,
+ double download_throughput,
+ double upload_throughput)
+ : offline_(offline),
+ latency_(latency),
+ download_throughput_(download_throughput),
+ upload_throughput_(upload_throughput) {}
+
+NetworkConditions::~NetworkConditions() {}
+
+bool NetworkConditions::IsThrottling() const {
+ return !offline_ && ((latency_ != 0) || (download_throughput_ != 0.0) ||
+ (upload_throughput_ != 0));
+}
+
+} // namespace network
diff --git a/chromium/services/network/throttling/network_conditions.h b/chromium/services/network/throttling/network_conditions.h
new file mode 100644
index 00000000000..7b34446f654
--- /dev/null
+++ b/chromium/services/network/throttling/network_conditions.h
@@ -0,0 +1,46 @@
+// 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.
+
+#ifndef SERVICES_NETWORK_THROTTLING_NETWORK_CONDITIONS_H_
+#define SERVICES_NETWORK_THROTTLING_NETWORK_CONDITIONS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+
+namespace network {
+
+// NetworkConditions holds information about desired network conditions.
+class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkConditions {
+ public:
+ NetworkConditions();
+ ~NetworkConditions();
+
+ explicit NetworkConditions(bool offline);
+ NetworkConditions(bool offline,
+ double latency,
+ double download_throughput,
+ double upload_throughput);
+
+ bool IsThrottling() const;
+
+ bool offline() const { return offline_; }
+ double latency() const { return latency_; }
+ double download_throughput() const { return download_throughput_; }
+ double upload_throughput() const { return upload_throughput_; }
+
+ private:
+ const bool offline_;
+ const double latency_;
+ const double download_throughput_;
+ const double upload_throughput_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkConditions);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_THROTTLING_NETWORK_CONDITIONS_H_
diff --git a/chromium/services/network/throttling/throttling_controller.cc b/chromium/services/network/throttling/throttling_controller.cc
new file mode 100644
index 00000000000..d987131a338
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_controller.cc
@@ -0,0 +1,76 @@
+// 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/network/throttling/throttling_controller.h"
+
+#include <utility>
+
+#include "net/http/http_request_info.h"
+#include "services/network/throttling/network_conditions.h"
+#include "services/network/throttling/throttling_network_interceptor.h"
+
+namespace network {
+
+ThrottlingController* ThrottlingController::instance_ = nullptr;
+
+ThrottlingController::ThrottlingController() = default;
+ThrottlingController::~ThrottlingController() = default;
+
+// static
+ThrottlingNetworkInterceptor* ThrottlingController::GetInterceptor(
+ const std::string& client_id) {
+ if (!instance_ || client_id.empty())
+ return nullptr;
+ return instance_->FindInterceptor(client_id);
+}
+
+// static
+void ThrottlingController::SetConditions(
+ const std::string& client_id,
+ std::unique_ptr<NetworkConditions> conditions) {
+ if (!instance_) {
+ if (!conditions)
+ return;
+ instance_ = new ThrottlingController();
+ }
+ instance_->SetNetworkConditions(client_id, std::move(conditions));
+}
+
+ThrottlingNetworkInterceptor* ThrottlingController::FindInterceptor(
+ const std::string& client_id) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ auto it = interceptors_.find(client_id);
+ return it != interceptors_.end() ? it->second.get() : nullptr;
+}
+
+void ThrottlingController::SetNetworkConditions(
+ const std::string& client_id,
+ std::unique_ptr<NetworkConditions> conditions) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ auto it = interceptors_.find(client_id);
+ if (it == interceptors_.end()) {
+ if (!conditions)
+ return;
+ std::unique_ptr<ThrottlingNetworkInterceptor> new_interceptor(
+ new ThrottlingNetworkInterceptor());
+ new_interceptor->UpdateConditions(std::move(conditions));
+ interceptors_[client_id] = std::move(new_interceptor);
+ } else {
+ if (!conditions) {
+ std::unique_ptr<NetworkConditions> online_conditions(
+ new NetworkConditions());
+ it->second->UpdateConditions(std::move(online_conditions));
+ interceptors_.erase(client_id);
+ if (interceptors_.empty()) {
+ delete this;
+ instance_ = nullptr;
+ }
+ } else {
+ it->second->UpdateConditions(std::move(conditions));
+ }
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/throttling/throttling_controller.h b/chromium/services/network/throttling/throttling_controller.h
new file mode 100644
index 00000000000..c6276099749
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_controller.h
@@ -0,0 +1,54 @@
+// 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.
+
+#ifndef SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_CONTROLLER_H_
+#define SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_CONTROLLER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/threading/thread_checker.h"
+
+namespace network {
+
+class NetworkConditions;
+class ThrottlingNetworkInterceptor;
+
+// ThrottlingController manages interceptors identified by client id
+// and their throttling conditions.
+class COMPONENT_EXPORT(NETWORK_SERVICE) ThrottlingController {
+ public:
+ // Applies network emulation configuration.
+ static void SetConditions(const std::string& client_id,
+ std::unique_ptr<NetworkConditions>);
+ static void DisableThrottling(const std::string& client_id);
+
+ static ThrottlingNetworkInterceptor* GetInterceptor(
+ const std::string& client_id);
+
+ private:
+ ThrottlingController();
+ ~ThrottlingController();
+
+ ThrottlingNetworkInterceptor* FindInterceptor(const std::string& client_id);
+ void SetNetworkConditions(const std::string& client_id,
+ std::unique_ptr<NetworkConditions> conditions);
+
+ static ThrottlingController* instance_;
+
+ using InterceptorMap =
+ std::map<std::string, std::unique_ptr<ThrottlingNetworkInterceptor>>;
+
+ InterceptorMap interceptors_;
+ THREAD_CHECKER(thread_checker_);
+
+ DISALLOW_COPY_AND_ASSIGN(ThrottlingController);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_CONTROLLER_H_
diff --git a/chromium/services/network/throttling/throttling_controller_unittest.cc b/chromium/services/network/throttling/throttling_controller_unittest.cc
new file mode 100644
index 00000000000..24638c76392
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_controller_unittest.cc
@@ -0,0 +1,327 @@
+// 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/network/throttling/throttling_controller.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "net/base/chunked_upload_data_stream.h"
+#include "net/http/http_transaction_test_util.h"
+#include "net/log/net_log_with_source.h"
+#include "services/network/throttling/network_conditions.h"
+#include "services/network/throttling/throttling_network_interceptor.h"
+#include "services/network/throttling/throttling_network_transaction.h"
+#include "services/network/throttling/throttling_upload_data_stream.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace network {
+
+using net::kSimpleGET_Transaction;
+using net::MockHttpRequest;
+using net::MockNetworkLayer;
+using net::MockTransaction;
+using net::TEST_MODE_SYNC_NET_START;
+
+const char kClientId[] = "42";
+const char kAnotherClientId[] = "24";
+const char kUploadData[] = "upload_data";
+int64_t kUploadIdentifier = 17;
+
+class TestCallback {
+ public:
+ TestCallback() : run_count_(0), value_(0) {}
+ void Run(int value) {
+ run_count_++;
+ value_ = value;
+ }
+ int run_count() { return run_count_; }
+ int value() { return value_; }
+
+ private:
+ int run_count_;
+ int value_;
+};
+
+class ThrottlingControllerHelper {
+ public:
+ ThrottlingControllerHelper()
+ : task_runner_(base::MakeRefCounted<base::TestMockTimeTaskRunner>()),
+ completion_callback_(
+ base::Bind(&TestCallback::Run, base::Unretained(&callback_))),
+ mock_transaction_(kSimpleGET_Transaction),
+ buffer_(new net::IOBuffer(64)) {
+ mock_transaction_.test_mode = TEST_MODE_SYNC_NET_START;
+ mock_transaction_.url = "http://dot.com";
+ mock_transaction_.request_headers =
+ "X-DevTools-Emulate-Network-Conditions-Client-Id: 42\r\n";
+ AddMockTransaction(&mock_transaction_);
+
+ std::unique_ptr<net::HttpTransaction> network_transaction;
+ network_layer_.CreateTransaction(net::DEFAULT_PRIORITY,
+ &network_transaction);
+ transaction_.reset(
+ new ThrottlingNetworkTransaction(std::move(network_transaction)));
+ message_loop_.SetTaskRunner(task_runner_);
+ }
+
+ void SetNetworkState(bool offline, double download, double upload) {
+ std::unique_ptr<NetworkConditions> conditions(
+ new NetworkConditions(offline, 0, download, upload));
+ ThrottlingController::SetConditions(kClientId, std::move(conditions));
+ }
+
+ void SetNetworkState(const std::string& id, bool offline) {
+ std::unique_ptr<NetworkConditions> conditions(
+ new NetworkConditions(offline));
+ ThrottlingController::SetConditions(id, std::move(conditions));
+ }
+
+ int Start(bool with_upload) {
+ request_.reset(new MockHttpRequest(mock_transaction_));
+
+ if (with_upload) {
+ upload_data_stream_.reset(
+ new net::ChunkedUploadDataStream(kUploadIdentifier));
+ upload_data_stream_->AppendData(kUploadData, arraysize(kUploadData),
+ true);
+ request_->upload_data_stream = upload_data_stream_.get();
+ }
+
+ int rv = transaction_->Start(request_.get(), completion_callback_,
+ net::NetLogWithSource());
+ EXPECT_EQ(with_upload, !!transaction_->custom_upload_data_stream_);
+ return rv;
+ }
+
+ int Read() {
+ return transaction_->Read(buffer_.get(), 64, completion_callback_);
+ }
+
+ bool ShouldFail() {
+ if (transaction_->interceptor_)
+ return transaction_->interceptor_->IsOffline();
+ ThrottlingNetworkInterceptor* interceptor =
+ ThrottlingController::GetInterceptor(kClientId);
+ EXPECT_TRUE(!!interceptor);
+ return interceptor->IsOffline();
+ }
+
+ bool HasStarted() { return !!transaction_->request_; }
+
+ bool HasFailed() { return transaction_->failed_; }
+
+ void CancelTransaction() { transaction_.reset(); }
+
+ int ReadUploadData() {
+ EXPECT_EQ(net::OK, transaction_->custom_upload_data_stream_->Init(
+ completion_callback_, net::NetLogWithSource()));
+ return transaction_->custom_upload_data_stream_->Read(buffer_.get(), 64,
+ completion_callback_);
+ }
+
+ ~ThrottlingControllerHelper() { RemoveMockTransaction(&mock_transaction_); }
+
+ TestCallback* callback() { return &callback_; }
+ ThrottlingNetworkTransaction* transaction() { return transaction_.get(); }
+
+ void FastForwardUntilNoTasksRemain() {
+ task_runner_->FastForwardUntilNoTasksRemain();
+ }
+
+ private:
+ scoped_refptr<base::TestMockTimeTaskRunner> task_runner_;
+ base::MessageLoop message_loop_;
+ MockNetworkLayer network_layer_;
+ TestCallback callback_;
+ net::CompletionCallback completion_callback_;
+ MockTransaction mock_transaction_;
+ std::unique_ptr<ThrottlingNetworkTransaction> transaction_;
+ scoped_refptr<net::IOBuffer> buffer_;
+ std::unique_ptr<net::ChunkedUploadDataStream> upload_data_stream_;
+ std::unique_ptr<MockHttpRequest> request_;
+};
+
+TEST(ThrottlingControllerTest, SingleDisableEnable) {
+ ThrottlingControllerHelper helper;
+ helper.SetNetworkState(false, 0, 0);
+ helper.Start(false);
+
+ EXPECT_FALSE(helper.ShouldFail());
+ helper.SetNetworkState(true, 0, 0);
+ EXPECT_TRUE(helper.ShouldFail());
+ helper.SetNetworkState(false, 0, 0);
+ EXPECT_FALSE(helper.ShouldFail());
+
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(ThrottlingControllerTest, InterceptorIsolation) {
+ ThrottlingControllerHelper helper;
+ helper.SetNetworkState(false, 0, 0);
+ helper.Start(false);
+
+ EXPECT_FALSE(helper.ShouldFail());
+ helper.SetNetworkState(kAnotherClientId, true);
+ EXPECT_FALSE(helper.ShouldFail());
+ helper.SetNetworkState(true, 0, 0);
+ EXPECT_TRUE(helper.ShouldFail());
+
+ helper.SetNetworkState(kAnotherClientId, false);
+ helper.SetNetworkState(false, 0, 0);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(ThrottlingControllerTest, FailOnStart) {
+ ThrottlingControllerHelper helper;
+ helper.SetNetworkState(true, 0, 0);
+
+ int rv = helper.Start(false);
+ EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
+
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(helper.callback()->run_count(), 0);
+}
+
+TEST(ThrottlingControllerTest, FailRunningTransaction) {
+ ThrottlingControllerHelper helper;
+ helper.SetNetworkState(false, 0, 0);
+ TestCallback* callback = helper.callback();
+
+ int rv = helper.Start(false);
+ EXPECT_EQ(rv, net::OK);
+
+ rv = helper.Read();
+ EXPECT_EQ(rv, net::ERR_IO_PENDING);
+ EXPECT_EQ(callback->run_count(), 0);
+
+ helper.SetNetworkState(true, 0, 0);
+ EXPECT_EQ(callback->run_count(), 0);
+
+ // Wait until HttpTrancation completes reading and invokes callback.
+ // ThrottlingNetworkTransaction should report error instead.
+ helper.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(callback->run_count(), 1);
+ EXPECT_EQ(callback->value(), net::ERR_INTERNET_DISCONNECTED);
+
+ // Check that transaction is not failed second time.
+ helper.SetNetworkState(false, 0, 0);
+ helper.SetNetworkState(true, 0, 0);
+ EXPECT_EQ(callback->run_count(), 1);
+}
+
+TEST(ThrottlingControllerTest, ReadAfterFail) {
+ ThrottlingControllerHelper helper;
+ helper.SetNetworkState(false, 0, 0);
+
+ int rv = helper.Start(false);
+ EXPECT_EQ(rv, net::OK);
+ EXPECT_TRUE(helper.HasStarted());
+
+ helper.SetNetworkState(true, 0, 0);
+ // Not failed yet, as no IO was initiated.
+ EXPECT_FALSE(helper.HasFailed());
+
+ rv = helper.Read();
+ // Fails on first IO.
+ EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
+
+ // Check that callback is never invoked.
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(helper.callback()->run_count(), 0);
+}
+
+TEST(ThrottlingControllerTest, CancelTransaction) {
+ ThrottlingControllerHelper helper;
+ helper.SetNetworkState(false, 0, 0);
+
+ int rv = helper.Start(false);
+ EXPECT_EQ(rv, net::OK);
+ EXPECT_TRUE(helper.HasStarted());
+ helper.CancelTransaction();
+
+ // Should not crash.
+ helper.SetNetworkState(true, 0, 0);
+ helper.SetNetworkState(false, 0, 0);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(ThrottlingControllerTest, CancelFailedTransaction) {
+ ThrottlingControllerHelper helper;
+ helper.SetNetworkState(true, 0, 0);
+
+ int rv = helper.Start(false);
+ EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
+ EXPECT_TRUE(helper.HasStarted());
+ helper.CancelTransaction();
+
+ // Should not crash.
+ helper.SetNetworkState(true, 0, 0);
+ helper.SetNetworkState(false, 0, 0);
+ base::RunLoop().RunUntilIdle();
+}
+
+TEST(ThrottlingControllerTest, UploadDoesNotFail) {
+ ThrottlingControllerHelper helper;
+ helper.SetNetworkState(true, 0, 0);
+ int rv = helper.Start(true);
+ EXPECT_EQ(rv, net::ERR_INTERNET_DISCONNECTED);
+ rv = helper.ReadUploadData();
+ EXPECT_EQ(rv, static_cast<int>(arraysize(kUploadData)));
+}
+
+TEST(ThrottlingControllerTest, DownloadOnly) {
+ ThrottlingControllerHelper helper;
+ TestCallback* callback = helper.callback();
+
+ helper.SetNetworkState(false, 10000000, 0);
+ int rv = helper.Start(false);
+ EXPECT_EQ(rv, net::ERR_IO_PENDING);
+ helper.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(callback->run_count(), 1);
+ EXPECT_GE(callback->value(), net::OK);
+
+ rv = helper.Read();
+ EXPECT_EQ(rv, net::ERR_IO_PENDING);
+ EXPECT_EQ(callback->run_count(), 1);
+ helper.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(callback->run_count(), 2);
+ EXPECT_GE(callback->value(), net::OK);
+}
+
+TEST(ThrottlingControllerTest, UploadOnly) {
+ ThrottlingControllerHelper helper;
+ TestCallback* callback = helper.callback();
+
+ helper.SetNetworkState(false, 0, 1000000);
+ int rv = helper.Start(true);
+ EXPECT_EQ(rv, net::OK);
+ helper.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(callback->run_count(), 0);
+
+ rv = helper.Read();
+ EXPECT_EQ(rv, net::ERR_IO_PENDING);
+ EXPECT_EQ(callback->run_count(), 0);
+ helper.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(callback->run_count(), 1);
+ EXPECT_GE(callback->value(), net::OK);
+
+ rv = helper.ReadUploadData();
+ EXPECT_EQ(rv, net::ERR_IO_PENDING);
+ EXPECT_EQ(callback->run_count(), 1);
+ helper.FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(callback->run_count(), 2);
+ EXPECT_EQ(callback->value(), static_cast<int>(arraysize(kUploadData)));
+}
+
+} // namespace network
diff --git a/chromium/services/network/throttling/throttling_network_interceptor.cc b/chromium/services/network/throttling/throttling_network_interceptor.cc
new file mode 100644
index 00000000000..03deaf88f62
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_network_interceptor.cc
@@ -0,0 +1,288 @@
+// 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/network/throttling/throttling_network_interceptor.h"
+
+#include <stddef.h>
+#include <algorithm>
+#include <limits>
+#include <utility>
+
+#include "base/time/time.h"
+#include "net/base/net_errors.h"
+#include "services/network/throttling/network_conditions.h"
+
+namespace network {
+
+namespace {
+
+int64_t kPacketSize = 1500;
+
+base::TimeDelta CalculateTickLength(double throughput) {
+ if (!throughput)
+ return base::TimeDelta::FromMicroseconds(1);
+ int64_t us_tick_length = (1000000L * kPacketSize) / throughput;
+ DCHECK(us_tick_length != 0);
+ if (us_tick_length == 0)
+ us_tick_length = 1;
+ return base::TimeDelta::FromMicroseconds(us_tick_length);
+}
+
+} // namespace
+
+ThrottlingNetworkInterceptor::ThrottleRecord::ThrottleRecord() {}
+
+ThrottlingNetworkInterceptor::ThrottleRecord::ThrottleRecord(
+ const ThrottleRecord& other) = default;
+
+ThrottlingNetworkInterceptor::ThrottleRecord::~ThrottleRecord() {}
+
+ThrottlingNetworkInterceptor::ThrottlingNetworkInterceptor()
+ : conditions_(new NetworkConditions()),
+ download_last_tick_(0),
+ upload_last_tick_(0),
+ weak_ptr_factory_(this) {}
+
+ThrottlingNetworkInterceptor::~ThrottlingNetworkInterceptor() {}
+
+base::WeakPtr<ThrottlingNetworkInterceptor>
+ThrottlingNetworkInterceptor::GetWeakPtr() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+void ThrottlingNetworkInterceptor::FinishRecords(ThrottleRecords* records,
+ bool offline) {
+ ThrottleRecords temp;
+ temp.swap(*records);
+ for (const ThrottleRecord& record : temp) {
+ bool failed = offline && !record.is_upload;
+ record.callback.Run(failed ? net::ERR_INTERNET_DISCONNECTED : record.result,
+ record.bytes);
+ }
+}
+
+void ThrottlingNetworkInterceptor::UpdateConditions(
+ std::unique_ptr<NetworkConditions> conditions) {
+ DCHECK(conditions);
+ base::TimeTicks now = base::TimeTicks::Now();
+ if (conditions_->IsThrottling())
+ UpdateThrottled(now);
+
+ conditions_ = std::move(conditions);
+
+ bool offline = conditions_->offline();
+ if (offline || !conditions_->IsThrottling()) {
+ timer_.Stop();
+ FinishRecords(&download_, offline);
+ FinishRecords(&upload_, offline);
+ FinishRecords(&suspended_, offline);
+ return;
+ }
+
+ // Throttling.
+ DCHECK(conditions_->download_throughput() != 0 ||
+ conditions_->upload_throughput() != 0);
+ offset_ = now;
+
+ download_last_tick_ = 0;
+ download_tick_length_ =
+ CalculateTickLength(conditions_->download_throughput());
+
+ upload_last_tick_ = 0;
+ upload_tick_length_ = CalculateTickLength(conditions_->upload_throughput());
+
+ latency_length_ = base::TimeDelta();
+ double latency = conditions_->latency();
+ if (latency > 0)
+ latency_length_ = base::TimeDelta::FromMillisecondsD(latency);
+ ArmTimer(now);
+}
+
+uint64_t ThrottlingNetworkInterceptor::UpdateThrottledRecords(
+ base::TimeTicks now,
+ ThrottleRecords* records,
+ uint64_t last_tick,
+ base::TimeDelta tick_length) {
+ if (tick_length.is_zero()) {
+ DCHECK(records->empty());
+ return last_tick;
+ }
+
+ int64_t new_tick = (now - offset_) / tick_length;
+ int64_t ticks = new_tick - last_tick;
+
+ int64_t length = records->size();
+ if (!length)
+ return new_tick;
+
+ int64_t shift = ticks % length;
+ for (int64_t i = 0; i < length; ++i) {
+ (*records)[i].bytes -=
+ (ticks / length) * kPacketSize + (i < shift ? kPacketSize : 0);
+ }
+ std::rotate(records->begin(), records->begin() + shift, records->end());
+ return new_tick;
+}
+
+void ThrottlingNetworkInterceptor::UpdateThrottled(base::TimeTicks now) {
+ download_last_tick_ = UpdateThrottledRecords(
+ now, &download_, download_last_tick_, download_tick_length_);
+ upload_last_tick_ = UpdateThrottledRecords(now, &upload_, upload_last_tick_,
+ upload_tick_length_);
+ UpdateSuspended(now);
+}
+
+void ThrottlingNetworkInterceptor::UpdateSuspended(base::TimeTicks now) {
+ int64_t activation_baseline =
+ (now - latency_length_ - base::TimeTicks()).InMicroseconds();
+ ThrottleRecords suspended;
+ for (const ThrottleRecord& record : suspended_) {
+ if (record.send_end <= activation_baseline) {
+ if (record.is_upload)
+ upload_.push_back(record);
+ else
+ download_.push_back(record);
+ } else {
+ suspended.push_back(record);
+ }
+ }
+ suspended_.swap(suspended);
+}
+
+void ThrottlingNetworkInterceptor::CollectFinished(ThrottleRecords* records,
+ ThrottleRecords* finished) {
+ ThrottleRecords active;
+ for (const ThrottleRecord& record : *records) {
+ if (record.bytes < 0)
+ finished->push_back(record);
+ else
+ active.push_back(record);
+ }
+ records->swap(active);
+}
+
+void ThrottlingNetworkInterceptor::OnTimer() {
+ base::TimeTicks now = base::TimeTicks::Now();
+ UpdateThrottled(now);
+
+ ThrottleRecords finished;
+ CollectFinished(&download_, &finished);
+ CollectFinished(&upload_, &finished);
+ for (const ThrottleRecord& record : finished)
+ record.callback.Run(record.result, record.bytes);
+
+ ArmTimer(now);
+}
+
+base::TimeTicks ThrottlingNetworkInterceptor::CalculateDesiredTime(
+ const ThrottleRecords& records,
+ uint64_t last_tick,
+ base::TimeDelta tick_length) {
+ int64_t min_ticks_left = 0x10000L;
+ size_t count = records.size();
+ for (size_t i = 0; i < count; ++i) {
+ int64_t packets_left = (records[i].bytes + kPacketSize - 1) / kPacketSize;
+ int64_t ticks_left = (i + 1) + count * (packets_left - 1);
+ if (i == 0 || ticks_left < min_ticks_left)
+ min_ticks_left = ticks_left;
+ }
+ return offset_ + tick_length * (last_tick + min_ticks_left);
+}
+
+void ThrottlingNetworkInterceptor::ArmTimer(base::TimeTicks now) {
+ size_t suspend_count = suspended_.size();
+ if (download_.empty() && upload_.empty() && !suspend_count)
+ return;
+
+ base::TimeTicks desired_time = CalculateDesiredTime(
+ download_, download_last_tick_, download_tick_length_);
+
+ base::TimeTicks upload_time =
+ CalculateDesiredTime(upload_, upload_last_tick_, upload_tick_length_);
+ if (upload_time < desired_time)
+ desired_time = upload_time;
+
+ int64_t min_baseline = std::numeric_limits<int64_t>::max();
+ for (size_t i = 0; i < suspend_count; ++i) {
+ if (suspended_[i].send_end < min_baseline)
+ min_baseline = suspended_[i].send_end;
+ }
+ if (suspend_count) {
+ base::TimeTicks activation_time =
+ base::TimeTicks() + base::TimeDelta::FromMicroseconds(min_baseline) +
+ latency_length_;
+ if (activation_time < desired_time)
+ desired_time = activation_time;
+ }
+
+ timer_.Start(FROM_HERE, desired_time - now,
+ base::Bind(&ThrottlingNetworkInterceptor::OnTimer,
+ base::Unretained(this)));
+}
+
+int ThrottlingNetworkInterceptor::StartThrottle(
+ int result,
+ int64_t bytes,
+ base::TimeTicks send_end,
+ bool start,
+ bool is_upload,
+ const ThrottleCallback& callback) {
+ if (result < 0)
+ return result;
+
+ if (conditions_->offline())
+ return is_upload ? result : net::ERR_INTERNET_DISCONNECTED;
+
+ if (!conditions_->latency() &&
+ ((is_upload && !conditions_->upload_throughput()) ||
+ (!is_upload && !conditions_->download_throughput()))) {
+ return result;
+ }
+
+ ThrottleRecord record;
+ record.result = result;
+ record.bytes = bytes;
+ record.callback = callback;
+ // TODO(dgozman): use upload throughput.
+ record.is_upload = is_upload;
+
+ base::TimeTicks now = base::TimeTicks::Now();
+ UpdateThrottled(now);
+ if (start && !latency_length_.is_zero()) {
+ record.send_end = (send_end - base::TimeTicks()).InMicroseconds();
+ suspended_.push_back(record);
+ UpdateSuspended(now);
+ } else {
+ if (is_upload)
+ upload_.push_back(record);
+ else
+ download_.push_back(record);
+ }
+ ArmTimer(now);
+
+ return net::ERR_IO_PENDING;
+}
+
+void ThrottlingNetworkInterceptor::StopThrottle(
+ const ThrottleCallback& callback) {
+ RemoveRecord(&download_, callback);
+ RemoveRecord(&upload_, callback);
+ RemoveRecord(&suspended_, callback);
+}
+
+void ThrottlingNetworkInterceptor::RemoveRecord(
+ ThrottleRecords* records,
+ const ThrottleCallback& callback) {
+ records->erase(std::remove_if(records->begin(), records->end(),
+ [&callback](const ThrottleRecord& record) {
+ return record.callback.Equals(callback);
+ }),
+ records->end());
+}
+
+bool ThrottlingNetworkInterceptor::IsOffline() {
+ return conditions_->offline();
+}
+
+} // namespace network \ No newline at end of file
diff --git a/chromium/services/network/throttling/throttling_network_interceptor.h b/chromium/services/network/throttling/throttling_network_interceptor.h
new file mode 100644
index 00000000000..bfb37671155
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_network_interceptor.h
@@ -0,0 +1,110 @@
+// 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.
+
+#ifndef SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_INTERCEPTOR_H_
+#define SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_INTERCEPTOR_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/timer/timer.h"
+
+namespace base {
+class TimeDelta;
+class TimeTicks;
+} // namespace base
+
+namespace network {
+class NetworkConditions;
+
+// ThrottlingNetworkInterceptor emulates network conditions for transactions
+// with specific client id.
+class COMPONENT_EXPORT(NETWORK_SERVICE) ThrottlingNetworkInterceptor {
+ public:
+ using ThrottleCallback = base::Callback<void(int, int64_t)>;
+
+ ThrottlingNetworkInterceptor();
+ virtual ~ThrottlingNetworkInterceptor();
+
+ base::WeakPtr<ThrottlingNetworkInterceptor> GetWeakPtr();
+
+ // Applies network emulation configuration.
+ void UpdateConditions(std::unique_ptr<NetworkConditions> conditions);
+
+ // Throttles with |is_upload == true| always succeed, even in offline mode.
+ int StartThrottle(int result,
+ int64_t bytes,
+ base::TimeTicks send_end,
+ bool start,
+ bool is_upload,
+ const ThrottleCallback& callback);
+ void StopThrottle(const ThrottleCallback& callback);
+
+ bool IsOffline();
+
+ private:
+ struct ThrottleRecord {
+ public:
+ ThrottleRecord();
+ ThrottleRecord(const ThrottleRecord& other);
+ ~ThrottleRecord();
+ int result;
+ int64_t bytes;
+ int64_t send_end;
+ bool is_upload;
+ ThrottleCallback callback;
+ };
+ using ThrottleRecords = std::vector<ThrottleRecord>;
+
+ void FinishRecords(ThrottleRecords* records, bool offline);
+
+ uint64_t UpdateThrottledRecords(base::TimeTicks now,
+ ThrottleRecords* records,
+ uint64_t last_tick,
+ base::TimeDelta tick_length);
+ void UpdateThrottled(base::TimeTicks now);
+ void UpdateSuspended(base::TimeTicks now);
+
+ void CollectFinished(ThrottleRecords* records, ThrottleRecords* finished);
+ void OnTimer();
+
+ base::TimeTicks CalculateDesiredTime(const ThrottleRecords& records,
+ uint64_t last_tick,
+ base::TimeDelta tick_length);
+ void ArmTimer(base::TimeTicks now);
+
+ void RemoveRecord(ThrottleRecords* records, const ThrottleCallback& callback);
+
+ std::unique_ptr<NetworkConditions> conditions_;
+
+ // Throttables suspended for a "latency" period.
+ ThrottleRecords suspended_;
+
+ // Throttables waiting certain amount of transfer to be "accounted".
+ ThrottleRecords download_;
+ ThrottleRecords upload_;
+
+ base::OneShotTimer timer_;
+ base::TimeTicks offset_;
+ base::TimeDelta download_tick_length_;
+ base::TimeDelta upload_tick_length_;
+ base::TimeDelta latency_length_;
+ uint64_t download_last_tick_;
+ uint64_t upload_last_tick_;
+
+ base::WeakPtrFactory<ThrottlingNetworkInterceptor> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrottlingNetworkInterceptor);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_INTERCEPTOR_H_
diff --git a/chromium/services/network/throttling/throttling_network_transaction.cc b/chromium/services/network/throttling/throttling_network_transaction.cc
new file mode 100644
index 00000000000..a6ada2ee49e
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_network_transaction.cc
@@ -0,0 +1,321 @@
+// 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/network/throttling/throttling_network_transaction.h"
+
+#include <utility>
+
+#include "base/callback_helpers.h"
+#include "net/base/load_timing_info.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_network_transaction.h"
+#include "net/http/http_request_info.h"
+#include "net/socket/connection_attempts.h"
+#include "services/network/throttling/throttling_controller.h"
+#include "services/network/throttling/throttling_network_interceptor.h"
+#include "services/network/throttling/throttling_upload_data_stream.h"
+
+namespace network {
+
+// Keep in sync with X_DevTools_Emulate_Network_Conditions_Client_Id defined in
+// HTTPNames.json5.
+const char
+ ThrottlingNetworkTransaction::kDevToolsEmulateNetworkConditionsClientId[] =
+ "X-DevTools-Emulate-Network-Conditions-Client-Id";
+
+ThrottlingNetworkTransaction::ThrottlingNetworkTransaction(
+ std::unique_ptr<net::HttpTransaction> network_transaction)
+ : throttled_byte_count_(0),
+ network_transaction_(std::move(network_transaction)),
+ request_(nullptr),
+ failed_(false) {}
+
+ThrottlingNetworkTransaction::~ThrottlingNetworkTransaction() {
+ if (interceptor_ && !throttle_callback_.is_null())
+ interceptor_->StopThrottle(throttle_callback_);
+}
+
+void ThrottlingNetworkTransaction::IOCallback(
+ const net::CompletionCallback& callback,
+ bool start,
+ int result) {
+ result = Throttle(callback, start, result);
+ if (result != net::ERR_IO_PENDING)
+ callback.Run(result);
+}
+
+int ThrottlingNetworkTransaction::Throttle(
+ const net::CompletionCallback& callback,
+ bool start,
+ int result) {
+ if (failed_)
+ return net::ERR_INTERNET_DISCONNECTED;
+ if (!interceptor_ || result < 0)
+ return result;
+
+ base::TimeTicks send_end;
+ if (start) {
+ throttled_byte_count_ += network_transaction_->GetTotalReceivedBytes();
+ net::LoadTimingInfo load_timing_info;
+ if (GetLoadTimingInfo(&load_timing_info)) {
+ send_end = load_timing_info.send_end;
+ if (!load_timing_info.push_start.is_null())
+ start = false;
+ }
+ if (send_end.is_null())
+ send_end = base::TimeTicks::Now();
+ }
+ if (result > 0)
+ throttled_byte_count_ += result;
+
+ throttle_callback_ =
+ base::Bind(&ThrottlingNetworkTransaction::ThrottleCallback,
+ base::Unretained(this), callback);
+ int rv = interceptor_->StartThrottle(result, throttled_byte_count_, send_end,
+ start, false, throttle_callback_);
+ if (rv != net::ERR_IO_PENDING)
+ throttle_callback_.Reset();
+ if (rv == net::ERR_INTERNET_DISCONNECTED)
+ Fail();
+ return rv;
+}
+
+void ThrottlingNetworkTransaction::ThrottleCallback(
+ const net::CompletionCallback& callback,
+ int result,
+ int64_t bytes) {
+ DCHECK(!throttle_callback_.is_null());
+ throttle_callback_.Reset();
+ if (result == net::ERR_INTERNET_DISCONNECTED)
+ Fail();
+ throttled_byte_count_ = bytes;
+ callback.Run(result);
+}
+
+void ThrottlingNetworkTransaction::Fail() {
+ DCHECK(request_);
+ DCHECK(!failed_);
+ failed_ = true;
+ network_transaction_->SetBeforeNetworkStartCallback(
+ BeforeNetworkStartCallback());
+ if (interceptor_)
+ interceptor_.reset();
+}
+
+bool ThrottlingNetworkTransaction::CheckFailed() {
+ if (failed_)
+ return true;
+ if (interceptor_ && interceptor_->IsOffline()) {
+ Fail();
+ return true;
+ }
+ return false;
+}
+
+int ThrottlingNetworkTransaction::Start(const net::HttpRequestInfo* request,
+ const net::CompletionCallback& callback,
+ const net::NetLogWithSource& net_log) {
+ DCHECK(request);
+ request_ = request;
+
+ std::string client_id;
+ bool has_devtools_client_id = request_->extra_headers.HasHeader(
+ kDevToolsEmulateNetworkConditionsClientId);
+ if (has_devtools_client_id) {
+ custom_request_.reset(new net::HttpRequestInfo(*request_));
+ custom_request_->extra_headers.GetHeader(
+ kDevToolsEmulateNetworkConditionsClientId, &client_id);
+ custom_request_->extra_headers.RemoveHeader(
+ kDevToolsEmulateNetworkConditionsClientId);
+
+ if (request_->upload_data_stream) {
+ custom_upload_data_stream_.reset(
+ new ThrottlingUploadDataStream(request_->upload_data_stream));
+ custom_request_->upload_data_stream = custom_upload_data_stream_.get();
+ }
+
+ request_ = custom_request_.get();
+ }
+
+ ThrottlingNetworkInterceptor* interceptor =
+ ThrottlingController::GetInterceptor(client_id);
+ if (interceptor) {
+ interceptor_ = interceptor->GetWeakPtr();
+ if (custom_upload_data_stream_)
+ custom_upload_data_stream_->SetInterceptor(interceptor);
+ }
+
+ if (CheckFailed())
+ return net::ERR_INTERNET_DISCONNECTED;
+
+ if (!interceptor_)
+ return network_transaction_->Start(request_, callback, net_log);
+
+ int result = network_transaction_->Start(
+ request_,
+ base::Bind(&ThrottlingNetworkTransaction::IOCallback,
+ base::Unretained(this), callback, true),
+ net_log);
+ return Throttle(callback, true, result);
+}
+
+int ThrottlingNetworkTransaction::RestartIgnoringLastError(
+ const net::CompletionCallback& callback) {
+ if (CheckFailed())
+ return net::ERR_INTERNET_DISCONNECTED;
+ if (!interceptor_)
+ return network_transaction_->RestartIgnoringLastError(callback);
+
+ int result = network_transaction_->RestartIgnoringLastError(
+ base::Bind(&ThrottlingNetworkTransaction::IOCallback,
+ base::Unretained(this), callback, true));
+ return Throttle(callback, true, result);
+}
+
+int ThrottlingNetworkTransaction::RestartWithCertificate(
+ scoped_refptr<net::X509Certificate> client_cert,
+ scoped_refptr<net::SSLPrivateKey> client_private_key,
+ const net::CompletionCallback& callback) {
+ if (CheckFailed())
+ return net::ERR_INTERNET_DISCONNECTED;
+ if (!interceptor_) {
+ return network_transaction_->RestartWithCertificate(
+ std::move(client_cert), std::move(client_private_key), callback);
+ }
+
+ int result = network_transaction_->RestartWithCertificate(
+ std::move(client_cert), std::move(client_private_key),
+ base::Bind(&ThrottlingNetworkTransaction::IOCallback,
+ base::Unretained(this), callback, true));
+ return Throttle(callback, true, result);
+}
+
+int ThrottlingNetworkTransaction::RestartWithAuth(
+ const net::AuthCredentials& credentials,
+ const net::CompletionCallback& callback) {
+ if (CheckFailed())
+ return net::ERR_INTERNET_DISCONNECTED;
+ if (!interceptor_)
+ return network_transaction_->RestartWithAuth(credentials, callback);
+
+ int result = network_transaction_->RestartWithAuth(
+ credentials, base::Bind(&ThrottlingNetworkTransaction::IOCallback,
+ base::Unretained(this), callback, true));
+ return Throttle(callback, true, result);
+}
+
+bool ThrottlingNetworkTransaction::IsReadyToRestartForAuth() {
+ return network_transaction_->IsReadyToRestartForAuth();
+}
+
+int ThrottlingNetworkTransaction::Read(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) {
+ if (CheckFailed())
+ return net::ERR_INTERNET_DISCONNECTED;
+ if (!interceptor_)
+ return network_transaction_->Read(buf, buf_len, callback);
+
+ int result = network_transaction_->Read(
+ buf, buf_len,
+ base::Bind(&ThrottlingNetworkTransaction::IOCallback,
+ base::Unretained(this), callback, false));
+ // URLRequestJob relies on synchronous end-of-stream notification.
+ if (result == 0)
+ return result;
+ return Throttle(callback, false, result);
+}
+
+void ThrottlingNetworkTransaction::StopCaching() {
+ network_transaction_->StopCaching();
+}
+
+bool ThrottlingNetworkTransaction::GetFullRequestHeaders(
+ net::HttpRequestHeaders* headers) const {
+ return network_transaction_->GetFullRequestHeaders(headers);
+}
+
+int64_t ThrottlingNetworkTransaction::GetTotalReceivedBytes() const {
+ return network_transaction_->GetTotalReceivedBytes();
+}
+
+int64_t ThrottlingNetworkTransaction::GetTotalSentBytes() const {
+ return network_transaction_->GetTotalSentBytes();
+}
+
+void ThrottlingNetworkTransaction::DoneReading() {
+ network_transaction_->DoneReading();
+}
+
+const net::HttpResponseInfo* ThrottlingNetworkTransaction::GetResponseInfo()
+ const {
+ return network_transaction_->GetResponseInfo();
+}
+
+net::LoadState ThrottlingNetworkTransaction::GetLoadState() const {
+ return network_transaction_->GetLoadState();
+}
+
+void ThrottlingNetworkTransaction::SetQuicServerInfo(
+ net::QuicServerInfo* quic_server_info) {
+ network_transaction_->SetQuicServerInfo(quic_server_info);
+}
+
+bool ThrottlingNetworkTransaction::GetLoadTimingInfo(
+ net::LoadTimingInfo* load_timing_info) const {
+ return network_transaction_->GetLoadTimingInfo(load_timing_info);
+}
+
+bool ThrottlingNetworkTransaction::GetRemoteEndpoint(
+ net::IPEndPoint* endpoint) const {
+ return network_transaction_->GetRemoteEndpoint(endpoint);
+}
+
+void ThrottlingNetworkTransaction::PopulateNetErrorDetails(
+ net::NetErrorDetails* details) const {
+ return network_transaction_->PopulateNetErrorDetails(details);
+}
+
+void ThrottlingNetworkTransaction::SetPriority(net::RequestPriority priority) {
+ network_transaction_->SetPriority(priority);
+}
+
+void ThrottlingNetworkTransaction::SetWebSocketHandshakeStreamCreateHelper(
+ net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) {
+ network_transaction_->SetWebSocketHandshakeStreamCreateHelper(create_helper);
+}
+
+void ThrottlingNetworkTransaction::SetBeforeNetworkStartCallback(
+ const BeforeNetworkStartCallback& callback) {
+ network_transaction_->SetBeforeNetworkStartCallback(callback);
+}
+
+void ThrottlingNetworkTransaction::SetRequestHeadersCallback(
+ net::RequestHeadersCallback callback) {
+ network_transaction_->SetRequestHeadersCallback(std::move(callback));
+}
+
+void ThrottlingNetworkTransaction::SetResponseHeadersCallback(
+ net::ResponseHeadersCallback callback) {
+ network_transaction_->SetResponseHeadersCallback(std::move(callback));
+}
+
+void ThrottlingNetworkTransaction::SetBeforeHeadersSentCallback(
+ const BeforeHeadersSentCallback& callback) {
+ network_transaction_->SetBeforeHeadersSentCallback(callback);
+}
+
+int ThrottlingNetworkTransaction::ResumeNetworkStart() {
+ if (CheckFailed())
+ return net::ERR_INTERNET_DISCONNECTED;
+ return network_transaction_->ResumeNetworkStart();
+}
+
+void ThrottlingNetworkTransaction::GetConnectionAttempts(
+ net::ConnectionAttempts* out) const {
+ network_transaction_->GetConnectionAttempts(out);
+}
+
+} // namespace network
diff --git a/chromium/services/network/throttling/throttling_network_transaction.h b/chromium/services/network/throttling/throttling_network_transaction.h
new file mode 100644
index 00000000000..0c9370a99c5
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_network_transaction.h
@@ -0,0 +1,136 @@
+// 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.
+
+#ifndef SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_TRANSACTION_H_
+#define SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_TRANSACTION_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/load_states.h"
+#include "net/base/net_error_details.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_transaction.h"
+#include "net/websockets/websocket_handshake_stream_base.h"
+#include "services/network/throttling/throttling_network_interceptor.h"
+
+namespace net {
+class AuthCredentials;
+class HttpRequestHeaders;
+struct HttpRequestInfo;
+class HttpResponseInfo;
+class IOBuffer;
+struct LoadTimingInfo;
+class NetLogWithSource;
+class X509Certificate;
+} // namespace net
+
+namespace network {
+
+class ThrottlingController;
+class ThrottlingControllerHelper;
+class ThrottlingUploadDataStream;
+
+// ThrottlingNetworkTransaction is a wrapper for network transaction. All
+// HttpTransaction methods are proxied to real transaction, but |callback|
+// parameter is saved and replaced with proxy callback. Fail method should be
+// used to simulate network outage. It runs saved callback (if any) with
+// net::ERR_INTERNET_DISCONNECTED result value.
+class COMPONENT_EXPORT(NETWORK_SERVICE) ThrottlingNetworkTransaction
+ : public net::HttpTransaction {
+ public:
+ static const char kDevToolsEmulateNetworkConditionsClientId[];
+
+ explicit ThrottlingNetworkTransaction(
+ std::unique_ptr<net::HttpTransaction> network_transaction);
+
+ ~ThrottlingNetworkTransaction() override;
+
+ // HttpTransaction methods:
+ int Start(const net::HttpRequestInfo* request,
+ const net::CompletionCallback& callback,
+ const net::NetLogWithSource& net_log) override;
+ int RestartIgnoringLastError(
+ const net::CompletionCallback& callback) override;
+ int RestartWithCertificate(
+ scoped_refptr<net::X509Certificate> client_cert,
+ scoped_refptr<net::SSLPrivateKey> client_private_key,
+ const net::CompletionCallback& callback) override;
+ int RestartWithAuth(const net::AuthCredentials& credentials,
+ const net::CompletionCallback& callback) override;
+ bool IsReadyToRestartForAuth() override;
+
+ int Read(net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback) override;
+ void StopCaching() override;
+ bool GetFullRequestHeaders(net::HttpRequestHeaders* headers) const override;
+ int64_t GetTotalReceivedBytes() const override;
+ int64_t GetTotalSentBytes() const override;
+ void DoneReading() override;
+ const net::HttpResponseInfo* GetResponseInfo() const override;
+ net::LoadState GetLoadState() const override;
+ void SetQuicServerInfo(net::QuicServerInfo* quic_server_info) override;
+ bool GetLoadTimingInfo(net::LoadTimingInfo* load_timing_info) const override;
+ bool GetRemoteEndpoint(net::IPEndPoint* endpoint) const override;
+ void PopulateNetErrorDetails(net::NetErrorDetails* details) const override;
+ void SetPriority(net::RequestPriority priority) override;
+ void SetWebSocketHandshakeStreamCreateHelper(
+ net::WebSocketHandshakeStreamBase::CreateHelper* create_helper) override;
+ void SetBeforeNetworkStartCallback(
+ const BeforeNetworkStartCallback& callback) override;
+ void SetBeforeHeadersSentCallback(
+ const BeforeHeadersSentCallback& callback) override;
+ void SetRequestHeadersCallback(net::RequestHeadersCallback callback) override;
+ void SetResponseHeadersCallback(
+ net::ResponseHeadersCallback callback) override;
+ int ResumeNetworkStart() override;
+ void GetConnectionAttempts(net::ConnectionAttempts* out) const override;
+
+ protected:
+ friend class ThrottlingControllerHelper;
+
+ private:
+ void Fail();
+ bool CheckFailed();
+
+ void IOCallback(const net::CompletionCallback& callback,
+ bool start,
+ int result);
+ int Throttle(const net::CompletionCallback& callback, bool start, int result);
+ void ThrottleCallback(const net::CompletionCallback& callback,
+ int result,
+ int64_t bytes);
+
+ ThrottlingNetworkInterceptor::ThrottleCallback throttle_callback_;
+ int64_t throttled_byte_count_;
+
+ ThrottlingController* controller_;
+ base::WeakPtr<ThrottlingNetworkInterceptor> interceptor_;
+
+ // Modified upload data stream. Should be destructed after |custom_request_|.
+ std::unique_ptr<ThrottlingUploadDataStream> custom_upload_data_stream_;
+
+ // Modified request. Should be destructed after |network_transaction_|.
+ std::unique_ptr<net::HttpRequestInfo> custom_request_;
+
+ // Real network transaction.
+ std::unique_ptr<net::HttpTransaction> network_transaction_;
+
+ const net::HttpRequestInfo* request_;
+
+ // True if Fail was already invoked.
+ bool failed_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrottlingNetworkTransaction);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_TRANSACTION_H_
diff --git a/chromium/services/network/throttling/throttling_network_transaction_factory.cc b/chromium/services/network/throttling/throttling_network_transaction_factory.cc
new file mode 100644
index 00000000000..4008be58155
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_network_transaction_factory.cc
@@ -0,0 +1,46 @@
+// 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/network/throttling/throttling_network_transaction_factory.h"
+
+#include <set>
+#include <string>
+#include <utility>
+
+#include "net/base/net_errors.h"
+#include "net/http/http_network_layer.h"
+#include "net/http/http_network_transaction.h"
+#include "services/network/throttling/throttling_controller.h"
+#include "services/network/throttling/throttling_network_transaction.h"
+
+namespace network {
+
+ThrottlingNetworkTransactionFactory::ThrottlingNetworkTransactionFactory(
+ net::HttpNetworkSession* session)
+ : network_layer_(new net::HttpNetworkLayer(session)) {}
+
+ThrottlingNetworkTransactionFactory::~ThrottlingNetworkTransactionFactory() {}
+
+int ThrottlingNetworkTransactionFactory::CreateTransaction(
+ net::RequestPriority priority,
+ std::unique_ptr<net::HttpTransaction>* trans) {
+ std::unique_ptr<net::HttpTransaction> network_transaction;
+ int rv = network_layer_->CreateTransaction(priority, &network_transaction);
+ if (rv != net::OK) {
+ return rv;
+ }
+ trans->reset(
+ new ThrottlingNetworkTransaction(std::move(network_transaction)));
+ return net::OK;
+}
+
+net::HttpCache* ThrottlingNetworkTransactionFactory::GetCache() {
+ return network_layer_->GetCache();
+}
+
+net::HttpNetworkSession* ThrottlingNetworkTransactionFactory::GetSession() {
+ return network_layer_->GetSession();
+}
+
+} // namespace network
diff --git a/chromium/services/network/throttling/throttling_network_transaction_factory.h b/chromium/services/network/throttling/throttling_network_transaction_factory.h
new file mode 100644
index 00000000000..012d4db4f46
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_network_transaction_factory.h
@@ -0,0 +1,45 @@
+// 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.
+
+#ifndef SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_TRANSACTION_FACTORY_H_
+#define SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_TRANSACTION_FACTORY_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "net/base/request_priority.h"
+#include "net/http/http_transaction_factory.h"
+
+namespace net {
+class HttpCache;
+class HttpNetworkSession;
+class HttpTransaction;
+} // namespace net
+
+namespace network {
+
+// NetworkTransactionFactory wraps HttpNetworkTransactions.
+class COMPONENT_EXPORT(NETWORK_SERVICE) ThrottlingNetworkTransactionFactory
+ : public net::HttpTransactionFactory {
+ public:
+ explicit ThrottlingNetworkTransactionFactory(
+ net::HttpNetworkSession* session);
+ ~ThrottlingNetworkTransactionFactory() override;
+
+ // net::HttpTransactionFactory methods:
+ int CreateTransaction(net::RequestPriority priority,
+ std::unique_ptr<net::HttpTransaction>* trans) override;
+ net::HttpCache* GetCache() override;
+ net::HttpNetworkSession* GetSession() override;
+
+ private:
+ std::unique_ptr<net::HttpTransactionFactory> network_layer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrottlingNetworkTransactionFactory);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_THROTTLING_THROTTLING_NETWORK_TRANSACTION_FACTORY_H_
diff --git a/chromium/services/network/throttling/throttling_upload_data_stream.cc b/chromium/services/network/throttling/throttling_upload_data_stream.cc
new file mode 100644
index 00000000000..20a58117172
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_upload_data_stream.cc
@@ -0,0 +1,95 @@
+// Copyright 2015 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/network/throttling/throttling_upload_data_stream.h"
+
+#include "net/base/net_errors.h"
+
+namespace network {
+
+ThrottlingUploadDataStream::ThrottlingUploadDataStream(
+ net::UploadDataStream* upload_data_stream)
+ : net::UploadDataStream(upload_data_stream->is_chunked(),
+ upload_data_stream->identifier()),
+ throttle_callback_(
+ base::Bind(&ThrottlingUploadDataStream::ThrottleCallback,
+ base::Unretained(this))),
+ throttled_byte_count_(0),
+ upload_data_stream_(upload_data_stream) {}
+
+ThrottlingUploadDataStream::~ThrottlingUploadDataStream() {
+ if (interceptor_)
+ interceptor_->StopThrottle(throttle_callback_);
+}
+
+void ThrottlingUploadDataStream::SetInterceptor(
+ ThrottlingNetworkInterceptor* interceptor) {
+ DCHECK(!interceptor_);
+ if (interceptor)
+ interceptor_ = interceptor->GetWeakPtr();
+}
+
+bool ThrottlingUploadDataStream::IsInMemory() const {
+ return false;
+}
+
+int ThrottlingUploadDataStream::InitInternal(
+ const net::NetLogWithSource& net_log) {
+ throttled_byte_count_ = 0;
+ int result = upload_data_stream_->Init(
+ base::BindOnce(&ThrottlingUploadDataStream::StreamInitCallback,
+ base::Unretained(this)),
+ net_log);
+ if (result == net::OK && !is_chunked())
+ SetSize(upload_data_stream_->size());
+ return result;
+}
+
+void ThrottlingUploadDataStream::StreamInitCallback(int result) {
+ if (!is_chunked())
+ SetSize(upload_data_stream_->size());
+ OnInitCompleted(result);
+}
+
+int ThrottlingUploadDataStream::ReadInternal(net::IOBuffer* buf, int buf_len) {
+ int result = upload_data_stream_->Read(
+ buf, buf_len,
+ base::BindOnce(&ThrottlingUploadDataStream::StreamReadCallback,
+ base::Unretained(this)));
+ return ThrottleRead(result);
+}
+
+void ThrottlingUploadDataStream::StreamReadCallback(int result) {
+ result = ThrottleRead(result);
+ if (result != net::ERR_IO_PENDING)
+ OnReadCompleted(result);
+}
+
+int ThrottlingUploadDataStream::ThrottleRead(int result) {
+ if (is_chunked() && upload_data_stream_->IsEOF())
+ SetIsFinalChunk();
+
+ if (!interceptor_ || result < 0)
+ return result;
+
+ if (result > 0)
+ throttled_byte_count_ += result;
+ return interceptor_->StartThrottle(result, throttled_byte_count_,
+ base::TimeTicks(), false, true,
+ throttle_callback_);
+}
+
+void ThrottlingUploadDataStream::ThrottleCallback(int result, int64_t bytes) {
+ throttled_byte_count_ = bytes;
+ OnReadCompleted(result);
+}
+
+void ThrottlingUploadDataStream::ResetInternal() {
+ upload_data_stream_->Reset();
+ throttled_byte_count_ = 0;
+ if (interceptor_)
+ interceptor_->StopThrottle(throttle_callback_);
+}
+
+} // namespace network
diff --git a/chromium/services/network/throttling/throttling_upload_data_stream.h b/chromium/services/network/throttling/throttling_upload_data_stream.h
new file mode 100644
index 00000000000..1b88136278d
--- /dev/null
+++ b/chromium/services/network/throttling/throttling_upload_data_stream.h
@@ -0,0 +1,55 @@
+// Copyright 2015 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 SERVICES_NETWORK_THROTTLING_THROTTLING_UPLOAD_DATA_STREAM_H_
+#define SERVICES_NETWORK_THROTTLING_THROTTLING_UPLOAD_DATA_STREAM_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "net/base/completion_callback.h"
+#include "net/base/upload_data_stream.h"
+#include "services/network/throttling/throttling_network_interceptor.h"
+
+namespace network {
+
+class ThrottlingNetworkInterceptor;
+
+// ThrottlingUploadData is a wrapper for upload data stream, which proxies
+// methods and throttles after the original method succeeds.
+class ThrottlingUploadDataStream : public net::UploadDataStream {
+ public:
+ // Supplied |upload_data_stream| must outlive this object.
+ explicit ThrottlingUploadDataStream(
+ net::UploadDataStream* upload_data_stream);
+ ~ThrottlingUploadDataStream() override;
+
+ void SetInterceptor(ThrottlingNetworkInterceptor* interceptor);
+
+ private:
+ // net::UploadDataStream implementation.
+ bool IsInMemory() const override;
+ int InitInternal(const net::NetLogWithSource& net_log) override;
+ int ReadInternal(net::IOBuffer* buf, int buf_len) override;
+ void ResetInternal() override;
+
+ void StreamInitCallback(int result);
+ void StreamReadCallback(int result);
+
+ int ThrottleRead(int result);
+ void ThrottleCallback(int result, int64_t bytes);
+
+ ThrottlingNetworkInterceptor::ThrottleCallback throttle_callback_;
+ int64_t throttled_byte_count_;
+
+ net::UploadDataStream* upload_data_stream_;
+ base::WeakPtr<ThrottlingNetworkInterceptor> interceptor_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThrottlingUploadDataStream);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_THROTTLING_THROTTLING_UPLOAD_DATA_STREAM_H_
diff --git a/chromium/services/network/udp_socket.cc b/chromium/services/network/udp_socket.cc
new file mode 100644
index 00000000000..4a19c988d33
--- /dev/null
+++ b/chromium/services/network/udp_socket.cc
@@ -0,0 +1,428 @@
+// Copyright 2018 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/network/udp_socket.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/numerics/checked_math.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/optional.h"
+#include "base/rand_util.h"
+#include "net/base/io_buffer.h"
+#include "net/base/net_errors.h"
+#include "net/base/rand_callback.h"
+#include "net/log/net_log.h"
+#include "net/socket/udp_socket.h"
+
+namespace network {
+
+namespace {
+
+const uint32_t kMaxReadSize = 64 * 1024;
+// The limit on data length for a UDP packet is 65,507 for IPv4 and 65,535 for
+// IPv6.
+const uint32_t kMaxPacketSize = kMaxReadSize - 1;
+
+class SocketWrapperImpl : public UDPSocket::SocketWrapper {
+ public:
+ SocketWrapperImpl(net::DatagramSocket::BindType bind_type,
+ const net::RandIntCallback& rand_int_cb,
+ net::NetLog* net_log,
+ const net::NetLogSource& source)
+ : socket_(bind_type, rand_int_cb, net_log, source) {}
+ ~SocketWrapperImpl() override {}
+
+ int Connect(const net::IPEndPoint& remote_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) override {
+ int result = socket_.Open(remote_addr.GetFamily());
+ if (result == net::OK)
+ result = ConfigureOptions(std::move(options));
+ if (result == net::OK)
+ result = socket_.Connect(remote_addr);
+ if (result == net::OK)
+ result = socket_.GetLocalAddress(local_addr_out);
+
+ if (result != net::OK)
+ socket_.Close();
+ return result;
+ }
+ int Bind(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) override {
+ int result = socket_.Open(local_addr.GetFamily());
+ if (result == net::OK)
+ result = ConfigureOptions(std::move(options));
+ if (result == net::OK)
+ result = socket_.Bind(local_addr);
+ if (result == net::OK)
+ result = socket_.GetLocalAddress(local_addr_out);
+
+ if (result != net::OK)
+ socket_.Close();
+ return result;
+ }
+ int SendTo(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::IPEndPoint& dest_addr,
+ const net::CompletionCallback& callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
+ return socket_.SendTo(buf, buf_len, dest_addr, callback);
+ }
+ int SetBroadcast(bool broadcast) override {
+ return socket_.SetBroadcast(broadcast);
+ }
+ int JoinGroup(const net::IPAddress& group_address) override {
+ return socket_.JoinGroup(group_address);
+ }
+ int LeaveGroup(const net::IPAddress& group_address) override {
+ return socket_.LeaveGroup(group_address);
+ }
+ int Write(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
+ return socket_.Write(buf, buf_len, callback, traffic_annotation);
+ }
+ int RecvFrom(net::IOBuffer* buf,
+ int buf_len,
+ net::IPEndPoint* address,
+ const net::CompletionCallback& callback) override {
+ return socket_.RecvFrom(buf, buf_len, address, callback);
+ }
+
+ private:
+ int ConfigureOptions(mojom::UDPSocketOptionsPtr options) {
+ if (!options)
+ return net::OK;
+ int result = net::OK;
+ if (options->allow_address_reuse)
+ result = socket_.AllowAddressReuse();
+ if (result == net::OK && options->multicast_interface != 0)
+ result = socket_.SetMulticastInterface(options->multicast_interface);
+ if (result == net::OK && !options->multicast_loopback_mode) {
+ result =
+ socket_.SetMulticastLoopbackMode(options->multicast_loopback_mode);
+ }
+ if (result == net::OK && options->multicast_time_to_live != 1) {
+ result = socket_.SetMulticastTimeToLive(
+ base::saturated_cast<int32_t>(options->multicast_time_to_live));
+ }
+ if (result == net::OK && options->receive_buffer_size != 0) {
+ result = socket_.SetReceiveBufferSize(
+ base::saturated_cast<int32_t>(options->receive_buffer_size));
+ }
+ if (result == net::OK && options->send_buffer_size != 0) {
+ result = socket_.SetSendBufferSize(
+ base::saturated_cast<int32_t>(options->send_buffer_size));
+ }
+ return result;
+ }
+
+ net::UDPSocket socket_;
+
+ DISALLOW_COPY_AND_ASSIGN(SocketWrapperImpl);
+};
+
+} // namespace
+
+UDPSocket::PendingSendRequest::PendingSendRequest() {}
+
+UDPSocket::PendingSendRequest::~PendingSendRequest() {}
+
+UDPSocket::UDPSocket(mojom::UDPSocketRequest request,
+ mojom::UDPSocketReceiverPtr receiver)
+ : is_bound_(false),
+ is_connected_(false),
+ receiver_(std::move(receiver)),
+ remaining_recv_slots_(0),
+ binding_(this) {
+ binding_.Bind(std::move(request));
+}
+
+UDPSocket::~UDPSocket() {}
+
+void UDPSocket::set_connection_error_handler(base::OnceClosure handler) {
+ binding_.set_connection_error_handler(std::move(handler));
+}
+
+void UDPSocket::Connect(const net::IPEndPoint& remote_addr,
+ mojom::UDPSocketOptionsPtr options,
+ ConnectCallback callback) {
+ if (IsConnectedOrBound()) {
+ std::move(callback).Run(net::ERR_SOCKET_IS_CONNECTED, base::nullopt);
+ return;
+ }
+ DCHECK(!wrapped_socket_);
+ wrapped_socket_ = CreateSocketWrapper();
+ net::IPEndPoint local_addr_out;
+ int result = wrapped_socket_->Connect(remote_addr, std::move(options),
+ &local_addr_out);
+ if (result != net::OK) {
+ wrapped_socket_.reset();
+ std::move(callback).Run(result, base::nullopt);
+ return;
+ }
+ is_connected_ = true;
+ std::move(callback).Run(result, local_addr_out);
+}
+
+void UDPSocket::Bind(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ BindCallback callback) {
+ if (IsConnectedOrBound()) {
+ std::move(callback).Run(net::ERR_SOCKET_IS_CONNECTED, base::nullopt);
+ return;
+ }
+ DCHECK(!wrapped_socket_);
+ wrapped_socket_ = CreateSocketWrapper();
+ net::IPEndPoint local_addr_out;
+ int result =
+ wrapped_socket_->Bind(local_addr, std::move(options), &local_addr_out);
+ if (result != net::OK) {
+ wrapped_socket_.reset();
+ std::move(callback).Run(result, base::nullopt);
+ return;
+ }
+ is_bound_ = true;
+ std::move(callback).Run(result, local_addr_out);
+}
+
+void UDPSocket::SetBroadcast(bool broadcast, SetBroadcastCallback callback) {
+ if (!is_bound_) {
+ std::move(callback).Run(net::ERR_UNEXPECTED);
+ return;
+ }
+ int net_result = wrapped_socket_->SetBroadcast(broadcast);
+ std::move(callback).Run(net_result);
+}
+
+void UDPSocket::JoinGroup(const net::IPAddress& group_address,
+ JoinGroupCallback callback) {
+ if (!is_bound_) {
+ std::move(callback).Run(net::ERR_UNEXPECTED);
+ return;
+ }
+ int net_result = wrapped_socket_->JoinGroup(group_address);
+ std::move(callback).Run(net_result);
+}
+
+void UDPSocket::LeaveGroup(const net::IPAddress& group_address,
+ LeaveGroupCallback callback) {
+ if (!is_bound_) {
+ std::move(callback).Run(net::ERR_UNEXPECTED);
+ return;
+ }
+ int net_result = wrapped_socket_->LeaveGroup(group_address);
+ std::move(callback).Run(net_result);
+}
+
+void UDPSocket::ReceiveMore(uint32_t num_additional_datagrams) {
+ ReceiveMoreWithBufferSize(num_additional_datagrams, kMaxReadSize);
+}
+
+void UDPSocket::ReceiveMoreWithBufferSize(uint32_t num_additional_datagrams,
+ uint32_t buffer_size) {
+ if (!receiver_)
+ return;
+ if (!IsConnectedOrBound()) {
+ receiver_->OnReceived(net::ERR_UNEXPECTED, base::nullopt, base::nullopt);
+ return;
+ }
+ if (num_additional_datagrams == 0)
+ return;
+ // Check for overflow.
+ if (!base::CheckAdd(remaining_recv_slots_, num_additional_datagrams)
+ .AssignIfValid(&remaining_recv_slots_)) {
+ return;
+ }
+ if (!recvfrom_buffer_) {
+ DCHECK_EQ(num_additional_datagrams, remaining_recv_slots_);
+ DoRecvFrom(std::min(buffer_size, kMaxReadSize));
+ }
+}
+
+void UDPSocket::SendTo(
+ const net::IPEndPoint& dest_addr,
+ base::span<const uint8_t> data,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ SendToCallback callback) {
+ if (!is_bound_) {
+ std::move(callback).Run(net::ERR_UNEXPECTED);
+ return;
+ }
+ DoSendToOrWrite(
+ &dest_addr, data,
+ static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
+ std::move(callback));
+}
+
+void UDPSocket::Send(
+ base::span<const uint8_t> data,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ SendCallback callback) {
+ if (!is_connected_) {
+ std::move(callback).Run(net::ERR_UNEXPECTED);
+ return;
+ }
+ DoSendToOrWrite(
+ nullptr, data,
+ static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
+ std::move(callback));
+}
+
+void UDPSocket::Close() {
+ if (!IsConnectedOrBound()) {
+ return;
+ }
+ is_connected_ = false;
+ is_bound_ = false;
+ recvfrom_buffer_ = nullptr;
+ send_callback_.Reset();
+ send_buffer_ = nullptr;
+ remaining_recv_slots_ = 0;
+ wrapped_socket_.reset();
+}
+
+std::unique_ptr<UDPSocket::SocketWrapper> UDPSocket::CreateSocketWrapper()
+ const {
+ return std::make_unique<SocketWrapperImpl>(
+ net::DatagramSocket::RANDOM_BIND, base::BindRepeating(&base::RandInt),
+ nullptr, net::NetLogSource());
+}
+
+bool UDPSocket::IsConnectedOrBound() const {
+ return is_connected_ || is_bound_;
+}
+
+void UDPSocket::DoRecvFrom(uint32_t buffer_size) {
+ DCHECK(receiver_);
+ DCHECK(!recvfrom_buffer_);
+ DCHECK_GT(remaining_recv_slots_, 0u);
+ DCHECK_GE(kMaxReadSize, buffer_size);
+
+ recvfrom_buffer_ = new net::IOBuffer(static_cast<size_t>(buffer_size));
+
+ // base::Unretained(this) is safe because socket is owned by |this|.
+ int net_result = wrapped_socket_->RecvFrom(
+ recvfrom_buffer_.get(), buffer_size, &recvfrom_address_,
+ base::BindRepeating(&UDPSocket::OnRecvFromCompleted,
+ base::Unretained(this), buffer_size));
+ if (net_result != net::ERR_IO_PENDING)
+ OnRecvFromCompleted(buffer_size, net_result);
+}
+
+void UDPSocket::DoSendToOrWrite(
+ const net::IPEndPoint* dest_addr,
+ const base::span<const uint8_t>& data,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ SendToCallback callback) {
+ if (pending_send_requests_.size() >= kMaxPendingSendRequests) {
+ std::move(callback).Run(net::ERR_INSUFFICIENT_RESOURCES);
+ return;
+ }
+
+ if (data.size() > kMaxPacketSize) {
+ std::move(callback).Run(net::ERR_MSG_TOO_BIG);
+ return;
+ }
+
+ // |data| points to a range of bytes in the received message and will be
+ // freed when this method returns, so copy out the bytes now.
+ scoped_refptr<net::IOBufferWithSize> buffer =
+ new net::IOBufferWithSize(data.size());
+ memcpy(buffer.get()->data(), data.begin(), data.size());
+
+ if (send_buffer_.get()) {
+ auto request = std::make_unique<PendingSendRequest>();
+ if (dest_addr)
+ request->addr = std::make_unique<net::IPEndPoint>(*dest_addr);
+ request->data = buffer;
+ request->traffic_annotation =
+ net::MutableNetworkTrafficAnnotationTag(traffic_annotation);
+ request->callback = std::move(callback);
+ pending_send_requests_.push_back(std::move(request));
+ return;
+ }
+
+ DoSendToOrWriteBuffer(dest_addr, buffer, traffic_annotation,
+ std::move(callback));
+}
+
+void UDPSocket::DoSendToOrWriteBuffer(
+ const net::IPEndPoint* dest_addr,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ SendToCallback callback) {
+ DCHECK(!send_buffer_);
+ DCHECK(send_callback_.is_null());
+
+ send_buffer_ = buffer;
+ send_callback_ = std::move(callback);
+ // base::Unretained(this) is safe because socket is owned by |this|.
+ int net_result;
+ if (dest_addr) {
+ net_result = wrapped_socket_->SendTo(
+ buffer.get(), buffer->size(), *dest_addr,
+ base::BindRepeating(&UDPSocket::OnSendToCompleted,
+ base::Unretained(this)),
+ traffic_annotation);
+ } else {
+ net_result = wrapped_socket_->Write(
+ buffer.get(), buffer->size(),
+ base::BindRepeating(&UDPSocket::OnSendToCompleted,
+ base::Unretained(this)),
+ traffic_annotation);
+ }
+ if (net_result != net::ERR_IO_PENDING)
+ OnSendToCompleted(net_result);
+}
+
+void UDPSocket::OnRecvFromCompleted(uint32_t buffer_size, int net_result) {
+ DCHECK(recvfrom_buffer_);
+
+ if (net_result >= 0) {
+ receiver_->OnReceived(
+ net::OK,
+ is_bound_ ? base::make_optional(recvfrom_address_) : base::nullopt,
+ base::span<const uint8_t>(
+ reinterpret_cast<const uint8_t*>(recvfrom_buffer_->data()),
+ static_cast<size_t>(net_result)));
+ } else {
+ receiver_->OnReceived(net_result, base::nullopt, base::nullopt);
+ }
+ recvfrom_buffer_ = nullptr;
+ DCHECK_GT(remaining_recv_slots_, 0u);
+ remaining_recv_slots_--;
+ if (remaining_recv_slots_ > 0)
+ DoRecvFrom(buffer_size);
+}
+
+void UDPSocket::OnSendToCompleted(int net_result) {
+ DCHECK(send_buffer_.get());
+ DCHECK(!send_callback_.is_null());
+
+ if (net_result > net::OK)
+ net_result = net::OK;
+ send_buffer_ = nullptr;
+ std::move(send_callback_).Run(net_result);
+
+ if (pending_send_requests_.empty())
+ return;
+ std::unique_ptr<PendingSendRequest> request =
+ std::move(pending_send_requests_.front());
+ pending_send_requests_.pop_front();
+ DoSendToOrWriteBuffer(request->addr.get(), request->data,
+ static_cast<net::NetworkTrafficAnnotationTag>(
+ request->traffic_annotation),
+ std::move(request->callback));
+}
+
+} // namespace network
diff --git a/chromium/services/network/udp_socket.h b/chromium/services/network/udp_socket.h
new file mode 100644
index 00000000000..8f5ae103cfe
--- /dev/null
+++ b/chromium/services/network/udp_socket.h
@@ -0,0 +1,176 @@
+// Copyright 2018 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 SERVICES_NETWORK_UDP_SOCKET_H_
+#define SERVICES_NETWORK_UDP_SOCKET_H_
+
+#include <deque>
+#include <memory>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "net/base/address_family.h"
+#include "net/base/completion_callback.h"
+#include "net/base/ip_endpoint.h"
+#include "net/interfaces/address_family.mojom.h"
+#include "net/interfaces/ip_endpoint.mojom.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
+
+namespace net {
+class IOBuffer;
+class IOBufferWithSize;
+} // namespace net
+
+namespace network {
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) UDPSocket : public mojom::UDPSocket {
+ public:
+ // Number of Send()/SendTo() requests that are queued internally. Public for
+ // testing.
+ static const uint32_t kMaxPendingSendRequests = 32;
+ // A socket wrapper class that allows tests to substitute the default
+ // implementation (implemented using net::UDPSocket) with a test
+ // implementation.
+ class SocketWrapper {
+ public:
+ virtual ~SocketWrapper() {}
+ // This wrapper class forwards the functions to a concrete udp socket
+ // implementation. Please refer to udp_socket_posix.h/udp_socket_win.h for
+ // definitions.
+ virtual int Connect(const net::IPEndPoint& remote_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) = 0;
+ virtual int Bind(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) = 0;
+ virtual int SendTo(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::IPEndPoint& dest_addr,
+ const net::CompletionCallback& callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0;
+ virtual int Write(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) = 0;
+ virtual int SetBroadcast(bool broadcast) = 0;
+ virtual int JoinGroup(const net::IPAddress& group_address) = 0;
+ virtual int LeaveGroup(const net::IPAddress& group_address) = 0;
+ virtual int RecvFrom(net::IOBuffer* buf,
+ int buf_len,
+ net::IPEndPoint* address,
+ const net::CompletionCallback& callback) = 0;
+ };
+
+ UDPSocket(mojom::UDPSocketRequest request,
+ mojom::UDPSocketReceiverPtr receiver);
+ ~UDPSocket() override;
+
+ // Sets connection error handler.
+ void set_connection_error_handler(base::OnceClosure handler);
+
+ // UDPSocket implementation.
+ void Connect(const net::IPEndPoint& remote_addr,
+ mojom::UDPSocketOptionsPtr options,
+ ConnectCallback callback) override;
+ void Bind(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ BindCallback callback) override;
+ void SetBroadcast(bool broadcast, SetBroadcastCallback callback) override;
+ void JoinGroup(const net::IPAddress& group_address,
+ JoinGroupCallback callback) override;
+ void LeaveGroup(const net::IPAddress& group_address,
+ LeaveGroupCallback callback) override;
+ void ReceiveMore(uint32_t num_additional_datagrams) override;
+ void ReceiveMoreWithBufferSize(uint32_t num_additional_datagrams,
+ uint32_t buffer_size) override;
+ void SendTo(const net::IPEndPoint& dest_addr,
+ base::span<const uint8_t> data,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ SendToCallback callback) override;
+ void Send(base::span<const uint8_t> data,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
+ SendCallback callback) override;
+ void Close() override;
+
+ private:
+ friend class UDPSocketTest;
+
+ // Represents a pending Send()/SendTo() request that is yet to be sent to the
+ // |socket_|. In the case of Send(), |addr| will be not filled in.
+ struct PendingSendRequest {
+ PendingSendRequest();
+ ~PendingSendRequest();
+
+ std::unique_ptr<net::IPEndPoint> addr;
+ net::MutableNetworkTrafficAnnotationTag traffic_annotation;
+ scoped_refptr<net::IOBufferWithSize> data;
+ SendToCallback callback;
+ };
+
+ // Helper method to create a new SocketWrapper.
+ std::unique_ptr<UDPSocket::SocketWrapper> CreateSocketWrapper() const;
+
+ // Returns whether a successful Connect() or Bind() has been executed.
+ bool IsConnectedOrBound() const;
+
+ void DoRecvFrom(uint32_t buffer_size);
+ void DoSendToOrWrite(
+ const net::IPEndPoint* dest_addr,
+ const base::span<const uint8_t>& data,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ SendToCallback callback);
+ void DoSendToOrWriteBuffer(
+ const net::IPEndPoint* dest_addr,
+ scoped_refptr<net::IOBufferWithSize> buffer,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ SendToCallback callback);
+
+ void OnRecvFromCompleted(uint32_t buffer_size, int net_result);
+ void OnSendToCompleted(int net_result);
+
+ // Whether a Bind() has been successfully executed.
+ bool is_bound_;
+
+ // Whether a Connect() has been successfully executed.
+ bool is_connected_;
+
+ // The interface which gets data from fulfilled receive requests.
+ mojom::UDPSocketReceiverPtr receiver_;
+
+ std::unique_ptr<SocketWrapper> wrapped_socket_;
+
+ // Non-null when there is a pending RecvFrom operation on socket.
+ scoped_refptr<net::IOBuffer> recvfrom_buffer_;
+
+ // Non-null when there is a pending Send/SendTo operation on socket.
+ scoped_refptr<net::IOBufferWithSize> send_buffer_;
+ SendToCallback send_callback_;
+
+ // The address of the sender of a received packet. This address might not be
+ // filled if an error occurred during the receiving of the packet.
+ net::IPEndPoint recvfrom_address_;
+
+ // How many more packets the client side expects to receive.
+ uint32_t remaining_recv_slots_;
+
+ // The queue owns the PendingSendRequest instances.
+ base::circular_deque<std::unique_ptr<PendingSendRequest>>
+ pending_send_requests_;
+
+ mojo::Binding<mojom::UDPSocket> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(UDPSocket);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_UDP_SOCKET_H_
diff --git a/chromium/services/network/udp_socket_factory.cc b/chromium/services/network/udp_socket_factory.cc
new file mode 100644
index 00000000000..54ac3e46e12
--- /dev/null
+++ b/chromium/services/network/udp_socket_factory.cc
@@ -0,0 +1,40 @@
+// Copyright 2018 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/network/udp_socket_factory.h"
+
+#include <utility>
+
+#include "base/memory/ptr_util.h"
+#include "base/optional.h"
+#include "net/base/net_errors.h"
+#include "services/network/udp_socket.h"
+
+namespace network {
+
+UDPSocketFactory::UDPSocketFactory() {}
+
+UDPSocketFactory::~UDPSocketFactory() {}
+
+void UDPSocketFactory::CreateUDPSocket(mojom::UDPSocketRequest request,
+ mojom::UDPSocketReceiverPtr receiver) {
+ auto socket =
+ std::make_unique<UDPSocket>(std::move(request), std::move(receiver));
+ // base::Unretained is safe as the destruction of |this| will also destroy
+ // |udp_sockets_| which owns this socket.
+ socket->set_connection_error_handler(
+ base::BindOnce(&UDPSocketFactory::OnPipeBroken, base::Unretained(this),
+ base::Unretained(socket.get())));
+ udp_sockets_.push_back(std::move(socket));
+}
+
+void UDPSocketFactory::OnPipeBroken(UDPSocket* socket) {
+ udp_sockets_.erase(
+ std::find_if(udp_sockets_.begin(), udp_sockets_.end(),
+ [socket](const std::unique_ptr<network::UDPSocket>& ptr) {
+ return ptr.get() == socket;
+ }));
+}
+
+} // namespace network
diff --git a/chromium/services/network/udp_socket_factory.h b/chromium/services/network/udp_socket_factory.h
new file mode 100644
index 00000000000..58d47e83f30
--- /dev/null
+++ b/chromium/services/network/udp_socket_factory.h
@@ -0,0 +1,41 @@
+// Copyright 2018 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 SERVICES_NETWORK_UDP_SOCKET_FACTORY_H_
+#define SERVICES_NETWORK_UDP_SOCKET_FACTORY_H_
+
+#include <memory>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
+
+namespace network {
+
+class UDPSocket;
+
+// Helper class that handles UDPSocketRequest. It takes care of destroying the
+// UDPSocket implementation instances when mojo pipes are broken.
+class COMPONENT_EXPORT(NETWORK_SERVICE) UDPSocketFactory {
+ public:
+ UDPSocketFactory();
+ virtual ~UDPSocketFactory();
+
+ void CreateUDPSocket(mojom::UDPSocketRequest request,
+ mojom::UDPSocketReceiverPtr receiver);
+
+ protected:
+ // Handles connection errors. This is virtual for testing.
+ virtual void OnPipeBroken(UDPSocket* client);
+
+ private:
+ std::vector<std::unique_ptr<UDPSocket>> udp_sockets_;
+
+ DISALLOW_COPY_AND_ASSIGN(UDPSocketFactory);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_UDP_SOCKET_FACTORY_H_
diff --git a/chromium/services/network/udp_socket_factory_unittest.cc b/chromium/services/network/udp_socket_factory_unittest.cc
new file mode 100644
index 00000000000..2076e6e5312
--- /dev/null
+++ b/chromium/services/network/udp_socket_factory_unittest.cc
@@ -0,0 +1,63 @@
+// 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 <utility>
+
+#include "services/network/udp_socket_factory.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "net/base/net_errors.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+class UDPSocketFactoryTest : public testing::Test {
+ public:
+ UDPSocketFactoryTest() {}
+ ~UDPSocketFactoryTest() override {}
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ DISALLOW_COPY_AND_ASSIGN(UDPSocketFactoryTest);
+};
+
+class TestUDPSocketFactory : public UDPSocketFactory {
+ public:
+ TestUDPSocketFactory() {}
+ ~TestUDPSocketFactory() override {}
+
+ void WaitUntilPipeBroken() { run_loop_.Run(); }
+
+ private:
+ // UDPSocketFactory implementation:
+ void OnPipeBroken(UDPSocket* client) override {
+ UDPSocketFactory::OnPipeBroken(client);
+ run_loop_.Quit();
+ }
+
+ base::RunLoop run_loop_;
+};
+// Tests that when client end of the pipe is closed, the factory implementation
+// cleans up the server side of the pipe.
+TEST_F(UDPSocketFactoryTest, ConnectionError) {
+ TestUDPSocketFactory factory;
+
+ mojom::UDPSocketReceiverPtr receiver_interface_ptr;
+ mojom::UDPSocketPtr socket_ptr;
+
+ factory.CreateUDPSocket(mojo::MakeRequest(&socket_ptr),
+ std::move(receiver_interface_ptr));
+
+ // Close client side of the pipe.
+ socket_ptr.reset();
+
+ factory.WaitUntilPipeBroken();
+}
+
+} // namespace network
diff --git a/chromium/services/network/udp_socket_test_util.cc b/chromium/services/network/udp_socket_test_util.cc
new file mode 100644
index 00000000000..881ab86fed0
--- /dev/null
+++ b/chromium/services/network/udp_socket_test_util.cc
@@ -0,0 +1,198 @@
+// 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 "services/network/udp_socket_test_util.h"
+
+#include <utility>
+
+#include "base/run_loop.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace test {
+
+UDPSocketTestHelper::UDPSocketTestHelper(mojom::UDPSocketPtr* socket)
+ : socket_(socket) {}
+
+UDPSocketTestHelper::~UDPSocketTestHelper() {}
+
+int UDPSocketTestHelper::ConnectSync(const net::IPEndPoint& remote_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) {
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ socket_->get()->Connect(
+ remote_addr, std::move(options),
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int* result_out,
+ net::IPEndPoint* local_addr_out, int result,
+ const base::Optional<net::IPEndPoint>& local_addr) {
+ *result_out = result;
+ if (local_addr) {
+ *local_addr_out = local_addr.value();
+ }
+ run_loop->Quit();
+ },
+ base::Unretained(&run_loop), base::Unretained(&net_error),
+ base::Unretained(local_addr_out)));
+ run_loop.Run();
+ return net_error;
+}
+
+int UDPSocketTestHelper::BindSync(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) {
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ socket_->get()->Bind(
+ local_addr, std::move(options),
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int* result_out,
+ net::IPEndPoint* local_addr_out, int result,
+ const base::Optional<net::IPEndPoint>& local_addr) {
+ *result_out = result;
+ if (local_addr) {
+ *local_addr_out = local_addr.value();
+ }
+ run_loop->Quit();
+ },
+ base::Unretained(&run_loop), base::Unretained(&net_error),
+ base::Unretained(local_addr_out)));
+ run_loop.Run();
+ return net_error;
+}
+
+int UDPSocketTestHelper::SendToSync(const net::IPEndPoint& remote_addr,
+ const std::vector<uint8_t>& input) {
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ socket_->get()->SendTo(
+ remote_addr, input,
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int* result_out, int result) {
+ *result_out = result;
+ run_loop->Quit();
+ },
+ base::Unretained(&run_loop), base::Unretained(&net_error)));
+ run_loop.Run();
+ return net_error;
+}
+
+int UDPSocketTestHelper::SendSync(const std::vector<uint8_t>& input) {
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ socket_->get()->Send(
+ input,
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int* result_out, int result) {
+ *result_out = result;
+ run_loop->Quit();
+ },
+ base::Unretained(&run_loop), base::Unretained(&net_error)));
+ run_loop.Run();
+ return net_error;
+}
+
+int UDPSocketTestHelper::SetBroadcastSync(bool broadcast) {
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ socket_->get()->SetBroadcast(
+ broadcast,
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int* result_out, int result) {
+ *result_out = result;
+ run_loop->Quit();
+ },
+ base::Unretained(&run_loop), base::Unretained(&net_error)));
+ run_loop.Run();
+ return net_error;
+}
+
+int UDPSocketTestHelper::JoinGroupSync(const net::IPAddress& group_address) {
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ socket_->get()->JoinGroup(
+ group_address,
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int* result_out, int result) {
+ *result_out = result;
+ run_loop->Quit();
+ },
+ base::Unretained(&run_loop), base::Unretained(&net_error)));
+ run_loop.Run();
+ return net_error;
+}
+
+int UDPSocketTestHelper::LeaveGroupSync(const net::IPAddress& group_address) {
+ base::RunLoop run_loop;
+ int net_error = net::ERR_FAILED;
+ socket_->get()->LeaveGroup(
+ group_address,
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int* result_out, int result) {
+ *result_out = result;
+ run_loop->Quit();
+ },
+ base::Unretained(&run_loop), base::Unretained(&net_error)));
+ run_loop.Run();
+ return net_error;
+}
+
+UDPSocketReceiverImpl::ReceivedResult::ReceivedResult(
+ int net_error_arg,
+ const base::Optional<net::IPEndPoint>& src_addr_arg,
+ base::Optional<std::vector<uint8_t>> data_arg)
+ : net_error(net_error_arg),
+ src_addr(src_addr_arg),
+ data(std::move(data_arg)) {}
+
+UDPSocketReceiverImpl::ReceivedResult::ReceivedResult(
+ const ReceivedResult& other) = default;
+
+UDPSocketReceiverImpl::ReceivedResult::~ReceivedResult() {}
+
+UDPSocketReceiverImpl::UDPSocketReceiverImpl()
+ : run_loop_(std::make_unique<base::RunLoop>()),
+ expected_receive_count_(0) {}
+
+UDPSocketReceiverImpl::~UDPSocketReceiverImpl() {}
+
+void UDPSocketReceiverImpl::WaitForReceivedResults(size_t count) {
+ DCHECK_LE(results_.size(), count);
+ DCHECK_EQ(0u, expected_receive_count_);
+
+ if (results_.size() == count)
+ return;
+
+ expected_receive_count_ = count;
+ run_loop_->Run();
+ run_loop_ = std::make_unique<base::RunLoop>();
+}
+
+void UDPSocketReceiverImpl::OnReceived(
+ int32_t result,
+ const base::Optional<net::IPEndPoint>& src_addr,
+ base::Optional<base::span<const uint8_t>> data) {
+ // OnReceive() API contracts specifies that this method will not be called
+ // with a |result| that is > 0.
+ DCHECK_GE(0, result);
+ DCHECK(result < 0 || data);
+
+ results_.emplace_back(result, src_addr,
+ data ? base::make_optional(std::vector<uint8_t>(
+ data.value().begin(), data.value().end()))
+ : base::nullopt);
+ if (results_.size() == expected_receive_count_) {
+ expected_receive_count_ = 0;
+ run_loop_->Quit();
+ }
+}
+
+} // namespace test
+
+} // namespace network
diff --git a/chromium/services/network/udp_socket_test_util.h b/chromium/services/network/udp_socket_test_util.h
new file mode 100644
index 00000000000..579128f972c
--- /dev/null
+++ b/chromium/services/network/udp_socket_test_util.h
@@ -0,0 +1,85 @@
+// 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 SERVICES_NETWORK_UDP_SOCKET_TEST_UTIL_H_
+#define SERVICES_NETWORK_UDP_SOCKET_TEST_UTIL_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/containers/span.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "base/run_loop.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
+
+namespace network {
+
+namespace test {
+
+// Helper functions to invoke the corresponding mojo APIs and wait for
+// completion.
+class UDPSocketTestHelper {
+ public:
+ explicit UDPSocketTestHelper(mojom::UDPSocketPtr* socket);
+ ~UDPSocketTestHelper();
+ int ConnectSync(const net::IPEndPoint& remote_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out);
+ int BindSync(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out);
+ int SendToSync(const net::IPEndPoint& remote_addr,
+ const std::vector<uint8_t>& input);
+ int SendSync(const std::vector<uint8_t>& input);
+ int SetBroadcastSync(bool broadcast);
+ int JoinGroupSync(const net::IPAddress& group_address);
+ int LeaveGroupSync(const net::IPAddress& group_address);
+
+ private:
+ mojom::UDPSocketPtr* socket_;
+};
+
+// An implementation of mojom::UDPSocketReceiver that records received results.
+class UDPSocketReceiverImpl : public mojom::UDPSocketReceiver {
+ public:
+ struct ReceivedResult {
+ ReceivedResult(int net_error_arg,
+ const base::Optional<net::IPEndPoint>& src_addr_arg,
+ base::Optional<std::vector<uint8_t>> data_arg);
+ ReceivedResult(const ReceivedResult& other);
+ ~ReceivedResult();
+
+ int net_error;
+ base::Optional<net::IPEndPoint> src_addr;
+ base::Optional<std::vector<uint8_t>> data;
+ };
+
+ UDPSocketReceiverImpl();
+ ~UDPSocketReceiverImpl() override;
+
+ const std::vector<ReceivedResult>& results() const { return results_; }
+
+ void WaitForReceivedResults(size_t count);
+
+ private:
+ void OnReceived(int32_t result,
+ const base::Optional<net::IPEndPoint>& src_addr,
+ base::Optional<base::span<const uint8_t>> data) override;
+ std::unique_ptr<base::RunLoop> run_loop_;
+ std::vector<ReceivedResult> results_;
+ size_t expected_receive_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(UDPSocketReceiverImpl);
+};
+
+} // namespace test
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_UDP_SOCKET_TEST_UTIL_H_
diff --git a/chromium/services/network/udp_socket_unittest.cc b/chromium/services/network/udp_socket_unittest.cc
new file mode 100644
index 00000000000..0fa16b75861
--- /dev/null
+++ b/chromium/services/network/udp_socket_unittest.cc
@@ -0,0 +1,747 @@
+// Copyright 2018 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 <stddef.h>
+#include <stdint.h>
+
+#include <limits>
+#include <utility>
+
+#include "services/network/udp_socket.h"
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "net/base/net_errors.h"
+#include "net/socket/udp_socket.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "services/network/public/mojom/udp_socket.mojom.h"
+#include "services/network/udp_socket_test_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+
+namespace {
+
+const size_t kDatagramSize = 255;
+
+class SocketWrapperTestImpl : public UDPSocket::SocketWrapper {
+ public:
+ SocketWrapperTestImpl() {}
+ ~SocketWrapperTestImpl() override {}
+
+ int Connect(const net::IPEndPoint& remote_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) override {
+ NOTREACHED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+ int Bind(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) override {
+ NOTREACHED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+ int SendTo(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::IPEndPoint& dest_addr,
+ const net::CompletionCallback& callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
+ NOTREACHED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+ int SetBroadcast(bool broadcast) override {
+ NOTREACHED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+ int JoinGroup(const net::IPAddress& group_address) override {
+ NOTREACHED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+ int LeaveGroup(const net::IPAddress& group_address) override {
+ NOTREACHED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+ int Write(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::CompletionCallback& callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
+ NOTREACHED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+ int RecvFrom(net::IOBuffer* buf,
+ int buf_len,
+ net::IPEndPoint* address,
+ const net::CompletionCallback& callback) override {
+ NOTREACHED();
+ return net::ERR_NOT_IMPLEMENTED;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(SocketWrapperTestImpl);
+};
+
+net::IPEndPoint GetLocalHostWithAnyPort() {
+ return net::IPEndPoint(net::IPAddress(127, 0, 0, 1), 0);
+}
+
+std::vector<uint8_t> CreateTestMessage(uint8_t initial, size_t size) {
+ std::vector<uint8_t> array(size);
+ for (size_t i = 0; i < size; ++i)
+ array[i] = static_cast<uint8_t>((i + initial) % 256);
+ return array;
+}
+
+// A Mock UDPSocket that always returns net::ERR_IO_PENDING for SendTo()s.
+class HangingUDPSocket : public SocketWrapperTestImpl {
+ public:
+ HangingUDPSocket() {}
+
+ // SocketWrapperTestImpl implementation.
+ int Bind(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) override {
+ return net::OK;
+ }
+ int SendTo(
+ net::IOBuffer* buf,
+ int buf_len,
+ const net::IPEndPoint& address,
+ const net::CompletionCallback& callback,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation) override {
+ EXPECT_EQ(expected_data_,
+ std::vector<unsigned char>(buf->data(), buf->data() + buf_len));
+ if (should_complete_requests_)
+ return net::OK;
+ pending_io_buffers_.push_back(buf);
+ pending_io_buffer_lengths_.push_back(buf_len);
+ pending_send_requests_.push_back(callback);
+ return net::ERR_IO_PENDING;
+ }
+
+ void set_expected_data(std::vector<uint8_t> expected_data) {
+ expected_data_ = expected_data;
+ }
+
+ const std::vector<net::IOBuffer*>& pending_io_buffers() const {
+ return pending_io_buffers_;
+ }
+
+ const std::vector<int>& pending_io_buffer_lengths() const {
+ return pending_io_buffer_lengths_;
+ }
+
+ // Completes all pending requests.
+ void CompleteAllPendingRequests() {
+ should_complete_requests_ = true;
+ for (auto request : pending_send_requests_) {
+ request.Run(net::OK);
+ }
+ pending_send_requests_.clear();
+ }
+
+ private:
+ std::vector<uint8_t> expected_data_;
+ bool should_complete_requests_ = false;
+ std::vector<net::IOBuffer*> pending_io_buffers_;
+ std::vector<int> pending_io_buffer_lengths_;
+ std::vector<net::CompletionCallback> pending_send_requests_;
+};
+
+// A Mock UDPSocket that returns 0 byte read.
+class ZeroByteReadUDPSocket : public SocketWrapperTestImpl {
+ public:
+ ZeroByteReadUDPSocket() {}
+ int Bind(const net::IPEndPoint& local_addr,
+ mojom::UDPSocketOptionsPtr options,
+ net::IPEndPoint* local_addr_out) override {
+ return net::OK;
+ }
+ int RecvFrom(net::IOBuffer* buf,
+ int buf_len,
+ net::IPEndPoint* address,
+ const net::CompletionCallback& callback) override {
+ *address = GetLocalHostWithAnyPort();
+ return 0;
+ }
+};
+
+} // namespace
+
+class UDPSocketTest : public testing::Test {
+ public:
+ UDPSocketTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO) {}
+ ~UDPSocketTest() override {}
+
+ void SetWrappedSocket(
+ UDPSocket* socket,
+ std::unique_ptr<UDPSocket::SocketWrapper> socket_wrapper) {
+ socket->wrapped_socket_ = std::move(socket_wrapper);
+ }
+
+ uint32_t GetRemainingRecvSlots(UDPSocket* socket) {
+ return socket->remaining_recv_slots_;
+ }
+
+ private:
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+
+ DISALLOW_COPY_AND_ASSIGN(UDPSocketTest);
+};
+
+TEST_F(UDPSocketTest, Settings) {
+ mojom::UDPSocketPtr socket_ptr;
+ UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+ net::IPEndPoint server_addr;
+ net::IPEndPoint any_port(GetLocalHostWithAnyPort());
+
+ test::UDPSocketTestHelper helper(&socket_ptr);
+ net::IPEndPoint local_addr;
+ mojom::UDPSocketOptionsPtr options = network::mojom::UDPSocketOptions::New();
+ options->send_buffer_size = 1024;
+ options->receive_buffer_size = 2048;
+ ASSERT_EQ(net::OK,
+ helper.BindSync(any_port, std::move(options), &local_addr));
+ EXPECT_NE(local_addr.ToString(), any_port.ToString());
+}
+
+// Tests that Send() is used after Bind() is not supported. Send() should only
+// be used after Connect().
+TEST_F(UDPSocketTest, TestSendWithBind) {
+ mojom::UDPSocketPtr socket_ptr;
+ UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+
+ // Bind() the socket.
+ test::UDPSocketTestHelper helper(&socket_ptr);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ // Connect() has not been used, so Send() is not supported.
+ std::vector<uint8_t> test_msg{1};
+ int result = helper.SendSync(test_msg);
+ EXPECT_EQ(net::ERR_UNEXPECTED, result);
+}
+
+// Tests that when SendTo() is used after Connect() is not supported. SendTo()
+// should only be used after Bind().
+TEST_F(UDPSocketTest, TestSendToWithConnect) {
+ // Create a server socket to listen for incoming datagrams.
+ test::UDPSocketReceiverImpl receiver;
+ mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
+ mojom::UDPSocketReceiverPtr receiver_interface_ptr;
+ receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
+
+ mojom::UDPSocketPtr server_socket;
+ UDPSocket impl(mojo::MakeRequest(&server_socket),
+ std::move(receiver_interface_ptr));
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&server_socket);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ // Create a client socket to send datagrams.
+ mojom::UDPSocketPtr client_socket;
+ UDPSocket client_impl(mojo::MakeRequest(&client_socket), nullptr);
+ net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper client_helper(&client_socket);
+ ASSERT_EQ(net::OK,
+ client_helper.ConnectSync(server_addr, nullptr, &client_addr));
+
+ std::vector<uint8_t> test_msg({1});
+ int result = client_helper.SendToSync(server_addr, test_msg);
+ EXPECT_EQ(net::ERR_UNEXPECTED, result);
+}
+
+// Tests that the sequence of calling Bind()/Connect() and setters is
+// important.
+TEST_F(UDPSocketTest, TestUnexpectedSequences) {
+ mojom::UDPSocketPtr socket_ptr;
+ UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+ test::UDPSocketTestHelper helper(&socket_ptr);
+ net::IPEndPoint local_addr(GetLocalHostWithAnyPort());
+
+ // Now these Setters should not work before Bind().
+ EXPECT_EQ(net::ERR_UNEXPECTED, helper.SetBroadcastSync(true));
+
+ // Now Bind() the socket.
+ ASSERT_EQ(net::OK, helper.BindSync(local_addr, nullptr, &local_addr));
+
+ // Calling Connect() after Bind() should fail because they can't be both used.
+ ASSERT_EQ(net::ERR_SOCKET_IS_CONNECTED,
+ helper.ConnectSync(local_addr, nullptr, &local_addr));
+
+ // Now Close() the socket.
+ socket_ptr->Close();
+
+ // Re-Bind() is okay.
+ ASSERT_EQ(net::OK, helper.BindSync(local_addr, nullptr, &local_addr));
+}
+
+// Tests that if the underlying socket implementation's Send() returned
+// ERR_IO_PENDING, udp_socket.cc doesn't free the send buffer.
+TEST_F(UDPSocketTest, TestBufferValid) {
+ mojom::UDPSocketPtr socket_ptr;
+ UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&socket_ptr);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ HangingUDPSocket* socket_raw_ptr = new HangingUDPSocket();
+ SetWrappedSocket(&impl, base::WrapUnique(socket_raw_ptr));
+
+ std::vector<uint8_t> test_msg(CreateTestMessage(0, kDatagramSize));
+ socket_raw_ptr->set_expected_data(test_msg);
+ base::RunLoop run_loop;
+ socket_ptr->SendTo(
+ GetLocalHostWithAnyPort(), test_msg,
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int result) {
+ EXPECT_EQ(net::OK, result);
+ run_loop->Quit();
+ },
+ base::Unretained(&run_loop)));
+
+ socket_ptr.FlushForTesting();
+
+ ASSERT_EQ(1u, socket_raw_ptr->pending_io_buffers().size());
+ ASSERT_EQ(1u, socket_raw_ptr->pending_io_buffer_lengths().size());
+ // Make sure the caller of HangingUDPSocket doesn't destroy the send buffer,
+ // and that buffer still contains the exact same data.
+ net::IOBuffer* buf = socket_raw_ptr->pending_io_buffers()[0];
+ int buf_len = socket_raw_ptr->pending_io_buffer_lengths()[0];
+ EXPECT_EQ(test_msg,
+ std::vector<unsigned char>(buf->data(), buf->data() + buf_len));
+}
+
+// Test that exercises the queuing of send requests and makes sure
+// ERR_INSUFFICIENT_RESOURCES is returned appropriately.
+TEST_F(UDPSocketTest, TestInsufficientResources) {
+ mojom::UDPSocketPtr socket_ptr;
+ UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+
+ const size_t kQueueSize = UDPSocket::kMaxPendingSendRequests;
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&socket_ptr);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ HangingUDPSocket* socket_raw_ptr = new HangingUDPSocket();
+ SetWrappedSocket(&impl, base::WrapUnique(socket_raw_ptr));
+
+ std::vector<uint8_t> test_msg(CreateTestMessage(0, kDatagramSize));
+ socket_raw_ptr->set_expected_data(test_msg);
+ // Send |kQueueSize| + 1 datagrams in a row, so the queue is filled up.
+ std::vector<std::unique_ptr<base::RunLoop>> run_loops;
+ for (size_t i = 0; i < kQueueSize + 1; ++i) {
+ run_loops.push_back(std::make_unique<base::RunLoop>());
+ socket_ptr->SendTo(
+ GetLocalHostWithAnyPort(), test_msg,
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+ base::BindOnce(
+ [](base::RunLoop* run_loop, int result) {
+ EXPECT_EQ(net::OK, result);
+ run_loop->Quit();
+ },
+ base::Unretained(run_loops[i].get())));
+ }
+
+ // SendTo() beyond the queue size should fail.
+ EXPECT_EQ(net::ERR_INSUFFICIENT_RESOURCES,
+ helper.SendToSync(GetLocalHostWithAnyPort(), test_msg));
+
+ // Complete all pending requests. Queued SendTo() should hear back.
+ socket_raw_ptr->CompleteAllPendingRequests();
+ for (const auto& loop : run_loops) {
+ loop->Run();
+ }
+}
+
+TEST_F(UDPSocketTest, TestReceiveMoreOverflow) {
+ // Create a server socket to listen for incoming datagrams.
+ test::UDPSocketReceiverImpl receiver;
+ mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
+ mojom::UDPSocketReceiverPtr receiver_interface_ptr;
+ receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
+
+ mojom::UDPSocketPtr server_socket;
+ UDPSocket impl(mojo::MakeRequest(&server_socket),
+ std::move(receiver_interface_ptr));
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&server_socket);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ server_socket->ReceiveMore(std::numeric_limits<uint32_t>::max());
+ server_socket.FlushForTesting();
+ EXPECT_EQ(std::numeric_limits<uint32_t>::max(), GetRemainingRecvSlots(&impl));
+ server_socket->ReceiveMore(1);
+ server_socket.FlushForTesting();
+ EXPECT_EQ(std::numeric_limits<uint32_t>::max(), GetRemainingRecvSlots(&impl));
+}
+
+TEST_F(UDPSocketTest, TestReadSend) {
+ // Create a server socket to listen for incoming datagrams.
+ test::UDPSocketReceiverImpl receiver;
+ mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
+ mojom::UDPSocketReceiverPtr receiver_interface_ptr;
+ receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
+
+ mojom::UDPSocketPtr server_socket;
+ UDPSocket impl(mojo::MakeRequest(&server_socket),
+ std::move(receiver_interface_ptr));
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&server_socket);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ // Create a client socket to send datagrams.
+ mojom::UDPSocketPtr client_socket;
+ UDPSocket client_impl(mojo::MakeRequest(&client_socket), nullptr);
+ net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper client_helper(&client_socket);
+ ASSERT_EQ(net::OK,
+ client_helper.ConnectSync(server_addr, nullptr, &client_addr));
+
+ const size_t kDatagramCount = 6;
+ server_socket->ReceiveMore(kDatagramCount);
+
+ for (size_t i = 0; i < kDatagramCount; ++i) {
+ std::vector<uint8_t> test_msg(
+ CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize));
+ int result = client_helper.SendSync(test_msg);
+ EXPECT_EQ(net::OK, result);
+ }
+
+ receiver.WaitForReceivedResults(kDatagramCount);
+ EXPECT_EQ(kDatagramCount, receiver.results().size());
+
+ int i = 0;
+ for (const auto& result : receiver.results()) {
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_EQ(result.src_addr, client_addr);
+ EXPECT_EQ(CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize),
+ result.data.value());
+ i++;
+ }
+ // Tests that sending a message that is larger than the specified limit
+ // results in an early rejection.
+ std::vector<uint8_t> large_msg(64 * 1024, 1);
+ EXPECT_EQ(net::ERR_MSG_TOO_BIG, helper.SendToSync(client_addr, large_msg));
+
+ // Close and re-Connect client socket.
+ client_socket->Close();
+ client_socket.FlushForTesting();
+
+ // Make sure datagram can still be sent from the re-connected client socket.
+ ASSERT_EQ(net::OK,
+ client_helper.ConnectSync(server_addr, nullptr, &client_addr));
+ server_socket->ReceiveMore(1);
+ std::vector<uint8_t> msg(CreateTestMessage(0, kDatagramSize));
+ EXPECT_EQ(net::OK, client_helper.SendSync(msg));
+
+ receiver.WaitForReceivedResults(kDatagramCount + 1);
+ ASSERT_EQ(kDatagramCount + 1, receiver.results().size());
+
+ auto result = receiver.results()[kDatagramCount];
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_EQ(result.src_addr, client_addr);
+ EXPECT_EQ(msg, result.data.value());
+}
+
+TEST_F(UDPSocketTest, TestReadSendTo) {
+ // Create a server socket to send data.
+ mojom::UDPSocketPtr server_socket;
+ UDPSocket impl(mojo::MakeRequest(&server_socket), nullptr);
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&server_socket);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ // Create a client socket to send datagrams.
+ test::UDPSocketReceiverImpl receiver;
+ mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
+ mojom::UDPSocketReceiverPtr client_receiver_ptr;
+ receiver_binding.Bind(mojo::MakeRequest(&client_receiver_ptr));
+
+ mojom::UDPSocketPtr client_socket;
+ UDPSocket client_impl(mojo::MakeRequest(&client_socket),
+ std::move(client_receiver_ptr));
+ net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper client_helper(&client_socket);
+ ASSERT_EQ(net::OK,
+ client_helper.ConnectSync(server_addr, nullptr, &client_addr));
+
+ const size_t kDatagramCount = 6;
+ client_socket->ReceiveMore(kDatagramCount);
+
+ for (size_t i = 0; i < kDatagramCount; ++i) {
+ std::vector<uint8_t> test_msg(
+ CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize));
+ int result = helper.SendToSync(client_addr, test_msg);
+ EXPECT_EQ(net::OK, result);
+ }
+
+ receiver.WaitForReceivedResults(kDatagramCount);
+ EXPECT_EQ(kDatagramCount, receiver.results().size());
+
+ int i = 0;
+ for (const auto& result : receiver.results()) {
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_FALSE(result.src_addr);
+ EXPECT_EQ(CreateTestMessage(static_cast<uint8_t>(i), kDatagramSize),
+ result.data.value());
+ i++;
+ }
+
+ // Tests that sending a message that is larger than the specified limit
+ // results in an early rejection.
+ std::vector<uint8_t> large_msg(64 * 1024, 1);
+ EXPECT_EQ(net::ERR_MSG_TOO_BIG, helper.SendToSync(client_addr, large_msg));
+
+ // Make sure datagram can still be sent from the re-bound server socket.
+ server_socket->Close();
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+ client_socket->ReceiveMore(1);
+ std::vector<uint8_t> msg(CreateTestMessage(0, kDatagramSize));
+ EXPECT_EQ(net::OK, helper.SendToSync(client_addr, msg));
+
+ receiver.WaitForReceivedResults(kDatagramCount + 1);
+ ASSERT_EQ(kDatagramCount + 1, receiver.results().size());
+
+ auto result = receiver.results()[kDatagramCount];
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_FALSE(result.src_addr);
+ EXPECT_EQ(msg, result.data.value());
+}
+
+TEST_F(UDPSocketTest, TestReceiveMoreWithBufferSize) {
+ // Create a server socket to listen for incoming datagrams.
+ test::UDPSocketReceiverImpl receiver;
+ mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
+ mojom::UDPSocketReceiverPtr receiver_interface_ptr;
+ receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
+
+ mojom::UDPSocketPtr server_socket;
+ UDPSocket impl(mojo::MakeRequest(&server_socket),
+ std::move(receiver_interface_ptr));
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&server_socket);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ // Create a client socket to send datagrams.
+ mojom::UDPSocketPtr client_socket;
+ UDPSocket client_impl(mojo::MakeRequest(&client_socket), nullptr);
+ net::IPEndPoint client_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper client_helper(&client_socket);
+ ASSERT_EQ(net::OK,
+ client_helper.ConnectSync(server_addr, nullptr, &client_addr));
+
+ // Use a buffer size that is 1 byte smaller than the datagram size.
+ // This should result in net::ERR_MSG_TOO_BIG, because the transport can't
+ // complete the read with this small buffer size.
+ size_t buffer_size = kDatagramSize - 1;
+ server_socket->ReceiveMoreWithBufferSize(1, buffer_size);
+ std::vector<uint8_t> test_msg(CreateTestMessage(0, kDatagramSize));
+ ASSERT_EQ(net::OK, client_helper.SendSync(test_msg));
+
+ receiver.WaitForReceivedResults(1);
+ ASSERT_EQ(1u, receiver.results().size());
+ auto result = receiver.results()[0];
+ EXPECT_EQ(net::ERR_MSG_TOO_BIG, result.net_error);
+ EXPECT_FALSE(result.data);
+
+ // Now use a buffer size that is equal to datagram size. This should be okay.
+ server_socket->ReceiveMoreWithBufferSize(1, kDatagramSize);
+ ASSERT_EQ(net::OK, client_helper.SendSync(test_msg));
+
+ receiver.WaitForReceivedResults(2);
+ ASSERT_EQ(2u, receiver.results().size());
+ result = receiver.results()[1];
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_EQ(client_addr, result.src_addr.value());
+ EXPECT_EQ(test_msg, result.data.value());
+}
+
+// Make sure passing an invalid net::IPEndPoint will be detected by
+// serialization/deserialization in mojo.
+TEST_F(UDPSocketTest, TestSendToInvalidAddress) {
+ mojom::UDPSocketPtr server_socket;
+ UDPSocket impl(mojo::MakeRequest(&server_socket), nullptr);
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&server_socket);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ std::vector<uint8_t> test_msg{1};
+ std::vector<uint8_t> invalid_ip_addr{127, 0, 0, 0, 1};
+ net::IPAddress ip_address(invalid_ip_addr.data(), invalid_ip_addr.size());
+ EXPECT_FALSE(ip_address.IsValid());
+ net::IPEndPoint invalid_addr(ip_address, 53);
+ server_socket->SendTo(
+ invalid_addr, test_msg,
+ net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
+ base::BindOnce([](int result) {}));
+ // Make sure that the pipe is broken upon processing |invalid_addr|.
+ base::RunLoop run_loop;
+ server_socket.set_connection_error_handler(
+ base::BindOnce([](base::RunLoop* run_loop) { run_loop->Quit(); },
+ base::Unretained(&run_loop)));
+ run_loop.Run();
+}
+
+// Tests that it is legal for UDPSocketReceiver::OnReceive() to be called with
+// 0 byte payload.
+TEST_F(UDPSocketTest, TestReadZeroByte) {
+ test::UDPSocketReceiverImpl receiver;
+ mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
+ mojom::UDPSocketReceiverPtr receiver_interface_ptr;
+ receiver_binding.Bind(mojo::MakeRequest(&receiver_interface_ptr));
+
+ mojom::UDPSocketPtr socket_ptr;
+ UDPSocket impl(mojo::MakeRequest(&socket_ptr),
+ std::move(receiver_interface_ptr));
+
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ test::UDPSocketTestHelper helper(&socket_ptr);
+ ASSERT_EQ(net::OK, helper.BindSync(server_addr, nullptr, &server_addr));
+
+ SetWrappedSocket(&impl, std::make_unique<ZeroByteReadUDPSocket>());
+
+ socket_ptr->ReceiveMore(1);
+
+ receiver.WaitForReceivedResults(1);
+ ASSERT_EQ(1u, receiver.results().size());
+
+ auto result = receiver.results()[0];
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_TRUE(result.data);
+ EXPECT_EQ(std::vector<uint8_t>(), result.data.value());
+}
+
+#if defined(OS_ANDROID)
+// Some Android devices do not support multicast socket.
+// The ones supporting multicast need WifiManager.MulticastLock to enable it.
+// https://developer.android.com/reference/android/net/wifi/WifiManager.MulticastLock.html
+#define MAYBE_JoinMulticastGroup DISABLED_JoinMulticastGroup
+#else
+#define MAYBE_JoinMulticastGroup JoinMulticastGroup
+#endif // defined(OS_ANDROID)
+TEST_F(UDPSocketTest, MAYBE_JoinMulticastGroup) {
+ const char kGroup[] = "237.132.100.17";
+
+ net::IPAddress group_ip;
+ EXPECT_TRUE(group_ip.AssignFromIPLiteral(kGroup));
+ mojom::UDPSocketPtr socket_ptr;
+ mojom::UDPSocketReceiverPtr receiver_ptr;
+ test::UDPSocketReceiverImpl receiver;
+ mojo::Binding<mojom::UDPSocketReceiver> receiver_binding(&receiver);
+ receiver_binding.Bind(mojo::MakeRequest(&receiver_ptr));
+ UDPSocket impl(mojo::MakeRequest(&socket_ptr), std::move(receiver_ptr));
+
+ test::UDPSocketTestHelper helper(&socket_ptr);
+
+ mojom::UDPSocketOptionsPtr options = network::mojom::UDPSocketOptions::New();
+#if defined(OS_FUCHSIA)
+ // Fuchsia currently doesn't support automatic interface selection for
+ // multicast, so interface index needs to be set explicitly.
+ // See https://fuchsia.atlassian.net/browse/NET-195 .
+ options->multicast_interface = 1;
+#endif // defined(OS_FUCHSIA)
+
+ net::IPAddress bind_ip_address;
+ EXPECT_TRUE(bind_ip_address.AssignFromIPLiteral("0.0.0.0"));
+ net::IPEndPoint socket_address(bind_ip_address, 0);
+ ASSERT_EQ(net::OK, helper.BindSync(socket_address, nullptr, &socket_address));
+ int port = socket_address.port();
+ EXPECT_NE(0, port);
+ EXPECT_EQ(net::OK, helper.JoinGroupSync(group_ip));
+ // Joining group multiple times.
+ EXPECT_NE(net::OK, helper.JoinGroupSync(group_ip));
+
+ // Receive messages from itself.
+ std::vector<uint8_t> test_msg(CreateTestMessage(0, kDatagramSize));
+ net::IPEndPoint group_alias(group_ip, port);
+ EXPECT_EQ(net::OK, helper.SendToSync(group_alias, test_msg));
+ socket_ptr->ReceiveMore(1);
+ receiver.WaitForReceivedResults(1);
+ ASSERT_EQ(1u, receiver.results().size());
+ auto result = receiver.results()[0];
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_EQ(port, result.src_addr.value().port());
+ EXPECT_EQ(test_msg, result.data.value());
+
+ // Create a second socket to send a packet to multicast group.
+ mojom::UDPSocketPtr second_socket_ptr;
+ UDPSocket second_socket_impl(mojo::MakeRequest(&second_socket_ptr), nullptr);
+ test::UDPSocketTestHelper second_socket_helper(&second_socket_ptr);
+ net::IPEndPoint second_socket_address(bind_ip_address, 0);
+ ASSERT_EQ(net::OK,
+ second_socket_helper.BindSync(second_socket_address, nullptr,
+ &second_socket_address));
+ int second_port = second_socket_address.port();
+ ASSERT_EQ(net::OK, second_socket_helper.SendToSync(group_alias, test_msg));
+
+ // First socket should receive packet sent by the second socket.
+ socket_ptr->ReceiveMore(1);
+ receiver.WaitForReceivedResults(2);
+ ASSERT_EQ(2u, receiver.results().size());
+ result = receiver.results()[1];
+ EXPECT_EQ(net::OK, result.net_error);
+ EXPECT_EQ(second_port, result.src_addr.value().port());
+ EXPECT_EQ(test_msg, result.data.value());
+
+ // First socket leaves group multiple times.
+ EXPECT_EQ(net::OK, helper.LeaveGroupSync(group_ip));
+ EXPECT_NE(net::OK, helper.LeaveGroupSync(group_ip));
+
+ // No longer can receive messages from itself or from second socket.
+ EXPECT_EQ(net::OK, helper.SendToSync(group_alias, test_msg));
+ ASSERT_EQ(net::OK, second_socket_helper.SendToSync(group_alias, test_msg));
+ socket_ptr->ReceiveMore(1);
+ socket_ptr.FlushForTesting();
+ ASSERT_EQ(2u, receiver.results().size());
+}
+
+TEST_F(UDPSocketTest, ErrorHappensDuringSocketOptionsConfiguration) {
+ mojom::UDPSocketPtr server_socket_ptr;
+ UDPSocket server_impl(mojo::MakeRequest(&server_socket_ptr), nullptr);
+ test::UDPSocketTestHelper server_helper(&server_socket_ptr);
+ net::IPEndPoint server_addr(GetLocalHostWithAnyPort());
+ ASSERT_EQ(net::OK,
+ server_helper.BindSync(server_addr, nullptr, &server_addr));
+
+ mojom::UDPSocketPtr socket_ptr;
+ UDPSocket impl(mojo::MakeRequest(&socket_ptr), nullptr);
+ test::UDPSocketTestHelper helper(&socket_ptr);
+
+ // Invalid options.
+ mojom::UDPSocketOptionsPtr options = network::mojom::UDPSocketOptions::New();
+ options->multicast_time_to_live = 256;
+
+ net::IPEndPoint local_addr;
+ ASSERT_EQ(net::ERR_INVALID_ARGUMENT,
+ helper.ConnectSync(server_addr, std::move(options), &local_addr));
+
+ // It's legal to retry Connect() with valid options.
+ mojom::UDPSocketOptionsPtr valid_options =
+ network::mojom::UDPSocketOptions::New();
+ valid_options->multicast_time_to_live = 255;
+ ASSERT_EQ(net::OK,
+ helper.ConnectSync(server_addr, std::move(options), &local_addr));
+ EXPECT_NE(0, local_addr.port());
+}
+
+} // namespace network
diff --git a/chromium/services/network/upload_progress_tracker.cc b/chromium/services/network/upload_progress_tracker.cc
new file mode 100644
index 00000000000..e75e4f42420
--- /dev/null
+++ b/chromium/services/network/upload_progress_tracker.cc
@@ -0,0 +1,89 @@
+// 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.
+
+#include "services/network/upload_progress_tracker.h"
+
+#include "base/logging.h"
+#include "net/base/upload_progress.h"
+#include "net/url_request/url_request.h"
+
+namespace network {
+namespace {
+// The interval for calls to ReportUploadProgress.
+constexpr base::TimeDelta kUploadProgressInterval =
+ base::TimeDelta::FromMilliseconds(100);
+} // namespace
+
+UploadProgressTracker::UploadProgressTracker(
+ const base::Location& location,
+ UploadProgressReportCallback report_progress,
+ net::URLRequest* request,
+ scoped_refptr<base::SequencedTaskRunner> task_runner)
+ : request_(request), report_progress_(std::move(report_progress)) {
+ DCHECK(report_progress_);
+
+ progress_timer_.SetTaskRunner(std::move(task_runner));
+ progress_timer_.Start(location, kUploadProgressInterval, this,
+ &UploadProgressTracker::ReportUploadProgressIfNeeded);
+}
+
+UploadProgressTracker::~UploadProgressTracker() {}
+
+void UploadProgressTracker::OnAckReceived() {
+ waiting_for_upload_progress_ack_ = false;
+}
+
+void UploadProgressTracker::OnUploadCompleted() {
+ waiting_for_upload_progress_ack_ = false;
+ ReportUploadProgressIfNeeded();
+ progress_timer_.Stop();
+}
+
+// static
+base::TimeDelta UploadProgressTracker::GetUploadProgressIntervalForTesting() {
+ return kUploadProgressInterval;
+}
+
+base::TimeTicks UploadProgressTracker::GetCurrentTime() const {
+ return base::TimeTicks::Now();
+}
+
+net::UploadProgress UploadProgressTracker::GetUploadProgress() const {
+ return request_->GetUploadProgress();
+}
+
+void UploadProgressTracker::ReportUploadProgressIfNeeded() {
+ if (waiting_for_upload_progress_ack_)
+ return;
+
+ net::UploadProgress progress = GetUploadProgress();
+ if (!progress.size())
+ return; // Nothing to upload, or in the chunked upload mode.
+
+ // No progress made since last time, or the progress was reset by a redirect
+ // or a retry.
+ if (progress.position() <= last_upload_position_)
+ return;
+
+ const uint64_t kHalfPercentIncrements = 200;
+ const base::TimeDelta kOneSecond = base::TimeDelta::FromMilliseconds(1000);
+
+ uint64_t amt_since_last = progress.position() - last_upload_position_;
+ base::TimeTicks now = GetCurrentTime();
+ base::TimeDelta time_since_last = now - last_upload_ticks_;
+
+ bool is_finished = (progress.size() == progress.position());
+ bool enough_new_progress =
+ (amt_since_last > (progress.size() / kHalfPercentIncrements));
+ bool too_much_time_passed = time_since_last > kOneSecond;
+
+ if (is_finished || enough_new_progress || too_much_time_passed) {
+ report_progress_.Run(progress);
+ waiting_for_upload_progress_ack_ = true;
+ last_upload_ticks_ = now;
+ last_upload_position_ = progress.position();
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/upload_progress_tracker.h b/chromium/services/network/upload_progress_tracker.h
new file mode 100644
index 00000000000..994535c3418
--- /dev/null
+++ b/chromium/services/network/upload_progress_tracker.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef SERVICES_NETWORK_UPLOAD_PROGRESS_TRACKER_H_
+#define SERVICES_NETWORK_UPLOAD_PROGRESS_TRACKER_H_
+
+#include <stdint.h>
+
+#include "base/callback.h"
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_task_runner_handle.h"
+#include "base/time/time.h"
+#include "base/timer/timer.h"
+#include "net/base/upload_progress.h"
+
+namespace base {
+class Location;
+}
+
+namespace net {
+class URLRequest;
+}
+
+namespace network {
+
+// UploadProgressTracker watches the upload progress of a URL loading, and sends
+// the progress to the client in a suitable granularity and frequency.
+class COMPONENT_EXPORT(NETWORK_SERVICE) UploadProgressTracker {
+ public:
+ using UploadProgressReportCallback =
+ base::RepeatingCallback<void(const net::UploadProgress&)>;
+
+ UploadProgressTracker(const base::Location& location,
+ UploadProgressReportCallback report_progress,
+ net::URLRequest* request,
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ base::SequencedTaskRunnerHandle::Get());
+ virtual ~UploadProgressTracker();
+
+ void OnAckReceived();
+ void OnUploadCompleted();
+
+ static base::TimeDelta GetUploadProgressIntervalForTesting();
+
+ private:
+ // Overridden by tests to use a fake time and progress.
+ virtual base::TimeTicks GetCurrentTime() const;
+ virtual net::UploadProgress GetUploadProgress() const;
+
+ void ReportUploadProgressIfNeeded();
+
+ net::URLRequest* request_; // Not owned.
+
+ uint64_t last_upload_position_ = 0;
+ bool waiting_for_upload_progress_ack_ = false;
+ base::TimeTicks last_upload_ticks_;
+ base::RepeatingTimer progress_timer_;
+
+ UploadProgressReportCallback report_progress_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadProgressTracker);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_UPLOAD_PROGRESS_TRACKER_H_
diff --git a/chromium/services/network/upload_progress_tracker_unittest.cc b/chromium/services/network/upload_progress_tracker_unittest.cc
new file mode 100644
index 00000000000..1de8512242b
--- /dev/null
+++ b/chromium/services/network/upload_progress_tracker_unittest.cc
@@ -0,0 +1,279 @@
+// 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 "services/network/upload_progress_tracker.h"
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/test/test_mock_time_task_runner.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "net/base/upload_progress.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace network {
+namespace {
+
+class TestingUploadProgressTracker : public UploadProgressTracker {
+ public:
+ TestingUploadProgressTracker(
+ const base::Location& location,
+ UploadProgressReportCallback report_callback,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner)
+ : UploadProgressTracker(location,
+ std::move(report_callback),
+ nullptr,
+ std::move(task_runner)),
+ current_time_(base::TimeTicks::Now()) {}
+
+ void set_upload_progress(const net::UploadProgress& upload_progress) {
+ upload_progress_ = upload_progress;
+ }
+
+ void set_current_time(const base::TimeTicks& current_time) {
+ current_time_ = current_time;
+ }
+
+ private:
+ // UploadProgressTracker overrides.
+ base::TimeTicks GetCurrentTime() const override { return current_time_; }
+ net::UploadProgress GetUploadProgress() const override {
+ return upload_progress_;
+ }
+
+ base::TimeTicks current_time_;
+ net::UploadProgress upload_progress_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestingUploadProgressTracker);
+};
+
+} // namespace
+
+class UploadProgressTrackerTest : public ::testing::Test {
+ public:
+ UploadProgressTrackerTest()
+ : task_runner_handle_(mock_task_runner_),
+ upload_progress_tracker_(
+ FROM_HERE,
+ base::BindRepeating(
+ &UploadProgressTrackerTest::OnUploadProgressReported,
+ base::Unretained(this)),
+ mock_task_runner_) {}
+
+ private:
+ void OnUploadProgressReported(const net::UploadProgress& progress) {
+ ++report_count_;
+ reported_position_ = progress.position();
+ reported_total_size_ = progress.size();
+ }
+
+ protected:
+ int report_count_ = 0;
+ int64_t reported_position_ = 0;
+ int64_t reported_total_size_ = 0;
+
+ // Mocks the current thread's task runner which will also be used as the
+ // UploadProgressTracker's task runner.
+ scoped_refptr<base::TestMockTimeTaskRunner> mock_task_runner_ =
+ new base::TestMockTimeTaskRunner;
+ base::ThreadTaskRunnerHandle task_runner_handle_;
+
+ TestingUploadProgressTracker upload_progress_tracker_;
+
+ DISALLOW_COPY_AND_ASSIGN(UploadProgressTrackerTest);
+};
+
+TEST_F(UploadProgressTrackerTest, NoACK) {
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(500, 1000));
+
+ // The first timer task calls ReportUploadProgress.
+ EXPECT_EQ(0, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+ EXPECT_EQ(500, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(750, 1000));
+
+ // The second timer task does nothing, since the first report didn't send the
+ // ACK.
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+}
+
+TEST_F(UploadProgressTrackerTest, NoUpload) {
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(0, 0));
+
+ // UploadProgressTracker does nothing on the empty upload content.
+ EXPECT_EQ(0, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(0, report_count_);
+}
+
+TEST_F(UploadProgressTrackerTest, NoProgress) {
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(500, 1000));
+
+ // The first timer task calls ReportUploadProgress.
+ EXPECT_EQ(0, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+ EXPECT_EQ(500, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+
+ upload_progress_tracker_.OnAckReceived();
+
+ // The second time doesn't call ReportUploadProgress since there's no
+ // progress.
+ EXPECT_EQ(1, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+}
+
+TEST_F(UploadProgressTrackerTest, Finished) {
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(999, 1000));
+
+ // The first timer task calls ReportUploadProgress.
+ EXPECT_EQ(0, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+ EXPECT_EQ(999, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+
+ upload_progress_tracker_.OnAckReceived();
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(1000, 1000));
+
+ // The second timer task calls ReportUploadProgress for reporting the
+ // completion.
+ EXPECT_EQ(1, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(2, report_count_);
+ EXPECT_EQ(1000, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+}
+
+TEST_F(UploadProgressTrackerTest, Progress) {
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(500, 1000));
+
+ // The first timer task calls ReportUploadProgress.
+ EXPECT_EQ(0, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+ EXPECT_EQ(500, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+
+ upload_progress_tracker_.OnAckReceived();
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(750, 1000));
+
+ // The second timer task calls ReportUploadProgress since the progress is
+ // big enough to report.
+ EXPECT_EQ(1, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(2, report_count_);
+ EXPECT_EQ(750, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+}
+
+TEST_F(UploadProgressTrackerTest, TimePassed) {
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(500, 1000));
+
+ // The first timer task calls ReportUploadProgress.
+ EXPECT_EQ(0, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+ EXPECT_EQ(500, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+
+ upload_progress_tracker_.OnAckReceived();
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(501, 1000));
+
+ // The second timer task doesn't call ReportUploadProgress since the progress
+ // is too small to report it.
+ EXPECT_EQ(1, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+
+ upload_progress_tracker_.set_current_time(base::TimeTicks::Now() +
+ base::TimeDelta::FromSeconds(5));
+
+ // The third timer task calls ReportUploadProgress since it's been long time
+ // from the last report.
+ EXPECT_EQ(1, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(2, report_count_);
+ EXPECT_EQ(501, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+}
+
+TEST_F(UploadProgressTrackerTest, Rewound) {
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(500, 1000));
+
+ // The first timer task calls ReportUploadProgress.
+ EXPECT_EQ(0, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+ EXPECT_EQ(500, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+
+ upload_progress_tracker_.OnAckReceived();
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(250, 1000));
+
+ // The second timer task doesn't call ReportUploadProgress since the progress
+ // was rewound.
+ EXPECT_EQ(1, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+
+ upload_progress_tracker_.set_current_time(base::TimeTicks::Now() +
+ base::TimeDelta::FromSeconds(5));
+
+ // Even after a good amount of time passed, the rewound progress should not be
+ // reported.
+ EXPECT_EQ(1, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+}
+
+TEST_F(UploadProgressTrackerTest, Completed) {
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(500, 1000));
+
+ // The first timer task calls ReportUploadProgress.
+ EXPECT_EQ(0, report_count_);
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(1, report_count_);
+ EXPECT_EQ(500, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+
+ upload_progress_tracker_.set_upload_progress(net::UploadProgress(1000, 1000));
+
+ // OnUploadCompleted runs ReportUploadProgress even without Ack nor timer.
+ upload_progress_tracker_.OnUploadCompleted();
+ EXPECT_EQ(2, report_count_);
+ EXPECT_EQ(1000, reported_position_);
+ EXPECT_EQ(1000, reported_total_size_);
+
+ mock_task_runner_->FastForwardBy(
+ UploadProgressTracker::GetUploadProgressIntervalForTesting());
+ EXPECT_EQ(2, report_count_);
+ EXPECT_FALSE(mock_task_runner_->HasPendingTask());
+}
+
+} // namespace network
diff --git a/chromium/services/network/url_loader.cc b/chromium/services/network/url_loader.cc
new file mode 100644
index 00000000000..208e7e240b2
--- /dev/null
+++ b/chromium/services/network/url_loader.cc
@@ -0,0 +1,847 @@
+// 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 "services/network/url_loader.h"
+
+#include <string>
+
+#include "base/files/file.h"
+#include "base/memory/weak_ptr.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/base/elements_upload_data_stream.h"
+#include "net/base/mime_sniffer.h"
+#include "net/base/upload_bytes_element_reader.h"
+#include "net/base/upload_file_element_reader.h"
+#include "net/cert/symantec_certs.h"
+#include "net/ssl/client_cert_store.h"
+#include "net/ssl/ssl_private_key.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "services/network/data_pipe_element_reader.h"
+#include "services/network/loader_util.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/net_adapters.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/resource_scheduler_client.h"
+
+namespace network {
+
+namespace {
+constexpr size_t kDefaultAllocationSize = 512 * 1024;
+
+// TODO: this duplicates some of PopulateResourceResponse in
+// content/browser/loader/resource_loader.cc
+void PopulateResourceResponse(net::URLRequest* request,
+ bool is_load_timing_enabled,
+ ResourceResponse* response) {
+ response->head.request_time = request->request_time();
+ response->head.response_time = request->response_time();
+ response->head.headers = request->response_headers();
+ request->GetCharset(&response->head.charset);
+ response->head.content_length = request->GetExpectedContentSize();
+ request->GetMimeType(&response->head.mime_type);
+ net::HttpResponseInfo response_info = request->response_info();
+ response->head.was_fetched_via_spdy = response_info.was_fetched_via_spdy;
+ response->head.was_alpn_negotiated = response_info.was_alpn_negotiated;
+ response->head.alpn_negotiated_protocol =
+ response_info.alpn_negotiated_protocol;
+ response->head.connection_info = response_info.connection_info;
+ response->head.socket_address = response_info.socket_address;
+
+ response->head.effective_connection_type =
+ net::EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
+
+ if (is_load_timing_enabled)
+ request->GetLoadTimingInfo(&response->head.load_timing);
+
+ if (request->ssl_info().cert.get()) {
+ response->head.ct_policy_compliance =
+ request->ssl_info().ct_policy_compliance;
+ response->head.is_legacy_symantec_cert =
+ (!net::IsCertStatusError(response->head.cert_status) ||
+ net::IsCertStatusMinorError(response->head.cert_status)) &&
+ net::IsLegacySymantecCert(request->ssl_info().public_key_hashes);
+ response->head.cert_status = request->ssl_info().cert_status;
+ }
+
+ response->head.request_start = request->creation_time();
+ response->head.response_start = base::TimeTicks::Now();
+ response->head.encoded_data_length = request->GetTotalReceivedBytes();
+}
+
+// A subclass of net::UploadBytesElementReader which owns
+// ResourceRequestBody.
+class BytesElementReader : public net::UploadBytesElementReader {
+ public:
+ BytesElementReader(ResourceRequestBody* resource_request_body,
+ const DataElement& element)
+ : net::UploadBytesElementReader(element.bytes(), element.length()),
+ resource_request_body_(resource_request_body) {
+ DCHECK_EQ(DataElement::TYPE_BYTES, element.type());
+ }
+
+ ~BytesElementReader() override {}
+
+ private:
+ scoped_refptr<ResourceRequestBody> resource_request_body_;
+
+ DISALLOW_COPY_AND_ASSIGN(BytesElementReader);
+};
+
+// A subclass of net::UploadFileElementReader which owns
+// ResourceRequestBody.
+// This class is necessary to ensure the BlobData and any attached shareable
+// files survive until upload completion.
+class FileElementReader : public net::UploadFileElementReader {
+ public:
+ FileElementReader(ResourceRequestBody* resource_request_body,
+ base::TaskRunner* task_runner,
+ const DataElement& element)
+ : net::UploadFileElementReader(task_runner,
+ element.path(),
+ element.offset(),
+ element.length(),
+ element.expected_modification_time()),
+ resource_request_body_(resource_request_body) {
+ DCHECK_EQ(DataElement::TYPE_FILE, element.type());
+ }
+
+ ~FileElementReader() override {}
+
+ private:
+ scoped_refptr<ResourceRequestBody> resource_request_body_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileElementReader);
+};
+
+class RawFileElementReader : public net::UploadFileElementReader {
+ public:
+ RawFileElementReader(ResourceRequestBody* resource_request_body,
+ base::TaskRunner* task_runner,
+ const DataElement& element)
+ : net::UploadFileElementReader(
+ task_runner,
+ // TODO(mmenke): Is duplicating this necessary?
+ element.file().Duplicate(),
+ element.path(),
+ element.offset(),
+ element.length(),
+ element.expected_modification_time()),
+ resource_request_body_(resource_request_body) {
+ DCHECK_EQ(DataElement::TYPE_RAW_FILE, element.type());
+ }
+
+ ~RawFileElementReader() override {}
+
+ private:
+ scoped_refptr<ResourceRequestBody> resource_request_body_;
+
+ DISALLOW_COPY_AND_ASSIGN(RawFileElementReader);
+};
+
+// TODO: copied from content/browser/loader/upload_data_stream_builder.cc.
+std::unique_ptr<net::UploadDataStream> CreateUploadDataStream(
+ ResourceRequestBody* body,
+ base::SequencedTaskRunner* file_task_runner) {
+ std::vector<std::unique_ptr<net::UploadElementReader>> element_readers;
+ for (const auto& element : *body->elements()) {
+ switch (element.type()) {
+ case DataElement::TYPE_BYTES:
+ element_readers.push_back(
+ std::make_unique<BytesElementReader>(body, element));
+ break;
+ case DataElement::TYPE_FILE:
+ element_readers.push_back(std::make_unique<FileElementReader>(
+ body, file_task_runner, element));
+ break;
+ case DataElement::TYPE_RAW_FILE:
+ element_readers.push_back(std::make_unique<RawFileElementReader>(
+ body, file_task_runner, element));
+ break;
+ case DataElement::TYPE_BLOB: {
+ CHECK(false) << "Network service always uses DATA_PIPE for blobs.";
+ break;
+ }
+ case DataElement::TYPE_DATA_PIPE: {
+ element_readers.push_back(std::make_unique<DataPipeElementReader>(
+ body, const_cast<DataElement*>(&element)->ReleaseDataPipeGetter()));
+ break;
+ }
+ case DataElement::TYPE_UNKNOWN:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ return std::make_unique<net::ElementsUploadDataStream>(
+ std::move(element_readers), body->identifier());
+}
+
+class SSLPrivateKeyInternal : public net::SSLPrivateKey {
+ public:
+ SSLPrivateKeyInternal(const std::vector<uint16_t>& algorithm_perferences,
+ mojom::SSLPrivateKeyPtr ssl_private_key)
+ : algorithm_perferences_(algorithm_perferences),
+ ssl_private_key_(std::move(ssl_private_key)) {
+ ssl_private_key_.set_connection_error_handler(
+ base::BindOnce(&SSLPrivateKeyInternal::HandleSSLPrivateKeyError, this));
+ }
+
+ // net::SSLPrivateKey:
+ std::vector<uint16_t> GetAlgorithmPreferences() override {
+ return algorithm_perferences_;
+ }
+
+ void Sign(uint16_t algorithm,
+ base::span<const uint8_t> input,
+ net::SSLPrivateKey::SignCallback callback) override {
+ std::vector<uint8_t> input_vector(input.begin(), input.end());
+ if (ssl_private_key_.encountered_error()) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(std::move(callback),
+ net::ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY,
+ input_vector));
+ return;
+ }
+
+ ssl_private_key_->Sign(algorithm, input_vector,
+ base::BindOnce(&SSLPrivateKeyInternal::Callback,
+ this, std::move(callback)));
+ }
+
+ private:
+ ~SSLPrivateKeyInternal() override = default;
+
+ void HandleSSLPrivateKeyError() { ssl_private_key_.reset(); }
+
+ void Callback(net::SSLPrivateKey::SignCallback callback,
+ int32_t net_error,
+ const std::vector<uint8_t>& input) {
+ DCHECK_LE(net_error, 0);
+ DCHECK_NE(net_error, net::ERR_IO_PENDING);
+ std::move(callback).Run(static_cast<net::Error>(net_error), input);
+ }
+
+ std::vector<uint16_t> algorithm_perferences_;
+ mojom::SSLPrivateKeyPtr ssl_private_key_;
+
+ DISALLOW_COPY_AND_ASSIGN(SSLPrivateKeyInternal);
+};
+
+} // namespace
+
+URLLoader::URLLoader(
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
+ mojom::NetworkServiceClient* network_service_client,
+ mojom::URLLoaderRequest url_loader_request,
+ int32_t options,
+ const ResourceRequest& request,
+ bool report_raw_headers,
+ mojom::URLLoaderClientPtr url_loader_client,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ uint32_t process_id,
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
+ base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder)
+ : url_request_context_getter_(url_request_context_getter),
+ network_service_client_(network_service_client),
+ options_(options),
+ resource_type_(request.resource_type),
+ is_load_timing_enabled_(request.enable_load_timing),
+ process_id_(process_id),
+ render_frame_id_(request.render_frame_id),
+ connected_(true),
+ keepalive_(request.keepalive),
+ binding_(this, std::move(url_loader_request)),
+ url_loader_client_(std::move(url_loader_client)),
+ writable_handle_watcher_(FROM_HERE,
+ mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+ peer_closed_handle_watcher_(FROM_HERE,
+ mojo::SimpleWatcher::ArmingPolicy::MANUAL),
+ report_raw_headers_(report_raw_headers),
+ resource_scheduler_client_(std::move(resource_scheduler_client)),
+ keepalive_statistics_recorder_(std::move(keepalive_statistics_recorder)),
+ first_auth_attempt_(true),
+ weak_ptr_factory_(this) {
+ if (!base::FeatureList::IsEnabled(features::kNetworkService)) {
+ CHECK(!url_loader_client_.internal_state()
+ ->handle()
+ .QuerySignalsState()
+ .peer_remote())
+ << "URLLoader must not be used by the renderer when network service is "
+ << "disabled, as that skips security checks in ResourceDispatcherHost. "
+ << "The only acceptable usage is the browser using SimpleURLLoader.";
+ }
+ url_request_context_getter_->AddObserver(this);
+ binding_.set_connection_error_handler(
+ base::BindOnce(&URLLoader::OnConnectionError, base::Unretained(this)));
+
+ url_request_ =
+ url_request_context_getter_->GetURLRequestContext()->CreateRequest(
+ GURL(request.url), request.priority, this, traffic_annotation);
+ url_request_->set_method(request.method);
+ url_request_->set_site_for_cookies(request.site_for_cookies);
+ url_request_->SetReferrer(ComputeReferrer(request.referrer));
+ url_request_->set_referrer_policy(request.referrer_policy);
+ url_request_->SetExtraRequestHeaders(request.headers);
+
+ // Resolve elements from request_body and prepare upload data.
+ if (request.request_body.get()) {
+ scoped_refptr<base::SequencedTaskRunner> task_runner =
+ base::CreateSequencedTaskRunnerWithTraits(
+ {base::MayBlock(), base::TaskPriority::USER_VISIBLE});
+ url_request_->set_upload(
+ CreateUploadDataStream(request.request_body.get(), task_runner.get()));
+
+ if (request.enable_upload_progress) {
+ upload_progress_tracker_ = std::make_unique<UploadProgressTracker>(
+ FROM_HERE,
+ base::BindRepeating(&URLLoader::SendUploadProgress,
+ base::Unretained(this)),
+ url_request_.get());
+ }
+ }
+
+ url_request_->set_initiator(request.request_initiator);
+
+ if (request.update_first_party_url_on_redirect) {
+ url_request_->set_first_party_url_policy(
+ net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
+ }
+
+ url_request_->SetLoadFlags(request.load_flags);
+ if (report_raw_headers_) {
+ url_request_->SetRequestHeadersCallback(
+ base::Bind(&net::HttpRawRequestHeaders::Assign,
+ base::Unretained(&raw_request_headers_)));
+ url_request_->SetResponseHeadersCallback(
+ base::Bind(&URLLoader::SetRawResponseHeaders, base::Unretained(this)));
+ }
+
+ if (keepalive_ && keepalive_statistics_recorder_)
+ keepalive_statistics_recorder_->OnLoadStarted(process_id_);
+
+ bool defer = false;
+ if (resource_scheduler_client_) {
+ resource_scheduler_request_handle_ =
+ resource_scheduler_client_->ScheduleRequest(
+ !(options_ & network::mojom::kURLLoadOptionSynchronous),
+ url_request_.get());
+ resource_scheduler_request_handle_->set_resume_callback(
+ base::BindRepeating(&URLLoader::ResumeStart, base::Unretained(this)));
+ resource_scheduler_request_handle_->WillStartRequest(&defer);
+ }
+ if (defer)
+ url_request_->LogBlockedBy("ResourceScheduler");
+ else
+ url_request_->Start();
+}
+
+URLLoader::~URLLoader() {
+ RecordBodyReadFromNetBeforePausedIfNeeded();
+ url_request_context_getter_->RemoveObserver(this);
+
+ if (keepalive_ && keepalive_statistics_recorder_)
+ keepalive_statistics_recorder_->OnLoadFinished(process_id_);
+}
+
+void URLLoader::FollowRedirect() {
+ if (!url_request_) {
+ NotifyCompleted(net::ERR_UNEXPECTED);
+ // |this| may have been deleted.
+ return;
+ }
+
+ url_request_->FollowDeferredRedirect();
+}
+
+void URLLoader::ProceedWithResponse() {
+ NOTREACHED();
+}
+
+void URLLoader::SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) {
+ if (url_request_ && resource_scheduler_client_) {
+ resource_scheduler_client_->ReprioritizeRequest(
+ url_request_.get(), priority, intra_priority_value);
+ }
+}
+
+void URLLoader::PauseReadingBodyFromNet() {
+ DVLOG(1) << "URLLoader pauses fetching response body for "
+ << (url_request_ ? url_request_->original_url().spec()
+ : "a URL that has completed loading or failed.");
+
+ if (!url_request_)
+ return;
+
+ // Please note that we pause reading body in all cases. Even if the URL
+ // request indicates that the response was cached, there could still be
+ // network activity involved. For example, the response was only partially
+ // cached.
+ //
+ // On the other hand, we only report BodyReadFromNetBeforePaused histogram
+ // when we are sure that the response body hasn't been read from cache. This
+ // avoids polluting the histogram data with data points from cached responses.
+ should_pause_reading_body_ = true;
+
+ // If the data pipe has been set up and the request is in IO pending state,
+ // there is a pending read for the response body.
+ if (HasDataPipe() && url_request_->status().is_io_pending()) {
+ update_body_read_before_paused_ = true;
+ } else {
+ body_read_before_paused_ = url_request_->GetRawBodyBytes();
+ }
+}
+
+void URLLoader::ResumeReadingBodyFromNet() {
+ DVLOG(1) << "URLLoader resumes fetching response body for "
+ << (url_request_ ? url_request_->original_url().spec()
+ : "a URL that has completed loading or failed.");
+ should_pause_reading_body_ = false;
+
+ if (paused_reading_body_) {
+ paused_reading_body_ = false;
+ ReadMore();
+ }
+}
+
+void URLLoader::OnReceivedRedirect(net::URLRequest* url_request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) {
+ DCHECK(url_request == url_request_.get());
+ DCHECK(url_request->status().is_success());
+
+ // Send the redirect response to the client, allowing them to inspect it and
+ // optionally follow the redirect.
+ *defer_redirect = true;
+
+ scoped_refptr<ResourceResponse> response = new ResourceResponse();
+ PopulateResourceResponse(url_request_.get(), is_load_timing_enabled_,
+ response.get());
+ if (report_raw_headers_) {
+ response->head.raw_request_response_info = BuildRawRequestResponseInfo(
+ *url_request_, raw_request_headers_, raw_response_headers_.get());
+ raw_request_headers_ = net::HttpRawRequestHeaders();
+ raw_response_headers_ = nullptr;
+ }
+ url_loader_client_->OnReceiveRedirect(redirect_info, response->head);
+}
+
+void URLLoader::OnAuthRequired(net::URLRequest* unused,
+ net::AuthChallengeInfo* auth_info) {
+ if (!network_service_client_) {
+ OnAuthRequiredResponse(base::nullopt);
+ return;
+ }
+
+ network_service_client_->OnAuthRequired(
+ process_id_, render_frame_id_, url_request_->url(), first_auth_attempt_,
+ auth_info,
+ base::BindOnce(&URLLoader::OnAuthRequiredResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+
+ first_auth_attempt_ = false;
+}
+
+void URLLoader::OnCertificateRequested(net::URLRequest* unused,
+ net::SSLCertRequestInfo* cert_info) {
+ if (!network_service_client_) {
+ OnCertificateRequestedResponse(nullptr, std::vector<uint16_t>(), nullptr,
+ true /* cancel_certificate_selection */);
+ return;
+ }
+
+ network_service_client_->OnCertificateRequested(
+ process_id_, render_frame_id_, cert_info,
+ base::BindOnce(&URLLoader::OnCertificateRequestedResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void URLLoader::OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& ssl_info,
+ bool fatal) {
+ if (!network_service_client_) {
+ OnSSLCertificateErrorResponse(ssl_info, net::ERR_INSECURE_RESPONSE);
+ return;
+ }
+ network_service_client_->OnSSLCertificateError(
+ resource_type_, url_request_->url(), process_id_, render_frame_id_,
+ ssl_info, fatal,
+ base::Bind(&URLLoader::OnSSLCertificateErrorResponse,
+ weak_ptr_factory_.GetWeakPtr(), ssl_info));
+}
+
+void URLLoader::ResumeStart() {
+ url_request_->LogUnblocked();
+ url_request_->Start();
+}
+
+void URLLoader::OnResponseStarted(net::URLRequest* url_request, int net_error) {
+ DCHECK(url_request == url_request_.get());
+
+ if (net_error != net::OK) {
+ NotifyCompleted(net_error);
+ // |this| may have been deleted.
+ return;
+ }
+
+ if (resource_scheduler_client_ && url_request->was_fetched_via_proxy() &&
+ url_request->was_fetched_via_spdy() &&
+ url_request->url().SchemeIs(url::kHttpScheme)) {
+ resource_scheduler_client_->OnReceivedSpdyProxiedHttpResponse();
+ }
+
+ if (upload_progress_tracker_) {
+ upload_progress_tracker_->OnUploadCompleted();
+ upload_progress_tracker_ = nullptr;
+ }
+
+ response_ = new ResourceResponse();
+ PopulateResourceResponse(url_request_.get(), is_load_timing_enabled_,
+ response_.get());
+ if (report_raw_headers_) {
+ response_->head.raw_request_response_info = BuildRawRequestResponseInfo(
+ *url_request_, raw_request_headers_, raw_response_headers_.get());
+ raw_request_headers_ = net::HttpRawRequestHeaders();
+ raw_response_headers_ = nullptr;
+ }
+
+ mojo::DataPipe data_pipe(kDefaultAllocationSize);
+ response_body_stream_ = std::move(data_pipe.producer_handle);
+ consumer_handle_ = std::move(data_pipe.consumer_handle);
+ peer_closed_handle_watcher_.Watch(
+ response_body_stream_.get(), MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ base::Bind(&URLLoader::OnResponseBodyStreamConsumerClosed,
+ base::Unretained(this)));
+ peer_closed_handle_watcher_.ArmOrNotify();
+
+ writable_handle_watcher_.Watch(
+ response_body_stream_.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
+ base::Bind(&URLLoader::OnResponseBodyStreamReady,
+ base::Unretained(this)));
+
+ if (!(options_ & mojom::kURLLoadOptionSniffMimeType) ||
+ !ShouldSniffContent(url_request_.get(), response_.get()))
+ SendResponseToClient();
+
+ // Start reading...
+ ReadMore();
+}
+
+void URLLoader::ReadMore() {
+ // Once the MIME type is sniffed, all data is sent as soon as it is read from
+ // the network.
+ DCHECK(consumer_handle_.is_valid() || !pending_write_);
+
+ if (should_pause_reading_body_) {
+ paused_reading_body_ = true;
+ return;
+ }
+
+ if (!pending_write_.get()) {
+ // TODO: we should use the abstractions in MojoAsyncResourceHandler.
+ DCHECK_EQ(0u, pending_write_buffer_offset_);
+ MojoResult result = NetToMojoPendingBuffer::BeginWrite(
+ &response_body_stream_, &pending_write_, &pending_write_buffer_size_);
+ if (result != MOJO_RESULT_OK && result != MOJO_RESULT_SHOULD_WAIT) {
+ // The response body stream is in a bad state. Bail.
+ // TODO: How should this be communicated to our client?
+ CloseResponseBodyStreamProducer();
+ return;
+ }
+
+ DCHECK_GT(static_cast<uint32_t>(std::numeric_limits<int>::max()),
+ pending_write_buffer_size_);
+ if (consumer_handle_.is_valid()) {
+ DCHECK_GE(pending_write_buffer_size_,
+ static_cast<uint32_t>(net::kMaxBytesToSniff));
+ }
+ if (result == MOJO_RESULT_SHOULD_WAIT) {
+ // The pipe is full. We need to wait for it to have more space.
+ writable_handle_watcher_.ArmOrNotify();
+ return;
+ }
+ }
+
+ auto buf = base::MakeRefCounted<NetToMojoIOBuffer>(
+ pending_write_.get(), pending_write_buffer_offset_);
+ int bytes_read;
+ url_request_->Read(buf.get(),
+ static_cast<int>(pending_write_buffer_size_ -
+ pending_write_buffer_offset_),
+ &bytes_read);
+ if (url_request_->status().is_io_pending()) {
+ // Wait for OnReadCompleted.
+ } else {
+ DidRead(bytes_read, true);
+ // |this| may have been deleted.
+ }
+}
+
+void URLLoader::DidRead(int num_bytes, bool completed_synchronously) {
+ if (num_bytes > 0)
+ pending_write_buffer_offset_ += num_bytes;
+ if (update_body_read_before_paused_) {
+ update_body_read_before_paused_ = false;
+ body_read_before_paused_ = url_request_->GetRawBodyBytes();
+ }
+
+ bool complete_read = true;
+ if (consumer_handle_.is_valid()) {
+ const std::string& type_hint = response_->head.mime_type;
+ std::string new_type;
+ bool made_final_decision = net::SniffMimeType(
+ pending_write_->buffer(), pending_write_buffer_offset_,
+ url_request_->url(), type_hint,
+ net::ForceSniffFileUrlsForHtml::kDisabled, &new_type);
+ // SniffMimeType() returns false if there is not enough data to determine
+ // the mime type. However, even if it returns false, it returns a new type
+ // that is probably better than the current one.
+ response_->head.mime_type.assign(new_type);
+
+ if (made_final_decision) {
+ SendResponseToClient();
+ } else {
+ complete_read = false;
+ }
+ }
+
+ if (!url_request_->status().is_success() || num_bytes == 0) {
+ CompletePendingWrite();
+ NotifyCompleted(url_request_->status().ToNetError());
+
+ CloseResponseBodyStreamProducer();
+ // |this| may have been deleted.
+ return;
+ }
+
+ if (complete_read) {
+ CompletePendingWrite();
+ }
+ if (completed_synchronously) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&URLLoader::ReadMore, weak_ptr_factory_.GetWeakPtr()));
+ } else {
+ ReadMore();
+ }
+}
+
+void URLLoader::OnReadCompleted(net::URLRequest* url_request, int bytes_read) {
+ DCHECK(url_request == url_request_.get());
+
+ DidRead(bytes_read, false);
+ // |this| may have been deleted.
+}
+
+void URLLoader::OnContextShuttingDown() {
+ // The associated network context is going away and we have to destroy
+ // net::URLRequest held by this loader.
+ delete this;
+}
+
+net::LoadState URLLoader::GetLoadStateForTesting() const {
+ if (!url_request_)
+ return net::LOAD_STATE_IDLE;
+ return url_request_->GetLoadState().state;
+}
+
+base::WeakPtr<URLLoader> URLLoader::GetWeakPtrForTests() {
+ return weak_ptr_factory_.GetWeakPtr();
+}
+
+void URLLoader::NotifyCompleted(int error_code) {
+ // Ensure sending the final upload progress message here, since
+ // OnResponseCompleted can be called without OnResponseStarted on cancellation
+ // or error cases.
+ if (upload_progress_tracker_) {
+ upload_progress_tracker_->OnUploadCompleted();
+ upload_progress_tracker_ = nullptr;
+ }
+
+ if (consumer_handle_.is_valid())
+ SendResponseToClient();
+
+ URLLoaderCompletionStatus status;
+ status.error_code = error_code;
+ status.exists_in_cache = url_request_->response_info().was_cached;
+ status.completion_time = base::TimeTicks::Now();
+ status.encoded_data_length = url_request_->GetTotalReceivedBytes();
+ status.encoded_body_length = url_request_->GetRawBodyBytes();
+ status.decoded_body_length = total_written_bytes_;
+
+ if ((options_ & mojom::kURLLoadOptionSendSSLInfoForCertificateError) &&
+ net::IsCertStatusError(url_request_->ssl_info().cert_status) &&
+ !net::IsCertStatusMinorError(url_request_->ssl_info().cert_status)) {
+ status.ssl_info = url_request_->ssl_info();
+ }
+
+ url_loader_client_->OnComplete(status);
+ DeleteIfNeeded();
+}
+
+void URLLoader::OnConnectionError() {
+ connected_ = false;
+ DeleteIfNeeded();
+}
+
+void URLLoader::OnResponseBodyStreamConsumerClosed(MojoResult result) {
+ CloseResponseBodyStreamProducer();
+}
+
+void URLLoader::OnResponseBodyStreamReady(MojoResult result) {
+ if (result != MOJO_RESULT_OK) {
+ CloseResponseBodyStreamProducer();
+ return;
+ }
+
+ ReadMore();
+}
+
+void URLLoader::CloseResponseBodyStreamProducer() {
+ RecordBodyReadFromNetBeforePausedIfNeeded();
+
+ resource_scheduler_request_handle_.reset();
+ url_request_.reset();
+ peer_closed_handle_watcher_.Cancel();
+ writable_handle_watcher_.Cancel();
+ response_body_stream_.reset();
+
+ pending_write_buffer_offset_ = 0;
+ pending_write_ = nullptr;
+
+ // Make sure if a ResumeReadingBodyFromNet() call is received later, we don't
+ // try to do ReadMore().
+ paused_reading_body_ = false;
+
+ DeleteIfNeeded();
+}
+
+void URLLoader::DeleteIfNeeded() {
+ if (!connected_ && !HasDataPipe())
+ delete this;
+}
+
+void URLLoader::SendResponseToClient() {
+ base::Optional<net::SSLInfo> ssl_info;
+ if (options_ & mojom::kURLLoadOptionSendSSLInfoWithResponse)
+ ssl_info = url_request_->ssl_info();
+ mojom::DownloadedTempFilePtr downloaded_file_ptr;
+ url_loader_client_->OnReceiveResponse(response_->head, ssl_info,
+ std::move(downloaded_file_ptr));
+
+ net::IOBufferWithSize* metadata =
+ url_request_->response_info().metadata.get();
+ if (metadata) {
+ const uint8_t* data = reinterpret_cast<const uint8_t*>(metadata->data());
+
+ url_loader_client_->OnReceiveCachedMetadata(
+ std::vector<uint8_t>(data, data + metadata->size()));
+ }
+
+ url_loader_client_->OnStartLoadingResponseBody(std::move(consumer_handle_));
+ response_ = nullptr;
+}
+
+void URLLoader::CompletePendingWrite() {
+ response_body_stream_ =
+ pending_write_->Complete(pending_write_buffer_offset_);
+ total_written_bytes_ += pending_write_buffer_offset_;
+ pending_write_ = nullptr;
+ pending_write_buffer_offset_ = 0;
+}
+
+void URLLoader::SetRawResponseHeaders(
+ scoped_refptr<const net::HttpResponseHeaders> headers) {
+ raw_response_headers_ = headers;
+}
+
+void URLLoader::SendUploadProgress(const net::UploadProgress& progress) {
+ url_loader_client_->OnUploadProgress(
+ progress.position(), progress.size(),
+ base::BindOnce(&URLLoader::OnUploadProgressACK,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void URLLoader::OnUploadProgressACK() {
+ if (upload_progress_tracker_)
+ upload_progress_tracker_->OnAckReceived();
+}
+
+void URLLoader::OnSSLCertificateErrorResponse(const net::SSLInfo& ssl_info,
+ int net_error) {
+ // The request can be NULL if it was cancelled by the client.
+ if (!url_request_ || !url_request_->is_pending())
+ return;
+
+ if (net_error == net::OK) {
+ url_request_->ContinueDespiteLastError();
+ return;
+ }
+
+ url_request_->CancelWithSSLError(net_error, ssl_info);
+}
+
+void URLLoader::OnCertificateRequestedResponse(
+ const scoped_refptr<net::X509Certificate>& x509_certificate,
+ const std::vector<uint16_t>& algorithm_preferences,
+ mojom::SSLPrivateKeyPtr ssl_private_key,
+ bool cancel_certificate_selection) {
+ if (cancel_certificate_selection) {
+ url_request_->CancelWithError(net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED);
+ } else {
+ if (x509_certificate) {
+ scoped_refptr<net::SSLPrivateKey> key(new SSLPrivateKeyInternal(
+ algorithm_preferences, std::move(ssl_private_key)));
+ url_request_->ContinueWithCertificate(std::move(x509_certificate),
+ std::move(key));
+ } else {
+ url_request_->ContinueWithCertificate(nullptr, nullptr);
+ }
+ }
+}
+
+void URLLoader::OnAuthRequiredResponse(
+ const base::Optional<net::AuthCredentials>& credentials) {
+ if (!url_request_)
+ return;
+
+ if (!credentials.has_value()) {
+ url_request_->CancelAuth();
+ } else {
+ url_request_->SetAuth(credentials.value());
+ }
+}
+
+bool URLLoader::HasDataPipe() const {
+ return pending_write_ || response_body_stream_.is_valid();
+}
+
+void URLLoader::RecordBodyReadFromNetBeforePausedIfNeeded() {
+ if (!url_request_)
+ return;
+
+ if (update_body_read_before_paused_)
+ body_read_before_paused_ = url_request_->GetRawBodyBytes();
+ if (body_read_before_paused_ != -1) {
+ if (!url_request_->was_cached()) {
+ UMA_HISTOGRAM_COUNTS_1M("Network.URLLoader.BodyReadFromNetBeforePaused",
+ body_read_before_paused_);
+ } else {
+ DVLOG(1) << "The request has been paused, but "
+ << "Network.URLLoader.BodyReadFromNetBeforePaused is not "
+ << "reported because the response body may be from cache. "
+ << "body_read_before_paused_: " << body_read_before_paused_;
+ }
+ }
+}
+
+} // namespace network
diff --git a/chromium/services/network/url_loader.h b/chromium/services/network/url_loader.h
new file mode 100644
index 00000000000..726cb033b77
--- /dev/null
+++ b/chromium/services/network/url_loader.h
@@ -0,0 +1,180 @@
+// 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 SERVICES_NETWORK_URL_LOADER_H_
+#define SERVICES_NETWORK_URL_LOADER_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/base/load_states.h"
+#include "net/http/http_raw_request_headers.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context_getter_observer.h"
+#include "services/network/keepalive_statistics_recorder.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/resource_scheduler.h"
+#include "services/network/resource_scheduler_client.h"
+#include "services/network/upload_progress_tracker.h"
+
+namespace net {
+class HttpResponseHeaders;
+class URLRequestContextGetter;
+}
+
+namespace network {
+
+class NetToMojoPendingBuffer;
+class KeepaliveStatisticsRecorder;
+struct ResourceResponse;
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) URLLoader
+ : public mojom::URLLoader,
+ public net::URLRequest::Delegate,
+ public net::URLRequestContextGetterObserver {
+ public:
+ URLLoader(
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter,
+ mojom::NetworkServiceClient* network_service_client,
+ mojom::URLLoaderRequest url_loader_request,
+ int32_t options,
+ const ResourceRequest& request,
+ bool report_raw_headers,
+ mojom::URLLoaderClientPtr url_loader_client,
+ const net::NetworkTrafficAnnotationTag& traffic_annotation,
+ uint32_t process_id,
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client,
+ base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder);
+ ~URLLoader() override;
+
+ // mojom::URLLoader implementation:
+ void FollowRedirect() override;
+ void ProceedWithResponse() override;
+ void SetPriority(net::RequestPriority priority,
+ int32_t intra_priority_value) override;
+ void PauseReadingBodyFromNet() override;
+ void ResumeReadingBodyFromNet() override;
+
+ // net::URLRequest::Delegate implementation:
+ void OnReceivedRedirect(net::URLRequest* url_request,
+ const net::RedirectInfo& redirect_info,
+ bool* defer_redirect) override;
+ void OnAuthRequired(net::URLRequest* request,
+ net::AuthChallengeInfo* info) override;
+ void OnCertificateRequested(net::URLRequest* request,
+ net::SSLCertRequestInfo* info) override;
+ void OnSSLCertificateError(net::URLRequest* request,
+ const net::SSLInfo& info,
+ bool fatal) override;
+ void OnResponseStarted(net::URLRequest* url_request, int net_error) override;
+ void OnReadCompleted(net::URLRequest* url_request, int bytes_read) override;
+
+ // net::URLRequestContextGetterObserver implementation:
+ void OnContextShuttingDown() override;
+ net::LoadState GetLoadStateForTesting() const;
+
+ // Returns a WeakPtr so tests can validate that the object was destroyed.
+ base::WeakPtr<URLLoader> GetWeakPtrForTests();
+
+ private:
+ void ReadMore();
+ void DidRead(int num_bytes, bool completed_synchronously);
+ void NotifyCompleted(int error_code);
+ void OnConnectionError();
+ void OnResponseBodyStreamConsumerClosed(MojoResult result);
+ void OnResponseBodyStreamReady(MojoResult result);
+ void CloseResponseBodyStreamProducer();
+ void DeleteIfNeeded();
+ void SendResponseToClient();
+ void CompletePendingWrite();
+ void SetRawResponseHeaders(scoped_refptr<const net::HttpResponseHeaders>);
+ void SendUploadProgress(const net::UploadProgress& progress);
+ void OnUploadProgressACK();
+ void OnSSLCertificateErrorResponse(const net::SSLInfo& ssl_info,
+ int net_error);
+ void OnCertificateRequestedResponse(
+ const scoped_refptr<net::X509Certificate>& x509_certificate,
+ const std::vector<uint16_t>& algorithm_preferences,
+ mojom::SSLPrivateKeyPtr ssl_private_key,
+ bool cancel_certificate_selection);
+ void OnAuthRequiredResponse(
+ const base::Optional<net::AuthCredentials>& credentials);
+ bool HasDataPipe() const;
+ void RecordBodyReadFromNetBeforePausedIfNeeded();
+ void ResumeStart();
+
+ scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
+ mojom::NetworkServiceClient* network_service_client_;
+ int32_t options_;
+ int resource_type_;
+ bool is_load_timing_enabled_;
+ uint32_t process_id_;
+ uint32_t render_frame_id_;
+ bool connected_;
+ const bool keepalive_;
+ std::unique_ptr<net::URLRequest> url_request_;
+ mojo::Binding<mojom::URLLoader> binding_;
+ mojom::URLLoaderClientPtr url_loader_client_;
+ int64_t total_written_bytes_ = 0;
+
+ mojo::ScopedDataPipeProducerHandle response_body_stream_;
+ scoped_refptr<NetToMojoPendingBuffer> pending_write_;
+ uint32_t pending_write_buffer_size_ = 0;
+ uint32_t pending_write_buffer_offset_ = 0;
+ mojo::SimpleWatcher writable_handle_watcher_;
+ mojo::SimpleWatcher peer_closed_handle_watcher_;
+
+ // Used when deferring sending the data to the client until mime sniffing is
+ // finished.
+ scoped_refptr<ResourceResponse> response_;
+ mojo::ScopedDataPipeConsumerHandle consumer_handle_;
+
+ std::unique_ptr<ResourceScheduler::ScheduledResourceRequest>
+ resource_scheduler_request_handle_;
+
+ bool report_raw_headers_;
+ net::HttpRawRequestHeaders raw_request_headers_;
+ scoped_refptr<const net::HttpResponseHeaders> raw_response_headers_;
+
+ std::unique_ptr<UploadProgressTracker> upload_progress_tracker_;
+
+ bool should_pause_reading_body_ = false;
+ // The response body stream is open, but transferring data is paused.
+ bool paused_reading_body_ = false;
+
+ // Whether to update |body_read_before_paused_| after the pending read is
+ // completed (or when the response body stream is closed).
+ bool update_body_read_before_paused_ = false;
+ // The number of bytes obtained by the reads initiated before the last
+ // PauseReadingBodyFromNet() call. -1 means the request hasn't been paused.
+ // The body may be read from cache or network. So even if this value is not
+ // -1, we still need to check whether it is from network before reporting it
+ // as BodyReadFromNetBeforePaused.
+ int64_t body_read_before_paused_ = -1;
+
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
+
+ mojom::SSLPrivateKeyPtr ssl_private_key_;
+
+ base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder_;
+
+ bool first_auth_attempt_;
+
+ base::WeakPtrFactory<URLLoader> weak_ptr_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLLoader);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_URL_LOADER_H_
diff --git a/chromium/services/network/url_loader_factory.cc b/chromium/services/network/url_loader_factory.cc
new file mode 100644
index 00000000000..bd42e002988
--- /dev/null
+++ b/chromium/services/network/url_loader_factory.cc
@@ -0,0 +1,74 @@
+// 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 "services/network/url_loader_factory.h"
+
+#include "base/logging.h"
+#include "services/network/network_context.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/resource_scheduler_client.h"
+#include "services/network/url_loader.h"
+
+namespace network {
+
+URLLoaderFactory::URLLoaderFactory(
+ NetworkContext* context,
+ uint32_t process_id,
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client)
+ : context_(context),
+ process_id_(process_id),
+ resource_scheduler_client_(std::move(resource_scheduler_client)) {
+ if (context_->network_service()) {
+ context->network_service()->keepalive_statistics_recorder()->Register(
+ process_id_);
+ }
+}
+
+URLLoaderFactory::~URLLoaderFactory() {
+ if (context_->network_service()) {
+ context_->network_service()->keepalive_statistics_recorder()->Unregister(
+ process_id_);
+ }
+}
+
+void URLLoaderFactory::CreateLoaderAndStart(
+ mojom::URLLoaderRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag& traffic_annotation) {
+ bool report_raw_headers = false;
+ if (url_request.report_raw_headers) {
+ const NetworkService* service = context_->network_service();
+ report_raw_headers = service && service->HasRawHeadersAccess(process_id_);
+ if (!report_raw_headers)
+ DLOG(ERROR) << "Denying raw headers request by process " << process_id_;
+ }
+
+ mojom::NetworkServiceClient* network_service_client = nullptr;
+ base::WeakPtr<KeepaliveStatisticsRecorder> keepalive_statistics_recorder;
+ if (context_->network_service()) {
+ network_service_client = context_->network_service()->client();
+ keepalive_statistics_recorder = context_->network_service()
+ ->keepalive_statistics_recorder()
+ ->AsWeakPtr();
+ }
+ new URLLoader(
+ context_->url_request_context_getter(), network_service_client,
+ std::move(request), options, url_request, report_raw_headers,
+ std::move(client),
+ static_cast<net::NetworkTrafficAnnotationTag>(traffic_annotation),
+ process_id_, resource_scheduler_client_,
+ std::move(keepalive_statistics_recorder));
+}
+
+void URLLoaderFactory::Clone(mojom::URLLoaderFactoryRequest request) {
+ context_->CreateURLLoaderFactory(std::move(request), process_id_,
+ resource_scheduler_client_);
+}
+
+} // namespace network
diff --git a/chromium/services/network/url_loader_factory.h b/chromium/services/network/url_loader_factory.h
new file mode 100644
index 00000000000..22080da76f5
--- /dev/null
+++ b/chromium/services/network/url_loader_factory.h
@@ -0,0 +1,59 @@
+// 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 SERVICES_NETWORK_URL_LOADER_FACTORY_H_
+#define SERVICES_NETWORK_URL_LOADER_FACTORY_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+namespace network {
+
+class NetworkContext;
+class ResourceSchedulerClient;
+
+// This class is an implementation of mojom::URLLoaderFactory that
+// creates a mojom::URLLoader.
+// A URLLoaderFactory has a pointer to ResourceSchedulerClient. A
+// ResourceSchedulerClient is associated with cloned
+// NetworkServiceURLLoaderFactories. Roughly one URLLoaderFactory
+// is created for one frame in render process, so it means ResourceScheduler
+// works on each frame.
+// A URLLoaderFactory can be created with null ResourceSchedulerClient, in which
+// case requests constructed by the factory will not be throttled.
+class URLLoaderFactory : public mojom::URLLoaderFactory {
+ public:
+ // NOTE: |context| must outlive this instance.
+ URLLoaderFactory(
+ NetworkContext* context,
+ uint32_t process_id,
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client);
+
+ ~URLLoaderFactory() override;
+
+ // mojom::URLLoaderFactory implementation.
+ void CreateLoaderAndStart(mojom::URLLoaderRequest request,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const ResourceRequest& url_request,
+ mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag&
+ traffic_annotation) override;
+ void Clone(mojom::URLLoaderFactoryRequest request) override;
+
+ private:
+ // Not owned.
+ NetworkContext* context_;
+ uint32_t process_id_;
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLLoaderFactory);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_URL_LOADER_FACTORY_H_
diff --git a/chromium/services/network/url_loader_unittest.cc b/chromium/services/network/url_loader_unittest.cc
new file mode 100644
index 00000000000..4adcbeed015
--- /dev/null
+++ b/chromium/services/network/url_loader_unittest.cc
@@ -0,0 +1,1411 @@
+// 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 <stdint.h>
+
+#include <limits>
+#include <list>
+#include <memory>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "mojo/common/data_pipe_utils.h"
+#include "mojo/public/c/system/data_pipe.h"
+#include "mojo/public/cpp/system/wait.h"
+#include "net/base/io_buffer.h"
+#include "net/base/load_flags.h"
+#include "net/base/mime_sniffer.h"
+#include "net/base/net_errors.h"
+#include "net/test/cert_test_util.h"
+#include "net/test/embedded_test_server/controllable_http_response.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/test/embedded_test_server/http_response.h"
+#include "net/test/test_data_directory.h"
+#include "net/test/url_request/url_request_failed_job.h"
+#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
+#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "net/url_request/url_request_filter.h"
+#include "net/url_request/url_request_interceptor.h"
+#include "net/url_request/url_request_job.h"
+#include "net/url_request/url_request_status.h"
+#include "net/url_request/url_request_test_job.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/resource_scheduler_client.h"
+#include "services/network/test/test_data_pipe_getter.h"
+#include "services/network/test/test_url_loader_client.h"
+#include "services/network/url_loader.h"
+#include "services/network/url_request_context_owner.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace network {
+
+namespace {
+
+constexpr char kBodyReadFromNetBeforePausedHistogram[] =
+ "Network.URLLoader.BodyReadFromNetBeforePaused";
+
+static ResourceRequest CreateResourceRequest(const char* method,
+ const GURL& url) {
+ ResourceRequest request;
+ request.method = std::string(method);
+ request.url = url;
+ request.site_for_cookies = url; // bypass third-party cookie blocking
+ request.request_initiator =
+ url::Origin::Create(url); // ensure initiator is set
+ request.is_main_frame = true;
+ request.allow_download = true;
+ return request;
+}
+
+class URLRequestMultipleWritesJob : public net::URLRequestJob {
+ public:
+ URLRequestMultipleWritesJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ std::list<std::string> packets,
+ net::Error net_error,
+ bool async_reads)
+ : URLRequestJob(request, network_delegate),
+ packets_(std::move(packets)),
+ net_error_(net_error),
+ async_reads_(async_reads),
+ weak_factory_(this) {}
+
+ // net::URLRequestJob implementation:
+ void Start() override {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::BindOnce(&URLRequestMultipleWritesJob::StartAsync,
+ weak_factory_.GetWeakPtr()));
+ }
+
+ int ReadRawData(net::IOBuffer* buf, int buf_size) override {
+ int result;
+ if (packets_.empty()) {
+ result = net_error_;
+ } else {
+ std::string packet = packets_.front();
+ packets_.pop_front();
+ CHECK_GE(buf_size, static_cast<int>(packet.length()));
+ memcpy(buf->data(), packet.c_str(), packet.length());
+ result = packet.length();
+ }
+
+ if (async_reads_) {
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(&URLRequestMultipleWritesJob::ReadRawDataComplete,
+ weak_factory_.GetWeakPtr(), result));
+ return net::ERR_IO_PENDING;
+ }
+ return result;
+ }
+
+ private:
+ ~URLRequestMultipleWritesJob() override {}
+
+ void StartAsync() { NotifyHeadersComplete(); }
+
+ std::list<std::string> packets_;
+ net::Error net_error_;
+ bool async_reads_;
+
+ base::WeakPtrFactory<URLRequestMultipleWritesJob> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLRequestMultipleWritesJob);
+};
+
+class MultipleWritesInterceptor : public net::URLRequestInterceptor {
+ public:
+ MultipleWritesInterceptor(std::list<std::string> packets,
+ net::Error net_error,
+ bool async_reads)
+ : packets_(std::move(packets)),
+ net_error_(net_error),
+ async_reads_(async_reads) {}
+ ~MultipleWritesInterceptor() override {}
+
+ static GURL GetURL() { return GURL("http://foo"); }
+
+ // URLRequestInterceptor implementation:
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return new URLRequestMultipleWritesJob(request, network_delegate,
+ std::move(packets_), net_error_,
+ async_reads_);
+ }
+
+ private:
+ std::list<std::string> packets_;
+ net::Error net_error_;
+ bool async_reads_;
+
+ DISALLOW_COPY_AND_ASSIGN(MultipleWritesInterceptor);
+};
+
+class RequestInterceptor : public net::URLRequestInterceptor {
+ public:
+ using InterceptCallback = base::Callback<void(net::URLRequest*)>;
+
+ explicit RequestInterceptor(const InterceptCallback& callback)
+ : callback_(callback) {}
+ ~RequestInterceptor() override {}
+
+ // URLRequestInterceptor implementation:
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ callback_.Run(request);
+ return nullptr;
+ }
+
+ private:
+ InterceptCallback callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(RequestInterceptor);
+};
+
+// Returns whether monitoring was successfully set up. If yes,
+// StopMonitorBodyReadFromNetBeforePausedHistogram() needs to be called later to
+// stop monitoring.
+//
+// |*output_sample| needs to stay valid until monitoring is stopped.
+WARN_UNUSED_RESULT bool StartMonitorBodyReadFromNetBeforePausedHistogram(
+ const base::RepeatingClosure& quit_closure,
+ base::HistogramBase::Sample* output_sample) {
+ return base::StatisticsRecorder::SetCallback(
+ kBodyReadFromNetBeforePausedHistogram,
+ base::BindRepeating(
+ [](const base::RepeatingClosure& quit_closure,
+ base::HistogramBase::Sample* output,
+ base::HistogramBase::Sample sample) {
+ *output = sample;
+ quit_closure.Run();
+ },
+ quit_closure, output_sample));
+}
+
+void StopMonitorBodyReadFromNetBeforePausedHistogram() {
+ base::StatisticsRecorder::ClearCallback(
+ kBodyReadFromNetBeforePausedHistogram);
+}
+
+} // namespace
+
+class URLLoaderTest : public testing::Test {
+ public:
+ URLLoaderTest()
+ : scoped_task_environment_(
+ base::test::ScopedTaskEnvironment::MainThreadType::IO),
+ resource_scheduler_(true) {
+ net::URLRequestContextBuilder context_builder;
+ context_builder.set_proxy_resolution_service(
+ net::ProxyResolutionService::CreateDirect());
+ context_ =
+ new network::NetworkURLRequestContextGetter(context_builder.Build());
+ resource_scheduler_client_ = base::MakeRefCounted<ResourceSchedulerClient>(
+ kProcessId, kRouteId, &resource_scheduler_,
+ context_->GetURLRequestContext()->network_quality_estimator());
+ net::URLRequestFailedJob::AddUrlHandler();
+ }
+ ~URLLoaderTest() override {
+ net::URLRequestFilter::GetInstance()->ClearHandlers();
+ }
+
+ void SetUp() override {
+ test_server_.AddDefaultHandlers(
+ base::FilePath(FILE_PATH_LITERAL("services/test/data")));
+ // This Unretained is safe because test_server_ is owned by |this|.
+ test_server_.RegisterRequestMonitor(
+ base::Bind(&URLLoaderTest::Monitor, base::Unretained(this)));
+ ASSERT_TRUE(test_server_.Start());
+ }
+
+ // Attempts to load |url| and returns the resulting error code. If |body| is
+ // non-NULL, also attempts to read the response body. The advantage of using
+ // |body| instead of calling ReadBody() after Load is that it will load the
+ // response body before URLLoader is complete, so URLLoader completion won't
+ // block on trying to write the body buffer.
+ int Load(const GURL& url, std::string* body = nullptr) WARN_UNUSED_RESULT {
+ DCHECK(!ran_);
+ mojom::URLLoaderPtr loader;
+
+ ResourceRequest request =
+ CreateResourceRequest(!request_body_ ? "GET" : "POST", url);
+ uint32_t options = mojom::kURLLoadOptionNone;
+ if (send_ssl_with_response_)
+ options |= mojom::kURLLoadOptionSendSSLInfoWithResponse;
+ if (sniff_)
+ options |= mojom::kURLLoadOptionSniffMimeType;
+ if (send_ssl_for_cert_error_)
+ options |= mojom::kURLLoadOptionSendSSLInfoForCertificateError;
+
+ if (request_body_)
+ request.request_body = request_body_;
+
+ URLLoader loader_impl(context(), nullptr, mojo::MakeRequest(&loader),
+ options, request, false, client_.CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, 0,
+ resource_scheduler_client(), nullptr);
+
+ ran_ = true;
+
+ if (expect_redirect_) {
+ client_.RunUntilRedirectReceived();
+ loader->FollowRedirect();
+ }
+
+ if (body) {
+ client_.RunUntilResponseBodyArrived();
+ *body = ReadBody();
+ }
+
+ client_.RunUntilComplete();
+ if (body) {
+ EXPECT_EQ(body->size(),
+ static_cast<size_t>(
+ client()->completion_status().decoded_body_length));
+ }
+
+ return client_.completion_status().error_code;
+ }
+
+ void LoadAndCompareFile(const std::string& path) {
+ base::FilePath file = GetTestFilePath(path);
+
+ std::string expected;
+ if (!base::ReadFileToString(file, &expected)) {
+ ADD_FAILURE() << "File not found: " << file.value();
+ return;
+ }
+
+ std::string body;
+ EXPECT_EQ(net::OK,
+ Load(test_server()->GetURL(std::string("/") + path), &body));
+ EXPECT_EQ(expected, body);
+ // The file isn't compressed, so both encoded and decoded body lengths
+ // should match the read body length.
+ EXPECT_EQ(
+ expected.size(),
+ static_cast<size_t>(client()->completion_status().decoded_body_length));
+ EXPECT_EQ(
+ expected.size(),
+ static_cast<size_t>(client()->completion_status().encoded_body_length));
+ // Over the wire length should include headers, so should be longer.
+ // TODO(mmenke): Worth adding better tests for encoded_data_length?
+ EXPECT_LT(
+ expected.size(),
+ static_cast<size_t>(client()->completion_status().encoded_data_length));
+ }
+
+ // Adds a MultipleWritesInterceptor for MultipleWritesInterceptor::GetURL()
+ // that results in seeing each element of |packets| read individually, and
+ // then a final read that returns |net_error|. The URLRequestInterceptor is
+ // not removed from URLFilter until the test fixture is torn down.
+ // |async_reads| indicates whether all reads (including those for |packets|
+ // and |net_error|) complete asynchronously or not.
+ void AddMultipleWritesInterceptor(std::list<std::string> packets,
+ net::Error net_error,
+ bool async_reads) {
+ net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+ MultipleWritesInterceptor::GetURL(),
+ std::unique_ptr<net::URLRequestInterceptor>(
+ new MultipleWritesInterceptor(std::move(packets), net_error,
+ async_reads)));
+ }
+
+ // If |second| is empty, then it's ignored.
+ void LoadPacketsAndVerifyContents(const std::string& first,
+ const std::string& second) {
+ EXPECT_FALSE(first.empty());
+ std::list<std::string> packets;
+ packets.push_back(first);
+ if (!second.empty())
+ packets.push_back(second);
+ AddMultipleWritesInterceptor(std::move(packets), net::OK,
+ false /* async_reads */);
+
+ std::string expected_body = first + second;
+ std::string actual_body;
+ EXPECT_EQ(net::OK, Load(MultipleWritesInterceptor::GetURL(), &actual_body));
+
+ EXPECT_EQ(actual_body, expected_body);
+ }
+
+ // Adds an interceptor that can examine the URLRequest object.
+ void AddRequestObserver(
+ const GURL& url,
+ const RequestInterceptor::InterceptCallback& callback) {
+ net::URLRequestFilter::GetInstance()->AddUrlInterceptor(
+ url, std::unique_ptr<net::URLRequestInterceptor>(
+ new RequestInterceptor(callback)));
+ }
+
+ net::EmbeddedTestServer* test_server() { return &test_server_; }
+ net::URLRequestContextGetter* context() { return context_.get(); }
+ TestURLLoaderClient* client() { return &client_; }
+ void DestroyContext() {
+ resource_scheduler_client_ = nullptr;
+ context_->NotifyContextShuttingDown();
+ }
+
+ // Returns the path of the requested file in the test data directory.
+ base::FilePath GetTestFilePath(const std::string& file_name) {
+ base::FilePath file_path;
+ PathService::Get(base::DIR_SOURCE_ROOT, &file_path);
+ file_path = file_path.Append(FILE_PATH_LITERAL("services"));
+ file_path = file_path.Append(FILE_PATH_LITERAL("test"));
+ file_path = file_path.Append(FILE_PATH_LITERAL("data"));
+ return file_path.AppendASCII(file_name);
+ }
+
+ base::File OpenFileForUpload(const base::FilePath& file_path) {
+ int open_flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
+#if defined(OS_WIN)
+ open_flags |= base::File::FLAG_ASYNC;
+#endif // defined(OS_WIN)
+ base::File file(file_path, open_flags);
+ EXPECT_TRUE(file.IsValid());
+ return file;
+ }
+
+ ResourceScheduler* resource_scheduler() { return &resource_scheduler_; }
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client() {
+ return resource_scheduler_client_;
+ }
+
+ // Configure how Load() works.
+ void set_sniff() {
+ DCHECK(!ran_);
+ sniff_ = true;
+ }
+ void set_send_ssl_with_response() {
+ DCHECK(!ran_);
+ send_ssl_with_response_ = true;
+ }
+ void set_send_ssl_for_cert_error() {
+ DCHECK(!ran_);
+ send_ssl_for_cert_error_ = true;
+ }
+ void set_expect_redirect() {
+ DCHECK(!ran_);
+ expect_redirect_ = true;
+ }
+ void set_request_body(scoped_refptr<ResourceRequestBody> request_body) {
+ request_body_ = request_body;
+ }
+
+ // Convenience methods after calling Load();
+ std::string mime_type() const {
+ DCHECK(ran_);
+ return client_.response_head().mime_type;
+ }
+ const base::Optional<net::SSLInfo>& ssl_info() const {
+ DCHECK(ran_);
+ return client_.ssl_info();
+ }
+
+ // Reads the response body from client()->response_body() until the channel is
+ // closed. Expects client()->response_body() to already be populated, and
+ // non-NULL.
+ std::string ReadBody() {
+ std::string body;
+ while (true) {
+ MojoHandle consumer = client()->response_body().value();
+
+ const void* buffer;
+ uint32_t num_bytes;
+ MojoResult rv = MojoBeginReadData(consumer, &buffer, &num_bytes,
+ MOJO_READ_DATA_FLAG_NONE);
+ // If no data has been received yet, spin the message loop until it has.
+ if (rv == MOJO_RESULT_SHOULD_WAIT) {
+ mojo::SimpleWatcher watcher(
+ FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC);
+ base::RunLoop run_loop;
+
+ watcher.Watch(
+ client()->response_body(),
+ MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_PEER_CLOSED,
+ MOJO_WATCH_CONDITION_SATISFIED,
+ base::BindRepeating(
+ [](base::Closure quit, MojoResult result,
+ const mojo::HandleSignalsState& state) { quit.Run(); },
+ run_loop.QuitClosure()));
+ run_loop.Run();
+ continue;
+ }
+
+ // The pipe was closed.
+ if (rv == MOJO_RESULT_FAILED_PRECONDITION)
+ return body;
+
+ CHECK_EQ(rv, MOJO_RESULT_OK);
+
+ body.append(static_cast<const char*>(buffer), num_bytes);
+ MojoEndReadData(consumer, num_bytes);
+ }
+
+ return body;
+ }
+
+ std::string ReadAvailableBody() {
+ MojoHandle consumer = client()->response_body().value();
+
+ uint32_t num_bytes = 0;
+ MojoResult result =
+ MojoReadData(consumer, nullptr, &num_bytes, MOJO_READ_DATA_FLAG_QUERY);
+ CHECK_EQ(MOJO_RESULT_OK, result);
+ if (num_bytes == 0)
+ return std::string();
+
+ std::vector<char> buffer(num_bytes);
+ result = MojoReadData(consumer, buffer.data(), &num_bytes,
+ MOJO_READ_DATA_FLAG_NONE);
+ CHECK_EQ(MOJO_RESULT_OK, result);
+ CHECK_EQ(num_bytes, buffer.size());
+
+ return std::string(buffer.data(), buffer.size());
+ }
+
+ const net::test_server::HttpRequest& sent_request() const {
+ return sent_request_;
+ }
+
+ static constexpr int kProcessId = 4;
+ static constexpr int kRouteId = 8;
+
+ private:
+ void Monitor(const net::test_server::HttpRequest& request) {
+ sent_request_ = request;
+ }
+
+ base::test::ScopedTaskEnvironment scoped_task_environment_;
+ net::EmbeddedTestServer test_server_;
+ scoped_refptr<NetworkURLRequestContextGetter> context_;
+ ResourceScheduler resource_scheduler_;
+ scoped_refptr<ResourceSchedulerClient> resource_scheduler_client_;
+
+ // Options applied to the created request in Load().
+ bool sniff_ = false;
+ bool send_ssl_with_response_ = false;
+ bool send_ssl_for_cert_error_ = false;
+ bool expect_redirect_ = false;
+ scoped_refptr<ResourceRequestBody> request_body_;
+
+ // Used to ensure that methods are called either before or after a request is
+ // made, since the test fixture is meant to be used only once.
+ bool ran_ = false;
+ net::test_server::HttpRequest sent_request_;
+ TestURLLoaderClient client_;
+};
+
+constexpr int URLLoaderTest::kProcessId;
+constexpr int URLLoaderTest::kRouteId;
+
+TEST_F(URLLoaderTest, Basic) {
+ LoadAndCompareFile("simple_page.html");
+}
+
+TEST_F(URLLoaderTest, Empty) {
+ LoadAndCompareFile("empty.html");
+}
+
+TEST_F(URLLoaderTest, BasicSSL) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.ServeFilesFromSourceDirectory(
+ base::FilePath(FILE_PATH_LITERAL("services/test/data")));
+ ASSERT_TRUE(https_server.Start());
+
+ GURL url = https_server.GetURL("/simple_page.html");
+ set_send_ssl_with_response();
+ EXPECT_EQ(net::OK, Load(url));
+ ASSERT_TRUE(!!ssl_info());
+ ASSERT_TRUE(!!ssl_info()->cert);
+
+ ASSERT_TRUE(https_server.GetCertificate()->Equals(ssl_info()->cert.get()));
+}
+
+TEST_F(URLLoaderTest, SSLSentOnlyWhenRequested) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.ServeFilesFromSourceDirectory(
+ base::FilePath(FILE_PATH_LITERAL("services/test/data")));
+ ASSERT_TRUE(https_server.Start());
+
+ GURL url = https_server.GetURL("/simple_page.html");
+ EXPECT_EQ(net::OK, Load(url));
+ ASSERT_FALSE(!!ssl_info());
+}
+
+// Test decoded_body_length / encoded_body_length when they're different.
+TEST_F(URLLoaderTest, GzipTest) {
+ std::string body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/gzip-body?Body"), &body));
+ EXPECT_EQ("Body", body);
+ // Deflating a 4-byte string should result in a longer string - main thing to
+ // check here, though, is that the two lengths are of different.
+ EXPECT_LT(client()->completion_status().decoded_body_length,
+ client()->completion_status().encoded_body_length);
+ // Over the wire length should include headers, so should be longer.
+ EXPECT_LT(client()->completion_status().encoded_body_length,
+ client()->completion_status().encoded_data_length);
+}
+
+TEST_F(URLLoaderTest, ErrorBeforeHeaders) {
+ EXPECT_EQ(net::ERR_EMPTY_RESPONSE,
+ Load(test_server()->GetURL("/close-socket"), nullptr));
+ EXPECT_FALSE(client()->response_body().is_valid());
+}
+
+TEST_F(URLLoaderTest, SyncErrorWhileReadingBody) {
+ std::string body;
+ EXPECT_EQ(net::ERR_FAILED,
+ Load(net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
+ net::URLRequestFailedJob::READ_SYNC, net::ERR_FAILED),
+ &body));
+ EXPECT_EQ("", body);
+}
+
+TEST_F(URLLoaderTest, AsyncErrorWhileReadingBody) {
+ std::string body;
+ EXPECT_EQ(net::ERR_FAILED,
+ Load(net::URLRequestFailedJob::GetMockHttpUrlWithFailurePhase(
+ net::URLRequestFailedJob::READ_ASYNC, net::ERR_FAILED),
+ &body));
+ EXPECT_EQ("", body);
+}
+
+TEST_F(URLLoaderTest, SyncErrorWhileReadingBodyAfterBytesReceived) {
+ const std::string kBody("Foo.");
+
+ std::list<std::string> packets;
+ packets.push_back(kBody);
+ AddMultipleWritesInterceptor(packets, net::ERR_ACCESS_DENIED,
+ false /*async_reads*/);
+ std::string body;
+ EXPECT_EQ(net::ERR_ACCESS_DENIED,
+ Load(MultipleWritesInterceptor::GetURL(), &body));
+ EXPECT_EQ(kBody, body);
+}
+
+TEST_F(URLLoaderTest, AsyncErrorWhileReadingBodyAfterBytesReceived) {
+ const std::string kBody("Foo.");
+
+ std::list<std::string> packets;
+ packets.push_back(kBody);
+ AddMultipleWritesInterceptor(packets, net::ERR_ACCESS_DENIED,
+ true /*async_reads*/);
+ std::string body;
+ EXPECT_EQ(net::ERR_ACCESS_DENIED,
+ Load(MultipleWritesInterceptor::GetURL(), &body));
+ EXPECT_EQ(kBody, body);
+}
+
+TEST_F(URLLoaderTest, DestroyContextWithLiveRequest) {
+ GURL url = test_server()->GetURL("/hung-after-headers");
+ ResourceRequest request = CreateResourceRequest("GET", url);
+
+ mojom::URLLoaderPtr loader;
+ // The loader is implicitly owned by the client and the NetworkContext, so
+ // don't hold on to a pointer to it.
+ base::WeakPtr<URLLoader> loader_impl =
+ (new URLLoader(context(), nullptr, mojo::MakeRequest(&loader), 0, request,
+ false, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, 0,
+ resource_scheduler_client(), nullptr))
+ ->GetWeakPtrForTests();
+
+ client()->RunUntilResponseReceived();
+ EXPECT_TRUE(client()->has_received_response());
+ EXPECT_FALSE(client()->has_received_completion());
+
+ // Request hasn't completed, so the loader should not have been destroyed.
+ EXPECT_TRUE(loader_impl);
+
+ // Destroying the context should result in destroying the loader and the
+ // client receiving a connection error.
+ DestroyContext();
+ EXPECT_FALSE(loader_impl);
+
+ client()->RunUntilConnectionError();
+ EXPECT_FALSE(client()->has_received_completion());
+ EXPECT_EQ(0u, client()->download_data_length());
+}
+
+TEST_F(URLLoaderTest, DoNotSniffUnlessSpecified) {
+ EXPECT_EQ(net::OK,
+ Load(test_server()->GetURL("/content-sniffer-test0.html")));
+ ASSERT_TRUE(mime_type().empty());
+}
+
+TEST_F(URLLoaderTest, SniffMimeType) {
+ set_sniff();
+ EXPECT_EQ(net::OK,
+ Load(test_server()->GetURL("/content-sniffer-test0.html")));
+ ASSERT_EQ(std::string("text/html"), mime_type());
+}
+
+TEST_F(URLLoaderTest, RespectNoSniff) {
+ set_sniff();
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/nosniff-test.html")));
+ ASSERT_TRUE(mime_type().empty());
+}
+
+TEST_F(URLLoaderTest, DoNotSniffHTMLFromTextPlain) {
+ set_sniff();
+ EXPECT_EQ(net::OK,
+ Load(test_server()->GetURL("/content-sniffer-test1.html")));
+ ASSERT_EQ(std::string("text/plain"), mime_type());
+}
+
+TEST_F(URLLoaderTest, DoNotSniffHTMLFromImageGIF) {
+ set_sniff();
+ EXPECT_EQ(net::OK,
+ Load(test_server()->GetURL("/content-sniffer-test2.html")));
+ ASSERT_EQ(std::string("image/gif"), mime_type());
+}
+
+TEST_F(URLLoaderTest, EmptyHtmlIsTextPlain) {
+ set_sniff();
+ EXPECT_EQ(net::OK,
+ Load(test_server()->GetURL("/content-sniffer-test4.html")));
+ ASSERT_EQ(std::string("text/plain"), mime_type());
+}
+
+TEST_F(URLLoaderTest, EmptyHtmlIsTextPlainWithAsyncResponse) {
+ set_sniff();
+
+ const std::string kBody;
+
+ std::list<std::string> packets;
+ packets.push_back(kBody);
+ AddMultipleWritesInterceptor(packets, net::OK, true /*async_reads*/);
+
+ std::string body;
+ EXPECT_EQ(net::OK, Load(MultipleWritesInterceptor::GetURL(), &body));
+ EXPECT_EQ(kBody, body);
+ ASSERT_EQ(std::string("text/plain"), mime_type());
+}
+
+// Tests the case where the first read doesn't have enough data to figure out
+// the right mime type. The second read would have enough data even though the
+// total bytes is still smaller than net::kMaxBytesToSniff.
+TEST_F(URLLoaderTest, FirstReadNotEnoughToSniff1) {
+ set_sniff();
+ std::string first(500, 'a');
+ std::string second(std::string(100, 'b'));
+ second[10] = 0;
+ EXPECT_LE(first.size() + second.size(),
+ static_cast<uint32_t>(net::kMaxBytesToSniff));
+ LoadPacketsAndVerifyContents(first, second);
+ ASSERT_EQ(std::string("application/octet-stream"), mime_type());
+}
+
+// Like above, except that the total byte count is > kMaxBytesToSniff.
+TEST_F(URLLoaderTest, FirstReadNotEnoughToSniff2) {
+ set_sniff();
+ std::string first(500, 'a');
+ std::string second(std::string(1000, 'b'));
+ second[10] = 0;
+ EXPECT_GE(first.size() + second.size(),
+ static_cast<uint32_t>(net::kMaxBytesToSniff));
+ LoadPacketsAndVerifyContents(first, second);
+ ASSERT_EQ(std::string("application/octet-stream"), mime_type());
+}
+
+// Tests that even if the first and only read is smaller than the minimum number
+// of bytes needed to sniff, the loader works correctly and returns the data.
+TEST_F(URLLoaderTest, LoneReadNotEnoughToSniff) {
+ set_sniff();
+ std::string first(net::kMaxBytesToSniff - 100, 'a');
+ LoadPacketsAndVerifyContents(first, std::string());
+ ASSERT_EQ(std::string("text/plain"), mime_type());
+}
+
+// Tests the simple case where the first read is enough to sniff.
+TEST_F(URLLoaderTest, FirstReadIsEnoughToSniff) {
+ set_sniff();
+ std::string first(net::kMaxBytesToSniff + 100, 'a');
+ LoadPacketsAndVerifyContents(first, std::string());
+ ASSERT_EQ(std::string("text/plain"), mime_type());
+}
+
+class NeverFinishedBodyHttpResponse : public net::test_server::HttpResponse {
+ public:
+ NeverFinishedBodyHttpResponse() = default;
+ ~NeverFinishedBodyHttpResponse() override = default;
+
+ private:
+ // net::test_server::HttpResponse implementation.
+ void SendResponse(
+ const net::test_server::SendBytesCallback& send,
+ const net::test_server::SendCompleteCallback& done) override {
+ send.Run(
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n"
+ "long long ago..." +
+ std::string(1024 * 1024, 'a'),
+ base::DoNothing());
+
+ // Never call |done|, so the other side will never see the completion of the
+ // response body.
+ }
+};
+
+TEST_F(URLLoaderTest, CloseResponseBodyConsumerBeforeProducer) {
+ net::EmbeddedTestServer server;
+ server.RegisterRequestHandler(
+ base::Bind([](const net::test_server::HttpRequest& request) {
+ std::unique_ptr<net::test_server::HttpResponse> response =
+ std::make_unique<NeverFinishedBodyHttpResponse>();
+ return response;
+ }));
+ ASSERT_TRUE(server.Start());
+
+ ResourceRequest request =
+ CreateResourceRequest("GET", server.GetURL("/hello.html"));
+
+ mojom::URLLoaderPtr loader;
+ // The loader is implicitly owned by the client and the NetworkContext.
+ new URLLoader(context(), nullptr, mojo::MakeRequest(&loader), 0, request,
+ false, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, 0, resource_scheduler_client(),
+ nullptr);
+
+ client()->RunUntilResponseBodyArrived();
+ EXPECT_TRUE(client()->has_received_response());
+ EXPECT_FALSE(client()->has_received_completion());
+
+ // Wait for a little amount of time for the response body pipe to be filled.
+ // (Please note that this doesn't guarantee that the pipe is filled to the
+ // point that it is not writable anymore.)
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(100));
+ run_loop.Run();
+
+ auto response_body = client()->response_body_release();
+ response_body.reset();
+ loader.reset();
+
+ // The client is disconnected only when the other side observes that both the
+ // URLLoaderPtr and the response body pipe are disconnected.
+ client()->RunUntilConnectionError();
+
+ EXPECT_FALSE(client()->has_received_completion());
+}
+
+TEST_F(URLLoaderTest, PauseReadingBodyFromNetBeforeRespnoseHeaders) {
+ const char* const kPath = "/hello.html";
+ const char* const kBodyContents = "This is the data as you requested.";
+
+ base::HistogramBase::Sample output_sample = -1;
+ base::RunLoop histogram_run_loop;
+ EXPECT_TRUE(StartMonitorBodyReadFromNetBeforePausedHistogram(
+ histogram_run_loop.QuitClosure(), &output_sample));
+
+ net::EmbeddedTestServer server;
+ net::test_server::ControllableHttpResponse response_controller(&server,
+ kPath);
+ ASSERT_TRUE(server.Start());
+
+ ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
+
+ mojom::URLLoaderPtr loader;
+ // The loader is implicitly owned by the client and the NetworkContext.
+ new URLLoader(context(), nullptr, mojo::MakeRequest(&loader), 0, request,
+ false, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, 0, resource_scheduler_client(),
+ nullptr);
+
+ // Pausing reading response body from network stops future reads from the
+ // underlying URLRequest. So no data should be sent using the response body
+ // data pipe.
+ loader->PauseReadingBodyFromNet();
+ // In order to avoid flakiness, make sure PauseReadBodyFromNet() is handled by
+ // the loader before the test HTTP server serves the response.
+ loader.FlushForTesting();
+
+ response_controller.WaitForRequest();
+ response_controller.Send(
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n" +
+ std::string(kBodyContents));
+ response_controller.Done();
+
+ // We will still receive the response body data pipe, although there won't be
+ // any data available until ResumeReadBodyFromNet() is called.
+ client()->RunUntilResponseBodyArrived();
+ EXPECT_TRUE(client()->has_received_response());
+ EXPECT_FALSE(client()->has_received_completion());
+
+ // Wait for a little amount of time so that if the loader mistakenly reads
+ // response body from the underlying URLRequest, it is easier to find out.
+ base::RunLoop run_loop;
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE, run_loop.QuitClosure(),
+ base::TimeDelta::FromMilliseconds(100));
+ run_loop.Run();
+
+ std::string available_data = ReadAvailableBody();
+ EXPECT_TRUE(available_data.empty());
+
+ loader->ResumeReadingBodyFromNet();
+ client()->RunUntilComplete();
+
+ available_data = ReadBody();
+ EXPECT_EQ(kBodyContents, available_data);
+
+ loader.reset();
+ client()->Unbind();
+ histogram_run_loop.Run();
+ EXPECT_EQ(0, output_sample);
+ StopMonitorBodyReadFromNetBeforePausedHistogram();
+}
+
+TEST_F(URLLoaderTest, PauseReadingBodyFromNetWhenReadIsPending) {
+ const char* const kPath = "/hello.html";
+ const char* const kBodyContentsFirstHalf = "This is the first half.";
+ const char* const kBodyContentsSecondHalf = "This is the second half.";
+
+ base::HistogramBase::Sample output_sample = -1;
+ base::RunLoop histogram_run_loop;
+ EXPECT_TRUE(StartMonitorBodyReadFromNetBeforePausedHistogram(
+ histogram_run_loop.QuitClosure(), &output_sample));
+
+ net::EmbeddedTestServer server;
+ net::test_server::ControllableHttpResponse response_controller(&server,
+ kPath);
+ ASSERT_TRUE(server.Start());
+
+ ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
+
+ mojom::URLLoaderPtr loader;
+ // The loader is implicitly owned by the client and the NetworkContext.
+ new URLLoader(context(), nullptr, mojo::MakeRequest(&loader), 0, request,
+ false, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, 0, resource_scheduler_client(),
+ nullptr);
+
+ response_controller.WaitForRequest();
+ response_controller.Send(
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n" +
+ std::string(kBodyContentsFirstHalf));
+
+ client()->RunUntilResponseBodyArrived();
+ EXPECT_TRUE(client()->has_received_response());
+ EXPECT_FALSE(client()->has_received_completion());
+
+ loader->PauseReadingBodyFromNet();
+ loader.FlushForTesting();
+
+ response_controller.Send(kBodyContentsSecondHalf);
+ response_controller.Done();
+
+ // It is uncertain how much data has been read before reading is actually
+ // paused, because if there is a pending read when PauseReadingBodyFromNet()
+ // arrives, the pending read won't be cancelled. Therefore, this test only
+ // checks that after ResumeReadingBodyFromNet() we should be able to get the
+ // whole response body.
+ loader->ResumeReadingBodyFromNet();
+ client()->RunUntilComplete();
+
+ EXPECT_EQ(std::string(kBodyContentsFirstHalf) +
+ std::string(kBodyContentsSecondHalf),
+ ReadBody());
+
+ loader.reset();
+ client()->Unbind();
+ histogram_run_loop.Run();
+ EXPECT_LE(0, output_sample);
+ StopMonitorBodyReadFromNetBeforePausedHistogram();
+}
+
+TEST_F(URLLoaderTest, ResumeReadingBodyFromNetAfterClosingConsumer) {
+ const char* const kPath = "/hello.html";
+ const char* const kBodyContentsFirstHalf = "This is the first half.";
+
+ base::HistogramBase::Sample output_sample = -1;
+ base::RunLoop histogram_run_loop;
+ EXPECT_TRUE(StartMonitorBodyReadFromNetBeforePausedHistogram(
+ histogram_run_loop.QuitClosure(), &output_sample));
+
+ net::EmbeddedTestServer server;
+ net::test_server::ControllableHttpResponse response_controller(&server,
+ kPath);
+ ASSERT_TRUE(server.Start());
+
+ ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
+
+ mojom::URLLoaderPtr loader;
+ // The loader is implicitly owned by the client and the NetworkContext.
+ new URLLoader(context(), nullptr, mojo::MakeRequest(&loader), 0, request,
+ false, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, 0, resource_scheduler_client(),
+ nullptr);
+
+ loader->PauseReadingBodyFromNet();
+ loader.FlushForTesting();
+
+ response_controller.WaitForRequest();
+ response_controller.Send(
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n" +
+ std::string(kBodyContentsFirstHalf));
+
+ client()->RunUntilResponseBodyArrived();
+ EXPECT_TRUE(client()->has_received_response());
+ EXPECT_FALSE(client()->has_received_completion());
+
+ auto response_body = client()->response_body_release();
+ response_body.reset();
+
+ // It shouldn't cause any issue even if a ResumeReadingBodyFromNet() call is
+ // made after the response body data pipe is closed.
+ loader->ResumeReadingBodyFromNet();
+ loader.FlushForTesting();
+
+ loader.reset();
+ client()->Unbind();
+ histogram_run_loop.Run();
+ EXPECT_EQ(0, output_sample);
+ StopMonitorBodyReadFromNetBeforePausedHistogram();
+}
+
+TEST_F(URLLoaderTest, MultiplePauseResumeReadingBodyFromNet) {
+ const char* const kPath = "/hello.html";
+ const char* const kBodyContentsFirstHalf = "This is the first half.";
+ const char* const kBodyContentsSecondHalf = "This is the second half.";
+
+ base::HistogramBase::Sample output_sample = -1;
+ base::RunLoop histogram_run_loop;
+ EXPECT_TRUE(StartMonitorBodyReadFromNetBeforePausedHistogram(
+ histogram_run_loop.QuitClosure(), &output_sample));
+
+ net::EmbeddedTestServer server;
+ net::test_server::ControllableHttpResponse response_controller(&server,
+ kPath);
+ ASSERT_TRUE(server.Start());
+
+ ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
+
+ mojom::URLLoaderPtr loader;
+ // The loader is implicitly owned by the client and the NetworkContext.
+ new URLLoader(context(), nullptr, mojo::MakeRequest(&loader), 0, request,
+ false, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, 0, resource_scheduler_client(),
+ nullptr);
+
+ // It is okay to call ResumeReadingBodyFromNet() even if there is no prior
+ // PauseReadingBodyFromNet().
+ loader->ResumeReadingBodyFromNet();
+ loader.FlushForTesting();
+
+ response_controller.WaitForRequest();
+ response_controller.Send(
+ "HTTP/1.1 200 OK\r\n"
+ "Content-Type: text/plain\r\n\r\n" +
+ std::string(kBodyContentsFirstHalf));
+
+ loader->PauseReadingBodyFromNet();
+
+ client()->RunUntilResponseBodyArrived();
+ EXPECT_TRUE(client()->has_received_response());
+ EXPECT_FALSE(client()->has_received_completion());
+
+ loader->PauseReadingBodyFromNet();
+ loader->PauseReadingBodyFromNet();
+ loader.FlushForTesting();
+
+ response_controller.Send(kBodyContentsSecondHalf);
+ response_controller.Done();
+
+ // One ResumeReadingBodyFromNet() call will resume reading even if there are
+ // multiple PauseReadingBodyFromNet() calls before it.
+ loader->ResumeReadingBodyFromNet();
+
+ client()->RunUntilComplete();
+
+ EXPECT_EQ(std::string(kBodyContentsFirstHalf) +
+ std::string(kBodyContentsSecondHalf),
+ ReadBody());
+
+ loader.reset();
+ client()->Unbind();
+ histogram_run_loop.Run();
+ EXPECT_LE(0, output_sample);
+ StopMonitorBodyReadFromNetBeforePausedHistogram();
+}
+
+TEST_F(URLLoaderTest, UploadBytes) {
+ const std::string kRequestBody = "Request Body";
+
+ scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+ request_body->AppendBytes(kRequestBody.c_str(), kRequestBody.length());
+ set_request_body(std::move(request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+ EXPECT_EQ(kRequestBody, response_body);
+}
+
+TEST_F(URLLoaderTest, UploadFile) {
+ base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+ std::string expected_body;
+ ASSERT_TRUE(base::ReadFileToString(file_path, &expected_body))
+ << "File not found: " << file_path.value();
+
+ scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+ request_body->AppendFileRange(
+ file_path, 0, std::numeric_limits<uint64_t>::max(), base::Time());
+ set_request_body(std::move(request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+ EXPECT_EQ(expected_body, response_body);
+}
+
+TEST_F(URLLoaderTest, UploadFileWithRange) {
+ base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+ std::string expected_body;
+ ASSERT_TRUE(base::ReadFileToString(file_path, &expected_body))
+ << "File not found: " << file_path.value();
+ expected_body = expected_body.substr(1, expected_body.size() - 2);
+
+ scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+ request_body->AppendFileRange(file_path, 1, expected_body.size(),
+ base::Time());
+ set_request_body(std::move(request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+ EXPECT_EQ(expected_body, response_body);
+}
+
+TEST_F(URLLoaderTest, UploadRawFile) {
+ base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+ std::string expected_body;
+ ASSERT_TRUE(base::ReadFileToString(file_path, &expected_body))
+ << "File not found: " << file_path.value();
+
+ scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+ request_body->AppendRawFileRange(
+ OpenFileForUpload(file_path), GetTestFilePath("should_be_ignored"), 0,
+ std::numeric_limits<uint64_t>::max(), base::Time());
+ set_request_body(std::move(request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+ EXPECT_EQ(expected_body, response_body);
+}
+
+TEST_F(URLLoaderTest, UploadRawFileWithRange) {
+ base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+ std::string expected_body;
+ ASSERT_TRUE(base::ReadFileToString(file_path, &expected_body))
+ << "File not found: " << file_path.value();
+ expected_body = expected_body.substr(1, expected_body.size() - 2);
+
+ scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+ request_body->AppendRawFileRange(OpenFileForUpload(file_path),
+ GetTestFilePath("should_be_ignored"), 1,
+ expected_body.size(), base::Time());
+ set_request_body(std::move(request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+ EXPECT_EQ(expected_body, response_body);
+}
+
+// Tests a request body with a data pipe element.
+TEST_F(URLLoaderTest, UploadDataPipe) {
+ const std::string kRequestBody = "Request Body";
+
+ mojom::DataPipeGetterPtr data_pipe_getter_ptr;
+ auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
+ kRequestBody, mojo::MakeRequest(&data_pipe_getter_ptr));
+
+ auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
+ resource_request_body->AppendDataPipe(std::move(data_pipe_getter_ptr));
+ set_request_body(std::move(resource_request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+ EXPECT_EQ(kRequestBody, response_body);
+}
+
+// Same as above and tests that the body is sent after a 307 redirect.
+TEST_F(URLLoaderTest, UploadDataPipe_Redirect307) {
+ const std::string kRequestBody = "Request Body";
+
+ mojom::DataPipeGetterPtr data_pipe_getter_ptr;
+ auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
+ kRequestBody, mojo::MakeRequest(&data_pipe_getter_ptr));
+
+ auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
+ resource_request_body->AppendDataPipe(std::move(data_pipe_getter_ptr));
+ set_request_body(std::move(resource_request_body));
+ set_expect_redirect();
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/redirect307-to-echo"),
+ &response_body));
+ EXPECT_EQ(kRequestBody, response_body);
+}
+
+// Tests a large request body, which should result in multiple asynchronous
+// reads.
+TEST_F(URLLoaderTest, UploadDataPipeWithLotsOfData) {
+ std::string request_body;
+ request_body.reserve(5 * 1024 * 1024);
+ // Using a repeating patter with a length that's prime is more likely to spot
+ // out of order or repeated chunks of data.
+ while (request_body.size() < 5 * 1024 * 1024)
+ request_body.append("foppity");
+
+ mojom::DataPipeGetterPtr data_pipe_getter_ptr;
+ auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
+ request_body, mojo::MakeRequest(&data_pipe_getter_ptr));
+
+ auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
+ resource_request_body->AppendDataPipe(std::move(data_pipe_getter_ptr));
+ set_request_body(std::move(resource_request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+ EXPECT_EQ(request_body, response_body);
+}
+
+TEST_F(URLLoaderTest, UploadDataPipeError) {
+ const std::string kRequestBody = "Request Body";
+
+ mojom::DataPipeGetterPtr data_pipe_getter_ptr;
+ auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
+ kRequestBody, mojo::MakeRequest(&data_pipe_getter_ptr));
+ data_pipe_getter->set_start_error(net::ERR_ACCESS_DENIED);
+
+ auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
+ resource_request_body->AppendDataPipe(std::move(data_pipe_getter_ptr));
+ set_request_body(std::move(resource_request_body));
+
+ EXPECT_EQ(net::ERR_ACCESS_DENIED, Load(test_server()->GetURL("/echo")));
+}
+
+TEST_F(URLLoaderTest, UploadDataPipeClosedEarly) {
+ const std::string kRequestBody = "Request Body";
+
+ mojom::DataPipeGetterPtr data_pipe_getter_ptr;
+ auto data_pipe_getter = std::make_unique<TestDataPipeGetter>(
+ kRequestBody, mojo::MakeRequest(&data_pipe_getter_ptr));
+ data_pipe_getter->set_pipe_closed_early(true);
+
+ auto resource_request_body = base::MakeRefCounted<ResourceRequestBody>();
+ resource_request_body->AppendDataPipe(std::move(data_pipe_getter_ptr));
+ set_request_body(std::move(resource_request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::ERR_FAILED, Load(test_server()->GetURL("/echo")));
+}
+
+TEST_F(URLLoaderTest, UploadDoubleRawFile) {
+ base::FilePath file_path = GetTestFilePath("simple_page.html");
+
+ std::string expected_body;
+ ASSERT_TRUE(base::ReadFileToString(file_path, &expected_body))
+ << "File not found: " << file_path.value();
+
+ scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
+ request_body->AppendRawFileRange(
+ OpenFileForUpload(file_path), GetTestFilePath("should_be_ignored"), 0,
+ std::numeric_limits<uint64_t>::max(), base::Time());
+ request_body->AppendRawFileRange(
+ OpenFileForUpload(file_path), GetTestFilePath("should_be_ignored"), 0,
+ std::numeric_limits<uint64_t>::max(), base::Time());
+ set_request_body(std::move(request_body));
+
+ std::string response_body;
+ EXPECT_EQ(net::OK, Load(test_server()->GetURL("/echo"), &response_body));
+ EXPECT_EQ(expected_body + expected_body, response_body);
+}
+
+// Tests that SSLInfo is not attached to OnComplete messages when there is no
+// certificate error.
+TEST_F(URLLoaderTest, NoSSLInfoWithoutCertificateError) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ ASSERT_TRUE(https_server.Start());
+ set_send_ssl_for_cert_error();
+ EXPECT_EQ(net::OK, Load(https_server.GetURL("/")));
+ EXPECT_FALSE(client()->completion_status().ssl_info.has_value());
+}
+
+// Tests that SSLInfo is not attached to OnComplete messages when the
+// corresponding option is not set.
+TEST_F(URLLoaderTest, NoSSLInfoOnComplete) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
+ ASSERT_TRUE(https_server.Start());
+ EXPECT_EQ(net::ERR_INSECURE_RESPONSE, Load(https_server.GetURL("/")));
+ EXPECT_FALSE(client()->completion_status().ssl_info.has_value());
+}
+
+// Tests that SSLInfo is attached to OnComplete messages when the corresponding
+// option is set.
+TEST_F(URLLoaderTest, SSLInfoOnComplete) {
+ net::EmbeddedTestServer https_server(net::EmbeddedTestServer::TYPE_HTTPS);
+ https_server.SetSSLConfig(net::EmbeddedTestServer::CERT_EXPIRED);
+ ASSERT_TRUE(https_server.Start());
+ set_send_ssl_for_cert_error();
+ EXPECT_EQ(net::ERR_INSECURE_RESPONSE, Load(https_server.GetURL("/")));
+ ASSERT_TRUE(client()->completion_status().ssl_info.has_value());
+ EXPECT_TRUE(client()->completion_status().ssl_info.value().cert);
+ EXPECT_EQ(net::CERT_STATUS_DATE_INVALID,
+ client()->completion_status().ssl_info.value().cert_status);
+}
+
+// A mock URLRequestJob which simulates an HTTPS request with a certificate
+// error.
+class MockHTTPSURLRequestJob : public net::URLRequestTestJob {
+ public:
+ MockHTTPSURLRequestJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const std::string& response_headers,
+ const std::string& response_data,
+ bool auto_advance)
+ : net::URLRequestTestJob(request,
+ network_delegate,
+ response_headers,
+ response_data,
+ auto_advance) {}
+
+ // net::URLRequestTestJob:
+ void GetResponseInfo(net::HttpResponseInfo* info) override {
+ // Get the original response info, but override the SSL info.
+ net::URLRequestJob::GetResponseInfo(info);
+ info->ssl_info.cert =
+ net::ImportCertFromFile(net::GetTestCertsDirectory(), "ok_cert.pem");
+ info->ssl_info.cert_status = net::CERT_STATUS_DATE_INVALID;
+ }
+
+ private:
+ ~MockHTTPSURLRequestJob() override {}
+
+ DISALLOW_COPY_AND_ASSIGN(MockHTTPSURLRequestJob);
+};
+
+class MockHTTPSJobURLRequestInterceptor : public net::URLRequestInterceptor {
+ public:
+ MockHTTPSJobURLRequestInterceptor() {}
+ ~MockHTTPSJobURLRequestInterceptor() override {}
+
+ // net::URLRequestInterceptor:
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return new MockHTTPSURLRequestJob(request, network_delegate, std::string(),
+ "dummy response", true);
+ }
+};
+
+// Tests that |cert_status| is set on the resource response.
+TEST_F(URLLoaderTest, CertStatusOnResponse) {
+ net::URLRequestFilter::GetInstance()->ClearHandlers();
+ net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
+ "https", "example.test",
+ std::unique_ptr<net::URLRequestInterceptor>(
+ new MockHTTPSJobURLRequestInterceptor()));
+
+ EXPECT_EQ(net::OK, Load(GURL("https://example.test/")));
+ EXPECT_EQ(net::CERT_STATUS_DATE_INVALID,
+ client()->response_head().cert_status);
+}
+
+// Verifies if URLLoader works well with ResourceScheduler.
+TEST_F(URLLoaderTest, ResourceSchedulerIntegration) {
+ // ResourceScheduler limits the number of connections for the same host
+ // by 6.
+ constexpr int kRepeat = 6;
+ constexpr char kPath[] = "/hello.html";
+
+ resource_scheduler()->DeprecatedOnWillInsertBody(kProcessId, kRouteId);
+
+ net::EmbeddedTestServer server;
+ // This is needed to stall all requests to the server.
+ net::test_server::ControllableHttpResponse response_controllers[kRepeat] = {
+ {&server, kPath}, {&server, kPath}, {&server, kPath},
+ {&server, kPath}, {&server, kPath}, {&server, kPath},
+ };
+
+ ASSERT_TRUE(server.Start());
+
+ ResourceRequest request = CreateResourceRequest("GET", server.GetURL(kPath));
+ request.load_flags = net::LOAD_DISABLE_CACHE;
+ request.priority = net::IDLE;
+
+ // Fill up the ResourceScheduler with delayable requests.
+ std::vector<std::pair<base::WeakPtr<URLLoader>, mojom::URLLoaderPtr>> loaders;
+ for (int i = 0; i < kRepeat; ++i) {
+ TestURLLoaderClient client;
+ mojom::URLLoaderPtr loaderInterfacePtr;
+
+ // The loader is implicitly owned by the client and the NetworkContext.
+ auto* loader = new URLLoader(
+ context(), nullptr, mojo::MakeRequest(&loaderInterfacePtr), 0, request,
+ false, client.CreateInterfacePtr(), TRAFFIC_ANNOTATION_FOR_TESTS,
+ kProcessId, resource_scheduler_client(), nullptr);
+
+ loaders.push_back(std::make_pair(loader->GetWeakPtrForTests(),
+ std::move(loaderInterfacePtr)));
+ }
+
+ base::RunLoop().RunUntilIdle();
+ for (const auto& pair : loaders) {
+ URLLoader* loader = pair.first.get();
+ ASSERT_NE(loader, nullptr);
+ EXPECT_EQ(net::LOAD_STATE_WAITING_FOR_RESPONSE,
+ loader->GetLoadStateForTesting());
+ }
+
+ mojom::URLLoaderPtr loaderInterfacePtr;
+ base::WeakPtr<URLLoader> loader =
+ (new URLLoader(context(), nullptr, mojo::MakeRequest(&loaderInterfacePtr),
+ 0, request, false, client()->CreateInterfacePtr(),
+ TRAFFIC_ANNOTATION_FOR_TESTS, kProcessId,
+ resource_scheduler_client(), nullptr))
+ ->GetWeakPtrForTests();
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_NE(loader, nullptr);
+ // Make sure that the ResourceScheduler throttles this request.
+ EXPECT_EQ(net::LOAD_STATE_WAITING_FOR_DELEGATE,
+ loader->GetLoadStateForTesting());
+
+ loader->SetPriority(net::HIGHEST, 0 /* intra_priority_value */);
+ base::RunLoop().RunUntilIdle();
+
+ ASSERT_NE(loader, nullptr);
+ // Make sure that the ResourceScheduler stops throtting.
+ EXPECT_EQ(net::LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET,
+ loader->GetLoadStateForTesting());
+}
+
+} // namespace network
diff --git a/chromium/services/network/url_request_context_builder_mojo.cc b/chromium/services/network/url_request_context_builder_mojo.cc
new file mode 100644
index 00000000000..9e83d08a7eb
--- /dev/null
+++ b/chromium/services/network/url_request_context_builder_mojo.cc
@@ -0,0 +1,72 @@
+// 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 "services/network/url_request_context_builder_mojo.h"
+
+#include "base/logging.h"
+#include "build/build_config.h"
+#include "net/proxy_resolution/pac_file_fetcher_impl.h"
+#include "net/proxy_resolution/proxy_config_service.h"
+#include "services/network/network_context.h"
+
+#if !defined(OS_IOS)
+#include "services/network/proxy_service_mojo.h"
+#endif
+
+namespace network {
+
+URLRequestContextBuilderMojo::URLRequestContextBuilderMojo()
+ : dhcp_fetcher_factory_(new net::DhcpProxyScriptFetcherFactory()) {}
+
+URLRequestContextBuilderMojo::~URLRequestContextBuilderMojo() = default;
+
+void URLRequestContextBuilderMojo::SetDhcpFetcherFactory(
+ std::unique_ptr<net::DhcpProxyScriptFetcherFactory> dhcp_fetcher_factory) {
+ dhcp_fetcher_factory_ = std::move(dhcp_fetcher_factory);
+}
+
+void URLRequestContextBuilderMojo::SetMojoProxyResolverFactory(
+ proxy_resolver::mojom::ProxyResolverFactoryPtr
+ mojo_proxy_resolver_factory) {
+ mojo_proxy_resolver_factory_ = std::move(mojo_proxy_resolver_factory);
+}
+
+URLRequestContextOwner URLRequestContextBuilderMojo::Create(
+ mojom::NetworkContextParams* params,
+ bool quic_disabled,
+ net::NetLog* net_log) {
+ return NetworkContext::ApplyContextParamsToBuilder(this, params,
+ quic_disabled, net_log);
+}
+
+std::unique_ptr<net::ProxyResolutionService>
+URLRequestContextBuilderMojo::CreateProxyService(
+ std::unique_ptr<net::ProxyConfigService> proxy_config_service,
+ net::URLRequestContext* url_request_context,
+ net::HostResolver* host_resolver,
+ net::NetworkDelegate* network_delegate,
+ net::NetLog* net_log) {
+ DCHECK(url_request_context);
+ DCHECK(host_resolver);
+
+#if !defined(OS_IOS)
+ if (mojo_proxy_resolver_factory_) {
+ std::unique_ptr<net::DhcpProxyScriptFetcher> dhcp_proxy_script_fetcher =
+ dhcp_fetcher_factory_->Create(url_request_context);
+ std::unique_ptr<net::ProxyScriptFetcher> proxy_script_fetcher =
+ std::make_unique<net::ProxyScriptFetcherImpl>(url_request_context);
+ return CreateProxyServiceUsingMojoFactory(
+ std::move(mojo_proxy_resolver_factory_),
+ std::move(proxy_config_service), std::move(proxy_script_fetcher),
+ std::move(dhcp_proxy_script_fetcher), host_resolver, net_log,
+ network_delegate);
+ }
+#endif
+
+ return net::URLRequestContextBuilder::CreateProxyService(
+ std::move(proxy_config_service), url_request_context, host_resolver,
+ network_delegate, net_log);
+}
+
+} // namespace network
diff --git a/chromium/services/network/url_request_context_builder_mojo.h b/chromium/services/network/url_request_context_builder_mojo.h
new file mode 100644
index 00000000000..de7a09e65eb
--- /dev/null
+++ b/chromium/services/network/url_request_context_builder_mojo.h
@@ -0,0 +1,79 @@
+// 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 SERVICES_NETWORK_URL_REQUEST_CONTEXT_BUILDER_MOJO_H_
+#define SERVICES_NETWORK_URL_REQUEST_CONTEXT_BUILDER_MOJO_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/macros.h"
+#include "build/build_config.h"
+#include "net/proxy_resolution/dhcp_pac_file_fetcher_factory.h"
+#include "net/url_request/url_request_context_builder.h"
+#include "services/network/public/mojom/network_service.mojom.h"
+#include "services/network/url_request_context_owner.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+
+namespace net {
+class HostResolver;
+class NetLog;
+class NetworkDelegate;
+class ProxyResolutionService;
+class URLRequestContext;
+} // namespace net
+
+namespace network {
+
+// Specialization of URLRequestContextBuilder that can create a
+// ProxyResolutionService that uses a Mojo ProxyResolver. The consumer is
+// responsible for providing the proxy_resolver::mojom::ProxyResolverFactory.
+// If a ProxyResolutionService is set directly via the URLRequestContextBuilder
+// API, it will be used instead.
+class COMPONENT_EXPORT(NETWORK_SERVICE) URLRequestContextBuilderMojo
+ : public net::URLRequestContextBuilder {
+ public:
+ URLRequestContextBuilderMojo();
+ ~URLRequestContextBuilderMojo() override;
+
+ // Overrides default DhcpProxyScriptFetcherFactory. Ignored if no
+ // proxy_resolver::mojom::ProxyResolverFactory is provided.
+ void SetDhcpFetcherFactory(
+ std::unique_ptr<net::DhcpProxyScriptFetcherFactory> dhcp_fetcher_factory);
+
+ // Sets Mojo factory used to create ProxyResolvers. If not set, falls back to
+ // URLRequestContext's default behavior.
+ void SetMojoProxyResolverFactory(
+ proxy_resolver::mojom::ProxyResolverFactoryPtr
+ mojo_proxy_resolver_factory);
+
+ // Can be used to create a URLRequestContext from this consumer-configured
+ // URLRequestContextBuilder, which |params| will then be applied to. The
+ // results URLRequestContext will be returned along with other state that it
+ // depends on. The URLRequestContext can be further modified before first use.
+ //
+ // This method is intended to ease the transition to an out-of-process
+ // NetworkService, and will be removed once that ships.
+ URLRequestContextOwner Create(mojom::NetworkContextParams* params,
+ bool quic_disabled,
+ net::NetLog* net_log);
+
+ private:
+ std::unique_ptr<net::ProxyResolutionService> CreateProxyService(
+ std::unique_ptr<net::ProxyConfigService> proxy_config_service,
+ net::URLRequestContext* url_request_context,
+ net::HostResolver* host_resolver,
+ net::NetworkDelegate* network_delegate,
+ net::NetLog* net_log) override;
+
+ std::unique_ptr<net::DhcpProxyScriptFetcherFactory> dhcp_fetcher_factory_;
+
+ proxy_resolver::mojom::ProxyResolverFactoryPtr mojo_proxy_resolver_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLRequestContextBuilderMojo);
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_URL_REQUEST_CONTEXT_BUILDER_MOJO_H_
diff --git a/chromium/services/network/url_request_context_owner.cc b/chromium/services/network/url_request_context_owner.cc
new file mode 100644
index 00000000000..e4cf7cd2d83
--- /dev/null
+++ b/chromium/services/network/url_request_context_owner.cc
@@ -0,0 +1,62 @@
+// 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 "services/network/url_request_context_owner.h"
+
+#include "base/message_loop/message_loop.h"
+#include "components/prefs/pref_service.h"
+#include "net/url_request/url_request_context.h"
+
+namespace network {
+
+NetworkURLRequestContextGetter::NetworkURLRequestContextGetter(
+ std::unique_ptr<net::URLRequestContext> url_request_context)
+ : url_request_context_(std::move(url_request_context)),
+ network_task_runner_(base::MessageLoop::current()->task_runner()) {}
+
+// net::URLRequestContextGetter implementation:
+net::URLRequestContext* NetworkURLRequestContextGetter::GetURLRequestContext() {
+ return shutdown_ ? nullptr : url_request_context_.get();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+NetworkURLRequestContextGetter::GetNetworkTaskRunner() const {
+ return network_task_runner_;
+}
+
+void NetworkURLRequestContextGetter::NotifyContextShuttingDown() {
+ shutdown_ = true;
+ URLRequestContextGetter::NotifyContextShuttingDown();
+ url_request_context_.reset();
+}
+
+NetworkURLRequestContextGetter::~NetworkURLRequestContextGetter() {}
+
+URLRequestContextOwner::URLRequestContextOwner() = default;
+
+URLRequestContextOwner::URLRequestContextOwner(
+ std::unique_ptr<PrefService> pref_service_in,
+ std::unique_ptr<net::URLRequestContext> url_request_context_in) {
+ pref_service = std::move(pref_service_in);
+ url_request_context_getter =
+ new NetworkURLRequestContextGetter(std::move(url_request_context_in));
+}
+
+URLRequestContextOwner::~URLRequestContextOwner() {
+ if (url_request_context_getter)
+ url_request_context_getter.get()->NotifyContextShuttingDown();
+}
+
+URLRequestContextOwner::URLRequestContextOwner(URLRequestContextOwner&& other)
+ : pref_service(std::move(other.pref_service)),
+ url_request_context_getter(std::move(other.url_request_context_getter)) {}
+
+URLRequestContextOwner& URLRequestContextOwner::operator=(
+ URLRequestContextOwner&& other) {
+ pref_service = std::move(other.pref_service);
+ url_request_context_getter = std::move(other.url_request_context_getter);
+ return *this;
+}
+
+} // namespace network
diff --git a/chromium/services/network/url_request_context_owner.h b/chromium/services/network/url_request_context_owner.h
new file mode 100644
index 00000000000..fd53fa89344
--- /dev/null
+++ b/chromium/services/network/url_request_context_owner.h
@@ -0,0 +1,58 @@
+// 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 SERVICES_NETWORK_URL_REQUEST_CONTEXT_OWNER_H_
+#define SERVICES_NETWORK_URL_REQUEST_CONTEXT_OWNER_H_
+
+#include <memory>
+
+#include "base/component_export.h"
+#include "base/memory/scoped_refptr.h"
+#include "net/url_request/url_request_context_getter.h"
+
+class PrefService;
+
+namespace network {
+
+class COMPONENT_EXPORT(NETWORK_SERVICE) NetworkURLRequestContextGetter
+ : public net::URLRequestContextGetter {
+ public:
+ explicit NetworkURLRequestContextGetter(
+ std::unique_ptr<net::URLRequestContext> url_request_context);
+
+ // net::URLRequestContextGetter implementation:
+ net::URLRequestContext* GetURLRequestContext() override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
+ const override;
+
+ void NotifyContextShuttingDown();
+
+ protected:
+ ~NetworkURLRequestContextGetter() override;
+
+ private:
+ bool shutdown_ = false;
+ std::unique_ptr<net::URLRequestContext> url_request_context_;
+ scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
+};
+
+// This owns a net::URLRequestContext and other state that's used with it.
+struct COMPONENT_EXPORT(NETWORK_SERVICE) URLRequestContextOwner {
+ URLRequestContextOwner();
+ URLRequestContextOwner(
+ std::unique_ptr<PrefService> pref_service,
+ std::unique_ptr<net::URLRequestContext> url_request_context);
+ ~URLRequestContextOwner();
+ URLRequestContextOwner(URLRequestContextOwner&& other);
+ URLRequestContextOwner& operator=(URLRequestContextOwner&& other);
+
+ // This needs to be destroyed after the URLRequestContext.
+ std::unique_ptr<PrefService> pref_service;
+
+ scoped_refptr<NetworkURLRequestContextGetter> url_request_context_getter;
+};
+
+} // namespace network
+
+#endif // SERVICES_NETWORK_URL_REQUEST_CONTEXT_OWNER_H_
diff --git a/chromium/services/preferences/BUILD.gn b/chromium/services/preferences/BUILD.gn
index c9a04a6fafe..0681fefc066 100644
--- a/chromium/services/preferences/BUILD.gn
+++ b/chromium/services/preferences/BUILD.gn
@@ -26,7 +26,7 @@ source_set("preferences") {
"//mojo/common:values_struct_traits",
"//services/preferences/public/cpp",
"//services/preferences/public/cpp/lib",
- "//services/preferences/public/interfaces",
+ "//services/preferences/public/mojom",
"//services/preferences/tracked",
"//services/service_manager/public/cpp",
]
@@ -55,7 +55,7 @@ source_set("tests") {
"//services/preferences/public/cpp",
"//services/preferences/public/cpp:service_main",
"//services/preferences/public/cpp/tests",
- "//services/preferences/public/interfaces",
+ "//services/preferences/public/mojom",
"//services/preferences/tracked:unit_tests",
"//services/service_manager/public/cpp",
"//testing/gmock",
diff --git a/chromium/services/preferences/persistent_pref_store_impl.h b/chromium/services/preferences/persistent_pref_store_impl.h
index 78b933fdd31..1509407e8db 100644
--- a/chromium/services/preferences/persistent_pref_store_impl.h
+++ b/chromium/services/preferences/persistent_pref_store_impl.h
@@ -13,8 +13,8 @@
#include "base/callback.h"
#include "base/macros.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
-#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
namespace prefs {
diff --git a/chromium/services/preferences/persistent_pref_store_impl_unittest.cc b/chromium/services/preferences/persistent_pref_store_impl_unittest.cc
index 549df9d7fe4..cc91d4eb6f3 100644
--- a/chromium/services/preferences/persistent_pref_store_impl_unittest.cc
+++ b/chromium/services/preferences/persistent_pref_store_impl_unittest.cc
@@ -14,7 +14,7 @@
#include "components/prefs/in_memory_pref_store.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/preferences/public/cpp/persistent_pref_store_client.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/preferences/unittest_common.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/preferences/pref_service_factory_unittest.cc b/chromium/services/preferences/pref_service_factory_unittest.cc
index 88a078eb005..02a104318c7 100644
--- a/chromium/services/preferences/pref_service_factory_unittest.cc
+++ b/chromium/services/preferences/pref_service_factory_unittest.cc
@@ -9,7 +9,6 @@
#include "base/memory/ptr_util.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
-#include "base/test/sequenced_worker_pool_owner.h"
#include "components/prefs/in_memory_pref_store.h"
#include "components/prefs/overlay_user_pref_store.h"
#include "components/prefs/pref_change_registrar.h"
@@ -24,12 +23,12 @@
#include "services/preferences/public/cpp/in_process_service_factory.h"
#include "services/preferences/public/cpp/pref_service_main.h"
#include "services/preferences/public/cpp/scoped_pref_update.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/preferences/unittest_common.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/service_manager/public/cpp/service_test.h"
-#include "services/service_manager/public/interfaces/service_factory.mojom.h"
+#include "services/service_manager/public/mojom/service_factory.mojom.h"
namespace prefs {
namespace {
diff --git a/chromium/services/preferences/pref_store_consistency_unittest.cc b/chromium/services/preferences/pref_store_consistency_unittest.cc
index 9dcddaf25a3..c1e9df968da 100644
--- a/chromium/services/preferences/pref_store_consistency_unittest.cc
+++ b/chromium/services/preferences/pref_store_consistency_unittest.cc
@@ -20,7 +20,7 @@
#include "services/preferences/public/cpp/dictionary_value_update.h"
#include "services/preferences/public/cpp/persistent_pref_store_client.h"
#include "services/preferences/public/cpp/scoped_pref_update.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/preferences/unittest_common.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -30,8 +30,6 @@ namespace {
constexpr char kChildKey[] = "child";
constexpr char kOtherDictionaryKey[] = "other_key";
-void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {}
-
struct UpdateOrAck {
std::vector<mojom::PrefUpdatePtr> updates;
bool is_ack;
@@ -77,8 +75,7 @@ class PrefServiceConnection : public mojom::PrefStoreObserver,
pref_registry->defaults().get(), pref_notifier.get());
pref_service_ = std::make_unique<PrefService>(
std::move(pref_notifier), std::move(pref_value_store),
- pref_store_client_.get(), pref_registry.get(),
- base::Bind(&DoNothingHandleReadError), true);
+ pref_store_client_.get(), pref_registry.get(), base::DoNothing(), true);
}
~PrefServiceConnection() override {
@@ -193,7 +190,7 @@ class PersistentPrefStoreConsistencyTest : public testing::Test {
void SetUp() override {
pref_store_ = base::MakeRefCounted<InMemoryPrefStore>();
pref_store_impl_ = std::make_unique<PersistentPrefStoreImpl>(
- pref_store_, base::BindOnce(&base::DoNothing));
+ pref_store_, base::DoNothing());
}
PersistentPrefStore* pref_store() { return pref_store_.get(); }
diff --git a/chromium/services/preferences/pref_store_impl.h b/chromium/services/preferences/pref_store_impl.h
index 8cb970247e7..40ea2a201d5 100644
--- a/chromium/services/preferences/pref_store_impl.h
+++ b/chromium/services/preferences/pref_store_impl.h
@@ -13,7 +13,7 @@
#include "components/prefs/pref_store.h"
#include "components/prefs/pref_value_store.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
namespace prefs {
diff --git a/chromium/services/preferences/pref_store_impl_unittest.cc b/chromium/services/preferences/pref_store_impl_unittest.cc
index aeabab9eefc..8a08015c005 100644
--- a/chromium/services/preferences/pref_store_impl_unittest.cc
+++ b/chromium/services/preferences/pref_store_impl_unittest.cc
@@ -14,7 +14,7 @@
#include "components/prefs/value_map_pref_store.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/preferences/public/cpp/pref_store_client.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/preferences/unittest_common.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/preferences/pref_store_manager_impl.cc b/chromium/services/preferences/pref_store_manager_impl.cc
index 557901e9edd..19a0b3639a9 100644
--- a/chromium/services/preferences/pref_store_manager_impl.cc
+++ b/chromium/services/preferences/pref_store_manager_impl.cc
@@ -9,7 +9,6 @@
#include "base/memory/ref_counted.h"
#include "base/stl_util.h"
-#include "base/threading/sequenced_worker_pool.h"
#include "components/prefs/pref_registry.h"
#include "components/prefs/pref_value_store.h"
#include "mojo/public/cpp/bindings/interface_request.h"
diff --git a/chromium/services/preferences/pref_store_manager_impl.h b/chromium/services/preferences/pref_store_manager_impl.h
index a297a9708d2..e84b1cb0295 100644
--- a/chromium/services/preferences/pref_store_manager_impl.h
+++ b/chromium/services/preferences/pref_store_manager_impl.h
@@ -16,7 +16,7 @@
#include "components/prefs/pref_value_store.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/strong_binding_set.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
diff --git a/chromium/services/preferences/public/cpp/BUILD.gn b/chromium/services/preferences/public/cpp/BUILD.gn
index f6cb549496a..1c27292c873 100644
--- a/chromium/services/preferences/public/cpp/BUILD.gn
+++ b/chromium/services/preferences/public/cpp/BUILD.gn
@@ -23,7 +23,7 @@ source_set("cpp") {
public_deps = [
"//base",
"//components/prefs",
- "//services/preferences/public/interfaces",
+ "//services/preferences/public/mojom",
"//services/service_manager/public/cpp",
]
diff --git a/chromium/services/preferences/public/cpp/OWNERS b/chromium/services/preferences/public/cpp/OWNERS
index 4df0c71cc7d..7aebc8abbf8 100644
--- a/chromium/services/preferences/public/cpp/OWNERS
+++ b/chromium/services/preferences/public/cpp/OWNERS
@@ -1,4 +1,4 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/preferences/public/cpp/persistent_pref_store_client.h b/chromium/services/preferences/public/cpp/persistent_pref_store_client.h
index 52932078c40..51561f455c9 100644
--- a/chromium/services/preferences/public/cpp/persistent_pref_store_client.h
+++ b/chromium/services/preferences/public/cpp/persistent_pref_store_client.h
@@ -18,7 +18,7 @@
#include "components/prefs/persistent_pref_store.h"
#include "components/prefs/pref_value_store.h"
#include "services/preferences/public/cpp/pref_store_client_mixin.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
namespace base {
class Value;
diff --git a/chromium/services/preferences/public/cpp/pref_registry_serializer.h b/chromium/services/preferences/public/cpp/pref_registry_serializer.h
index 9df4eb5ed62..8249f373644 100644
--- a/chromium/services/preferences/public/cpp/pref_registry_serializer.h
+++ b/chromium/services/preferences/public/cpp/pref_registry_serializer.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREF_REGISTRY_SERIALIZER_H_
#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_REGISTRY_SERIALIZER_H_
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
class PrefRegistry;
diff --git a/chromium/services/preferences/public/cpp/pref_service_factory.cc b/chromium/services/preferences/public/cpp/pref_service_factory.cc
index 38a65f58703..a065d00b743 100644
--- a/chromium/services/preferences/public/cpp/pref_service_factory.cc
+++ b/chromium/services/preferences/public/cpp/pref_service_factory.cc
@@ -17,7 +17,7 @@
#include "services/preferences/public/cpp/persistent_pref_store_client.h"
#include "services/preferences/public/cpp/pref_registry_serializer.h"
#include "services/preferences/public/cpp/pref_store_client.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace prefs {
@@ -40,8 +40,6 @@ class RefCountedInterfacePtr
mojo::InterfacePtr<Interface> ptr_;
};
-void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {}
-
scoped_refptr<PrefStore> CreatePrefStoreClient(
PrefValueStore::PrefStoreType store_type,
std::unordered_map<PrefValueStore::PrefStoreType,
@@ -119,8 +117,8 @@ void OnConnect(
pref_notifier.get());
auto pref_service = std::make_unique<PrefService>(
std::move(pref_notifier), std::move(pref_value_store),
- persistent_pref_store.get(), pref_registry.get(),
- base::Bind(&DoNothingHandleReadError), true);
+ persistent_pref_store.get(), pref_registry.get(), base::DoNothing(),
+ true);
switch (pref_service->GetAllPrefStoresInitializationStatus()) {
case PrefService::INITIALIZATION_STATUS_WAITING:
pref_service->AddPrefInitObserver(
diff --git a/chromium/services/preferences/public/cpp/pref_service_factory.h b/chromium/services/preferences/public/cpp/pref_service_factory.h
index aeed45c72bd..81aaa2c2cb0 100644
--- a/chromium/services/preferences/public/cpp/pref_service_factory.h
+++ b/chromium/services/preferences/public/cpp/pref_service_factory.h
@@ -15,7 +15,7 @@
#include "base/callback.h"
#include "components/prefs/pref_value_store.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
class PrefRegistry;
class PrefService;
diff --git a/chromium/services/preferences/public/cpp/pref_service_main.cc b/chromium/services/preferences/public/cpp/pref_service_main.cc
index 8c54aece69c..500dcec26e4 100644
--- a/chromium/services/preferences/public/cpp/pref_service_main.cc
+++ b/chromium/services/preferences/public/cpp/pref_service_main.cc
@@ -4,7 +4,6 @@
#include "services/preferences/public/cpp/pref_service_main.h"
-#include "base/threading/sequenced_worker_pool.h"
#include "services/preferences/pref_store_manager_impl.h"
#include "services/service_manager/public/cpp/service.h"
diff --git a/chromium/services/preferences/public/cpp/pref_store_client.h b/chromium/services/preferences/public/cpp/pref_store_client.h
index b7ca96e98c4..582ea244260 100644
--- a/chromium/services/preferences/public/cpp/pref_store_client.h
+++ b/chromium/services/preferences/public/cpp/pref_store_client.h
@@ -8,7 +8,7 @@
#include "base/macros.h"
#include "components/prefs/pref_store.h"
#include "services/preferences/public/cpp/pref_store_client_mixin.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
namespace prefs {
diff --git a/chromium/services/preferences/public/cpp/pref_store_client_mixin.h b/chromium/services/preferences/public/cpp/pref_store_client_mixin.h
index 29cb6041f88..18a826f71ff 100644
--- a/chromium/services/preferences/public/cpp/pref_store_client_mixin.h
+++ b/chromium/services/preferences/public/cpp/pref_store_client_mixin.h
@@ -12,7 +12,7 @@
#include "base/macros.h"
#include "base/observer_list.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
namespace base {
class DictionaryValue;
diff --git a/chromium/services/preferences/public/cpp/preferences.typemap b/chromium/services/preferences/public/cpp/preferences.typemap
index d438bedb829..a584f5450df 100644
--- a/chromium/services/preferences/public/cpp/preferences.typemap
+++ b/chromium/services/preferences/public/cpp/preferences.typemap
@@ -2,15 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/preferences/public/interfaces/preferences.mojom"
+mojom = "//services/preferences/public/mojom/preferences.mojom"
public_headers = [
"//components/prefs/persistent_pref_store.h",
"//components/prefs/pref_value_store.h",
]
traits_headers =
- [ "//services/preferences/public/cpp/preferences_struct_traits.h" ]
+ [ "//services/preferences/public/cpp/preferences_mojom_traits.h" ]
sources = [
- "//services/preferences/public/cpp/preferences_struct_traits.cc",
+ "//services/preferences/public/cpp/preferences_mojom_traits.cc",
]
deps = [
"//components/prefs",
diff --git a/chromium/services/preferences/public/cpp/preferences_struct_traits.cc b/chromium/services/preferences/public/cpp/preferences_mojom_traits.cc
index 4d22db121f9..7f8efb84543 100644
--- a/chromium/services/preferences/public/cpp/preferences_struct_traits.cc
+++ b/chromium/services/preferences/public/cpp/preferences_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/preferences/public/cpp/preferences_struct_traits.h"
+#include "services/preferences/public/cpp/preferences_mojom_traits.h"
namespace mojo {
diff --git a/chromium/services/preferences/public/cpp/preferences_struct_traits.h b/chromium/services/preferences/public/cpp/preferences_mojom_traits.h
index 194d2748b24..62af028dfe7 100644
--- a/chromium/services/preferences/public/cpp/preferences_struct_traits.h
+++ b/chromium/services/preferences/public/cpp/preferences_mojom_traits.h
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_STRUCT_TRAITS_H_
-#define SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_STRUCT_TRAITS_H_
+#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_MOJOM_TRAITS_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_MOJOM_TRAITS_H_
#include "components/prefs/persistent_pref_store.h"
#include "components/prefs/pref_value_store.h"
#include "mojo/public/cpp/bindings/enum_traits.h"
-#include "services/preferences/public/interfaces/preferences.mojom-shared.h"
+#include "services/preferences/public/mojom/preferences.mojom-shared.h"
namespace mojo {
@@ -35,4 +35,4 @@ struct EnumTraits<::prefs::mojom::PersistentPrefStoreConnection_ReadError,
} // namespace mojo
-#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_STRUCT_TRAITS_H_
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_MOJOM_TRAITS_H_
diff --git a/chromium/services/preferences/public/cpp/tests/BUILD.gn b/chromium/services/preferences/public/cpp/tests/BUILD.gn
index 6e9cbc61e02..d8286293cf8 100644
--- a/chromium/services/preferences/public/cpp/tests/BUILD.gn
+++ b/chromium/services/preferences/public/cpp/tests/BUILD.gn
@@ -14,7 +14,7 @@ source_set("tests") {
"//components/prefs:test_support",
"//mojo/public/cpp/bindings:bindings",
"//services/preferences/public/cpp",
- "//services/preferences/public/interfaces",
+ "//services/preferences/public/mojom",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/services/preferences/public/cpp/tracked/BUILD.gn b/chromium/services/preferences/public/cpp/tracked/BUILD.gn
index ddcc14d0e40..83854472e03 100644
--- a/chromium/services/preferences/public/cpp/tracked/BUILD.gn
+++ b/chromium/services/preferences/public/cpp/tracked/BUILD.gn
@@ -12,7 +12,7 @@ static_library("tracked") {
"tracked_preference_histogram_names.h",
]
public_deps = [
- "//services/preferences/public/interfaces",
+ "//services/preferences/public/mojom",
]
deps = [
"//base",
@@ -28,6 +28,6 @@ static_library("test_support") {
deps = [
"//base",
- "//services/preferences/public/interfaces",
+ "//services/preferences/public/mojom",
]
}
diff --git a/chromium/services/preferences/public/cpp/tracked/configuration.h b/chromium/services/preferences/public/cpp/tracked/configuration.h
index 2b06c56f8dd..9cfd111b28f 100644
--- a/chromium/services/preferences/public/cpp/tracked/configuration.h
+++ b/chromium/services/preferences/public/cpp/tracked/configuration.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_CONFIGURATION_H_
#define SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_CONFIGURATION_H_
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
namespace prefs {
diff --git a/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h b/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h
index 44f9fb87d1e..41f4ed66b2c 100644
--- a/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h
+++ b/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h
@@ -12,8 +12,8 @@
#include "base/compiler_specific.h"
#include "base/macros.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
-#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
class MockValidationDelegate;
diff --git a/chromium/services/preferences/public/interfaces/BUILD.gn b/chromium/services/preferences/public/mojom/BUILD.gn
index 58d8191fb9c..890e1fe265f 100644
--- a/chromium/services/preferences/public/interfaces/BUILD.gn
+++ b/chromium/services/preferences/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"preferences.mojom",
"tracked_preference_validation_delegate.mojom",
diff --git a/chromium/services/preferences/public/interfaces/OWNERS b/chromium/services/preferences/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/preferences/public/interfaces/OWNERS
+++ b/chromium/services/preferences/public/mojom/OWNERS
diff --git a/chromium/services/preferences/public/interfaces/preferences.mojom b/chromium/services/preferences/public/mojom/preferences.mojom
index ba576a9283e..194ce5fa062 100644
--- a/chromium/services/preferences/public/interfaces/preferences.mojom
+++ b/chromium/services/preferences/public/mojom/preferences.mojom
@@ -5,9 +5,9 @@
module prefs.mojom;
import "mojo/common/file_path.mojom";
-import "mojo/common/string16.mojom";
+import "mojo/public/mojom/base/string16.mojom";
import "mojo/common/values.mojom";
-import "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom";
+import "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom";
const string kServiceName = "preferences";
const string kLocalStateServiceName = "local_state";
@@ -183,7 +183,7 @@ struct TrackedPersistentPrefStoreConfiguration {
string seed;
string legacy_device_id;
string registry_seed;
- mojo.common.mojom.String16 registry_path;
+ mojo_base.mojom.String16 registry_path;
TrackedPreferenceValidationDelegate? validation_delegate;
ResetOnLoadObserver? reset_on_load_observer;
};
diff --git a/chromium/services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom b/chromium/services/preferences/public/mojom/tracked_preference_validation_delegate.mojom
index 370f95f75d9..370f95f75d9 100644
--- a/chromium/services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom
+++ b/chromium/services/preferences/public/mojom/tracked_preference_validation_delegate.mojom
diff --git a/chromium/services/preferences/scoped_pref_connection_builder.h b/chromium/services/preferences/scoped_pref_connection_builder.h
index e45e6578b52..f908ba7c485 100644
--- a/chromium/services/preferences/scoped_pref_connection_builder.h
+++ b/chromium/services/preferences/scoped_pref_connection_builder.h
@@ -12,7 +12,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
namespace prefs {
class PersistentPrefStoreImpl;
diff --git a/chromium/services/preferences/shared_pref_registry.h b/chromium/services/preferences/shared_pref_registry.h
index 397fa6d4da7..788c4cb1fcd 100644
--- a/chromium/services/preferences/shared_pref_registry.h
+++ b/chromium/services/preferences/shared_pref_registry.h
@@ -12,7 +12,7 @@
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
class PrefRegistry;
diff --git a/chromium/services/preferences/tracked/BUILD.gn b/chromium/services/preferences/tracked/BUILD.gn
index 00aca10ad58..6802e27ffdd 100644
--- a/chromium/services/preferences/tracked/BUILD.gn
+++ b/chromium/services/preferences/tracked/BUILD.gn
@@ -48,7 +48,7 @@ source_set("tracked") {
public_deps = [
"//services/preferences/public/cpp/tracked",
- "//services/preferences/public/interfaces",
+ "//services/preferences/public/mojom",
]
deps = [
diff --git a/chromium/services/preferences/tracked/pref_hash_filter.h b/chromium/services/preferences/tracked/pref_hash_filter.h
index bdc9b621c9b..c425aee850d 100644
--- a/chromium/services/preferences/tracked/pref_hash_filter.h
+++ b/chromium/services/preferences/tracked/pref_hash_filter.h
@@ -18,7 +18,7 @@
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/optional.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
#include "services/preferences/tracked/hash_store_contents.h"
#include "services/preferences/tracked/interceptable_pref_filter.h"
#include "services/preferences/tracked/tracked_preference.h"
diff --git a/chromium/services/preferences/tracked/pref_hash_store_transaction.h b/chromium/services/preferences/tracked/pref_hash_store_transaction.h
index 2e888859ee8..1d5d365d7c2 100644
--- a/chromium/services/preferences/tracked/pref_hash_store_transaction.h
+++ b/chromium/services/preferences/tracked/pref_hash_store_transaction.h
@@ -9,7 +9,7 @@
#include <vector>
#include "base/strings/string_piece.h"
-#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
namespace base {
class DictionaryValue;
diff --git a/chromium/services/preferences/tracked/segregated_pref_store.h b/chromium/services/preferences/tracked/segregated_pref_store.h
index c5d81b2dee5..1a43e50bf3e 100644
--- a/chromium/services/preferences/tracked/segregated_pref_store.h
+++ b/chromium/services/preferences/tracked/segregated_pref_store.h
@@ -16,7 +16,7 @@
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
#include "components/prefs/persistent_pref_store.h"
-#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
// Provides a unified PersistentPrefStore implementation that splits its storage
// and retrieval between two underlying PersistentPrefStore instances: a set of
diff --git a/chromium/services/preferences/tracked/tracked_atomic_preference.cc b/chromium/services/preferences/tracked/tracked_atomic_preference.cc
index 8df3a3609fa..8f2e4dea753 100644
--- a/chromium/services/preferences/tracked/tracked_atomic_preference.cc
+++ b/chromium/services/preferences/tracked/tracked_atomic_preference.cc
@@ -5,7 +5,7 @@
#include "services/preferences/tracked/tracked_atomic_preference.h"
#include "base/values.h"
-#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
#include "services/preferences/tracked/pref_hash_store_transaction.h"
using ValueState =
diff --git a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
index 8f87d62189b..80c37a219d4 100644
--- a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
+++ b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
@@ -12,7 +12,7 @@
#include "components/prefs/json_pref_store.h"
#include "components/prefs/pref_filter.h"
-#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
#include "services/preferences/tracked/pref_hash_filter.h"
#include "services/preferences/tracked/pref_hash_store_impl.h"
#include "services/preferences/tracked/segregated_pref_store.h"
diff --git a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h
index ca08959b9fd..b429f11d5a3 100644
--- a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h
+++ b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h
@@ -6,7 +6,7 @@
#define SERVICES_PREFERENCES_TRACKED_TRACKED_PERSISTENT_PREF_STORE_FACTORY_H_
#include <utility>
-#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/mojom/preferences.mojom.h"
namespace base {
class DictionaryValue;
diff --git a/chromium/services/preferences/tracked/tracked_split_preference.cc b/chromium/services/preferences/tracked/tracked_split_preference.cc
index da6ceba8fbf..a40757f922e 100644
--- a/chromium/services/preferences/tracked/tracked_split_preference.cc
+++ b/chromium/services/preferences/tracked/tracked_split_preference.cc
@@ -8,7 +8,7 @@
#include "base/logging.h"
#include "base/values.h"
-#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/public/mojom/tracked_preference_validation_delegate.mojom.h"
#include "services/preferences/tracked/pref_hash_store_transaction.h"
using ValueState =
diff --git a/chromium/services/proxy_resolver/BUILD.gn b/chromium/services/proxy_resolver/BUILD.gn
index 52486f59025..69700c13246 100644
--- a/chromium/services/proxy_resolver/BUILD.gn
+++ b/chromium/services/proxy_resolver/BUILD.gn
@@ -25,7 +25,7 @@ source_set("lib") {
]
public_deps = [
- "//services/proxy_resolver/public/interfaces",
+ "//services/proxy_resolver/public/mojom",
"//services/service_manager/public/cpp",
]
}
diff --git a/chromium/services/proxy_resolver/OWNERS b/chromium/services/proxy_resolver/OWNERS
index 8618ce25f34..310d6b2cf05 100644
--- a/chromium/services/proxy_resolver/OWNERS
+++ b/chromium/services/proxy_resolver/OWNERS
@@ -1,4 +1,4 @@
-file://content/network/OWNERS
+file://services/network/OWNERS
per-file manifest.json=set noparent
per-file manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/proxy_resolver/proxy_resolver_factory_impl.cc b/chromium/services/proxy_resolver/proxy_resolver_factory_impl.cc
index af37179e77a..f2616fc5494 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_factory_impl.cc
+++ b/chromium/services/proxy_resolver/proxy_resolver_factory_impl.cc
@@ -11,9 +11,9 @@
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/base/net_errors.h"
-#include "net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h"
-#include "net/proxy/proxy_resolver_factory.h"
-#include "net/proxy/proxy_resolver_v8_tracing.h"
+#include "net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings.h"
+#include "net/proxy_resolution/proxy_resolver_factory.h"
+#include "net/proxy_resolution/proxy_resolver_v8_tracing.h"
#include "services/proxy_resolver/proxy_resolver_impl.h"
namespace proxy_resolver {
diff --git a/chromium/services/proxy_resolver/proxy_resolver_factory_impl.h b/chromium/services/proxy_resolver/proxy_resolver_factory_impl.h
index 6e66bf22fda..84e6b1f7ef0 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_factory_impl.h
+++ b/chromium/services/proxy_resolver/proxy_resolver_factory_impl.h
@@ -12,7 +12,7 @@
#include "base/callback.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/proxy_resolver/public/interfaces/proxy_resolver.mojom.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
namespace net {
diff --git a/chromium/services/proxy_resolver/proxy_resolver_factory_impl_unittest.cc b/chromium/services/proxy_resolver/proxy_resolver_factory_impl_unittest.cc
index cb99096c299..4984df5a85e 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_factory_impl_unittest.cc
+++ b/chromium/services/proxy_resolver/proxy_resolver_factory_impl_unittest.cc
@@ -13,8 +13,8 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/base/test_completion_callback.h"
-#include "net/proxy/mock_proxy_resolver.h"
-#include "net/proxy/proxy_resolver_v8_tracing.h"
+#include "net/proxy_resolution/mock_proxy_resolver.h"
+#include "net/proxy_resolution/proxy_resolver_v8_tracing.h"
#include "net/test/event_waiter.h"
#include "net/test/gtest_util.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
diff --git a/chromium/services/proxy_resolver/proxy_resolver_impl.cc b/chromium/services/proxy_resolver/proxy_resolver_impl.cc
index bfca06810eb..94369e3f025 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_impl.cc
+++ b/chromium/services/proxy_resolver/proxy_resolver_impl.cc
@@ -9,10 +9,10 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "net/base/net_errors.h"
-#include "net/proxy/mojo_proxy_resolver_v8_tracing_bindings.h"
-#include "net/proxy/proxy_info.h"
-#include "net/proxy/proxy_resolver_script_data.h"
-#include "net/proxy/proxy_resolver_v8_tracing.h"
+#include "net/proxy_resolution/mojo_proxy_resolver_v8_tracing_bindings.h"
+#include "net/proxy_resolution/pac_file_data.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolver_v8_tracing.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
namespace proxy_resolver {
diff --git a/chromium/services/proxy_resolver/proxy_resolver_impl.h b/chromium/services/proxy_resolver/proxy_resolver_impl.h
index d8220c9f52a..50513543ffd 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_impl.h
+++ b/chromium/services/proxy_resolver/proxy_resolver_impl.h
@@ -10,8 +10,8 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
-#include "net/proxy/proxy_resolver.h"
-#include "services/proxy_resolver/public/interfaces/proxy_resolver.mojom.h"
+#include "net/proxy_resolution/proxy_resolver.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
namespace net {
class ProxyResolverV8Tracing;
diff --git a/chromium/services/proxy_resolver/proxy_resolver_impl_unittest.cc b/chromium/services/proxy_resolver/proxy_resolver_impl_unittest.cc
index 6f315d457e7..129e9a39212 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_impl_unittest.cc
+++ b/chromium/services/proxy_resolver/proxy_resolver_impl_unittest.cc
@@ -13,10 +13,10 @@
#include "base/test/scoped_task_environment.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "net/base/net_errors.h"
-#include "net/proxy/mock_proxy_resolver.h"
-#include "net/proxy/proxy_info.h"
-#include "net/proxy/proxy_resolver_v8_tracing.h"
-#include "net/proxy/proxy_server.h"
+#include "net/base/proxy_server.h"
+#include "net/proxy_resolution/mock_proxy_resolver.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_resolver_v8_tracing.h"
#include "net/test/event_waiter.h"
#include "net/test/gtest_util.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
diff --git a/chromium/services/proxy_resolver/proxy_resolver_service.cc b/chromium/services/proxy_resolver/proxy_resolver_service.cc
index d3e08425ae5..8add610cc0f 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_service.cc
+++ b/chromium/services/proxy_resolver/proxy_resolver_service.cc
@@ -22,8 +22,7 @@ ProxyResolverService::CreateService() {
void ProxyResolverService::OnStart() {
ref_factory_ = std::make_unique<service_manager::ServiceContextRefFactory>(
- base::Bind(&service_manager::ServiceContext::RequestQuit,
- base::Unretained(context())));
+ context()->CreateQuitClosure());
registry_.AddInterface(
base::Bind(&ProxyResolverService::OnProxyResolverFactoryRequest,
base::Unretained(this)));
@@ -41,4 +40,4 @@ void ProxyResolverService::OnProxyResolverFactoryRequest(
proxy_resolver_factory_.BindRequest(std::move(request), ref_factory_.get());
}
-} // namespace proxy_resolver \ No newline at end of file
+} // namespace proxy_resolver
diff --git a/chromium/services/proxy_resolver/proxy_resolver_service.h b/chromium/services/proxy_resolver/proxy_resolver_service.h
index b6013eb31a1..222d0bf96f7 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_service.h
+++ b/chromium/services/proxy_resolver/proxy_resolver_service.h
@@ -9,7 +9,7 @@
#include <string>
#include "services/proxy_resolver/proxy_resolver_factory_impl.h"
-#include "services/proxy_resolver/public/interfaces/proxy_resolver.mojom.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
diff --git a/chromium/services/proxy_resolver/proxy_resolver_service_unittest.cc b/chromium/services/proxy_resolver/proxy_resolver_service_unittest.cc
index d8e39e5de9c..a35287d39fb 100644
--- a/chromium/services/proxy_resolver/proxy_resolver_service_unittest.cc
+++ b/chromium/services/proxy_resolver/proxy_resolver_service_unittest.cc
@@ -7,7 +7,7 @@
#include <memory>
#include "base/test/scoped_task_environment.h"
-#include "services/proxy_resolver/public/interfaces/proxy_resolver.mojom.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
#include "services/service_manager/public/cpp/test/test_connector_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/proxy_resolver/public/cpp/OWNERS b/chromium/services/proxy_resolver/public/cpp/OWNERS
index 4df0c71cc7d..7aebc8abbf8 100644
--- a/chromium/services/proxy_resolver/public/cpp/OWNERS
+++ b/chromium/services/proxy_resolver/public/cpp/OWNERS
@@ -1,4 +1,4 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/proxy_resolver/public/cpp/proxy_resolver.typemap b/chromium/services/proxy_resolver/public/cpp/proxy_resolver.typemap
index c1c3be4e9bf..14fdcf83e34 100644
--- a/chromium/services/proxy_resolver/public/cpp/proxy_resolver.typemap
+++ b/chromium/services/proxy_resolver/public/cpp/proxy_resolver.typemap
@@ -2,15 +2,15 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/proxy_resolver/public/interfaces/proxy_resolver.mojom"
+mojom = "//services/proxy_resolver/public/mojom/proxy_resolver.mojom"
public_headers = [
- "//net/proxy/proxy_server.h",
- "//net/proxy/proxy_info.h",
+ "//net/base/proxy_server.h",
+ "//net/proxy_resolution/proxy_info.h",
]
traits_headers =
- [ "//services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.h" ]
+ [ "//services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h" ]
sources = [
- "//services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.cc",
+ "//services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc",
]
type_mappings = [
"proxy_resolver.mojom.ProxyInfo=net::ProxyInfo",
diff --git a/chromium/services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.cc b/chromium/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc
index 8f1a5fb2a38..26e6c6ac699 100644
--- a/chromium/services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.cc
+++ b/chromium/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.cc
@@ -2,12 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.h"
+#include "services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h"
#include "base/logging.h"
#include "net/base/host_port_pair.h"
-#include "net/proxy/proxy_info.h"
-#include "net/proxy/proxy_server.h"
+#include "net/base/proxy_server.h"
+#include "net/proxy_resolution/proxy_info.h"
namespace mojo {
diff --git a/chromium/services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.h b/chromium/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h
index f9000922e43..4c434c4b417 100644
--- a/chromium/services/proxy_resolver/public/cpp/proxy_resolver_struct_traits.h
+++ b/chromium/services/proxy_resolver/public/cpp/proxy_resolver_mojom_traits.h
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_PROXY_RESOLVER_PUBLIC_CPP_PROXY_RESOLVER_STRUCT_TRAITS_H_
-#define SERVICES_PROXY_RESOLVER_PUBLIC_CPP_PROXY_RESOLVER_STRUCT_TRAITS_H_
+#ifndef SERVICES_PROXY_RESOLVER_PUBLIC_CPP_PROXY_RESOLVER_MOJOM_TRAITS_H_
+#define SERVICES_PROXY_RESOLVER_PUBLIC_CPP_PROXY_RESOLVER_MOJOM_TRAITS_H_
#include "base/strings/string_piece.h"
#include "mojo/public/cpp/bindings/enum_traits.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
#include "net/base/host_port_pair.h"
-#include "net/proxy/proxy_info.h"
-#include "net/proxy/proxy_list.h"
-#include "net/proxy/proxy_server.h"
-#include "services/proxy_resolver/public/interfaces/proxy_resolver.mojom.h"
+#include "net/base/proxy_server.h"
+#include "net/proxy_resolution/proxy_info.h"
+#include "net/proxy_resolution/proxy_list.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
namespace net {
class ProxyInfo;
@@ -57,4 +57,4 @@ struct StructTraits<proxy_resolver::mojom::ProxyInfoDataView, net::ProxyInfo> {
} // namespace mojo
-#endif // SERVICES_PROXY_RESOLVER_PUBLIC_CPP_PROXY_RESOLVER_STRUCT_TRAITS_H_
+#endif // SERVICES_PROXY_RESOLVER_PUBLIC_CPP_PROXY_RESOLVER_MOJOM_TRAITS_H_
diff --git a/chromium/services/proxy_resolver/public/interfaces/BUILD.gn b/chromium/services/proxy_resolver/public/mojom/BUILD.gn
index 610b842b65b..430e7073725 100644
--- a/chromium/services/proxy_resolver/public/interfaces/BUILD.gn
+++ b/chromium/services/proxy_resolver/public/mojom/BUILD.gn
@@ -4,14 +4,14 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"proxy_resolver.mojom",
]
deps = [
"//mojo/common:common_custom_types",
"//net/interfaces",
- "//url/mojo:url_mojom_gurl",
+ "//url/mojom:url_mojom_gurl",
]
if (!is_ios) {
diff --git a/chromium/services/proxy_resolver/public/interfaces/OWNERS b/chromium/services/proxy_resolver/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/proxy_resolver/public/interfaces/OWNERS
+++ b/chromium/services/proxy_resolver/public/mojom/OWNERS
diff --git a/chromium/services/proxy_resolver/public/interfaces/proxy_resolver.mojom b/chromium/services/proxy_resolver/public/mojom/proxy_resolver.mojom
index c76489de55d..0615bf97471 100644
--- a/chromium/services/proxy_resolver/public/interfaces/proxy_resolver.mojom
+++ b/chromium/services/proxy_resolver/public/mojom/proxy_resolver.mojom
@@ -9,7 +9,7 @@ module proxy_resolver.mojom;
import "net/interfaces/address_family.mojom";
import "net/interfaces/host_resolver_service.mojom";
-import "url/mojo/url.mojom";
+import "url/mojom/url.mojom";
const string kProxyResolverServiceName = "proxy_resolver";
diff --git a/chromium/services/resource_coordinator/BUILD.gn b/chromium/services/resource_coordinator/BUILD.gn
index 397031b2bf8..e4b87a02201 100644
--- a/chromium/services/resource_coordinator/BUILD.gn
+++ b/chromium/services/resource_coordinator/BUILD.gn
@@ -60,9 +60,8 @@ source_set("lib") {
"//mojo/public/cpp/bindings",
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/cpp:ukm_builders",
- "//services/metrics/public/interfaces",
+ "//services/metrics/public/mojom",
"//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
- "//services/resource_coordinator/tracing:lib",
"//services/service_manager/public/cpp/standalone_service:standalone_service",
]
}
@@ -103,15 +102,9 @@ source_set("tests") {
"observers/ipc_volume_reporter_unittest.cc",
"observers/metrics_collector_unittest.cc",
"observers/page_signal_generator_impl_unittest.cc",
+ "public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits_unittest.cc",
"public/cpp/memory_instrumentation/os_metrics_unittest.cc",
- "public/cpp/memory_instrumentation/struct_traits_unittest.cc",
"public/cpp/memory_instrumentation/tracing_integration_unittest.cc",
- "public/cpp/tracing/chrome_trace_event_agent_unittest.cc",
- "tracing/agent_registry_unittest.cc",
- "tracing/coordinator_unittest.cc",
- "tracing/recorder_unittest.cc",
- "tracing/test_util.cc",
- "tracing/test_util.h",
]
if (!is_android) {
@@ -125,10 +118,9 @@ source_set("tests") {
"//components/ukm:test_support",
"//mojo/public/cpp/bindings",
"//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
- "//services/resource_coordinator/tracing:lib",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//testing/gmock",
"//testing/gtest",
]
diff --git a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.cc b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.cc
index 721bbc9b740..9bbeea38973 100644
--- a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.cc
+++ b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.cc
@@ -98,6 +98,14 @@ bool CoordinationUnitBase::GetProperty(const mojom::PropertyType property_type,
return false;
}
+int64_t CoordinationUnitBase::GetPropertyOrDefault(
+ const mojom::PropertyType property_type, int64_t default_value) const {
+ int64_t value = 0;
+ if (GetProperty(property_type, &value))
+ return value;
+ return default_value;
+}
+
void CoordinationUnitBase::OnEventReceived(mojom::Event event) {
for (auto& observer : observers())
observer.OnEventReceived(this, event);
diff --git a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.h b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.h
index 0ff7424c927..186dba1d962 100644
--- a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.h
+++ b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base.h
@@ -14,8 +14,8 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/resource_coordinator/observers/coordination_unit_graph_observer.h"
#include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit_provider.mojom.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
namespace resource_coordinator {
@@ -41,6 +41,8 @@ class CoordinationUnitBase {
void RemoveObserver(CoordinationUnitGraphObserver* observer);
bool GetProperty(const mojom::PropertyType property_type,
int64_t* result) const;
+ int64_t GetPropertyOrDefault(const mojom::PropertyType property_type,
+ int64_t default_value) const;
const CoordinationUnitID& id() const { return id_; }
const base::ObserverList<CoordinationUnitGraphObserver>& observers() const {
diff --git a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base_unittest.cc b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base_unittest.cc
index b5d923dbc4e..51d53fa1067 100644
--- a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base_unittest.cc
+++ b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_base_unittest.cc
@@ -8,7 +8,7 @@
#include "services/resource_coordinator/coordination_unit/mock_coordination_unit_graphs.h"
#include "services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h"
#include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.h b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.h
index bd1f8a0f039..289137a7148 100644
--- a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.h
+++ b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.h
@@ -6,7 +6,7 @@
#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_COORDINATION_UNIT_INTROSPECTOR_IMPL_H_
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit_introspector.mojom.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
namespace service_manager {
diff --git a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h
index b82fce2fd1e..08442ec8412 100644
--- a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h
+++ b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h
@@ -11,7 +11,7 @@
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/resource_coordinator/coordination_unit/coordination_unit_manager.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit_provider.mojom.h"
namespace service_manager {
struct BindSourceInfo;
diff --git a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.cc b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.cc
index f81c547cd04..a2b946247fe 100644
--- a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.cc
+++ b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.cc
@@ -19,7 +19,9 @@ void OnLastServiceRefDestroyed() {
} // namespace
CoordinationUnitTestHarness::CoordinationUnitTestHarness()
- : service_ref_factory_(base::Bind(&OnLastServiceRefDestroyed)),
+ : task_env_(base::test::ScopedTaskEnvironment::MainThreadType::MOCK_TIME,
+ base::test::ScopedTaskEnvironment::ExecutionMode::QUEUED),
+ service_ref_factory_(base::Bind(&OnLastServiceRefDestroyed)),
provider_(&service_ref_factory_, &coordination_unit_manager_) {}
CoordinationUnitTestHarness::~CoordinationUnitTestHarness() = default;
diff --git a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h
index 49c1f51047c..e03c9b6bc10 100644
--- a/chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h
+++ b/chromium/services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h
@@ -8,7 +8,7 @@
#include <stdint.h>
#include <string>
-#include "base/message_loop/message_loop.h"
+#include "base/test/scoped_task_environment.h"
#include "services/resource_coordinator/coordination_unit/coordination_unit_base.h"
#include "services/resource_coordinator/coordination_unit/coordination_unit_manager.h"
#include "services/resource_coordinator/coordination_unit/coordination_unit_provider_impl.h"
@@ -68,6 +68,9 @@ class CoordinationUnitTestHarness : public testing::Test {
void TearDown() override;
protected:
+ base::test::ScopedTaskEnvironment& task_env() {
+ return task_env_;
+ }
service_manager::ServiceContextRefFactory* service_context_ref_factory() {
return &service_ref_factory_;
}
@@ -77,7 +80,7 @@ class CoordinationUnitTestHarness : public testing::Test {
CoordinationUnitProviderImpl* provider() { return &provider_; }
private:
- base::MessageLoop message_loop_;
+ base::test::ScopedTaskEnvironment task_env_;
service_manager::ServiceContextRefFactory service_ref_factory_;
CoordinationUnitManager coordination_unit_manager_;
CoordinationUnitProviderImpl provider_;
diff --git a/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc b/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
index 39c6273bc7f..bb3036cebb5 100644
--- a/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
+++ b/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.cc
@@ -16,8 +16,7 @@ namespace resource_coordinator {
PageCoordinationUnitImpl::PageCoordinationUnitImpl(
const CoordinationUnitID& id,
std::unique_ptr<service_manager::ServiceContextRef> service_ref)
- : CoordinationUnitInterface(id, std::move(service_ref)),
- was_almost_idle_(false) {}
+ : CoordinationUnitInterface(id, std::move(service_ref)) {}
PageCoordinationUnitImpl::~PageCoordinationUnitImpl() {
for (auto* child_frame : frame_coordination_units_)
@@ -44,6 +43,10 @@ void PageCoordinationUnitImpl::RemoveFrame(const CoordinationUnitID& cu_id) {
frame_cu->RemovePageCoordinationUnit(this);
}
+void PageCoordinationUnitImpl::SetIsLoading(bool is_loading) {
+ SetProperty(mojom::PropertyType::kIsLoading, is_loading);
+}
+
void PageCoordinationUnitImpl::SetVisibility(bool visible) {
SetProperty(mojom::PropertyType::kVisible, visible);
}
@@ -64,27 +67,6 @@ void PageCoordinationUnitImpl::OnMainFrameNavigationCommitted() {
SendEvent(mojom::Event::kNavigationCommitted);
}
-bool PageCoordinationUnitImpl::CheckAndUpdateAlmostIdleStateIfNeeded() {
- auto* main_frame_cu = GetMainFrameCoordinationUnit();
- if (!main_frame_cu)
- return false;
- auto* process_cu = main_frame_cu->GetProcessCoordinationUnit();
- if (!process_cu)
- return false;
- int64_t main_thread_task_load_is_low = 0;
- int64_t is_network_almost_idle = 0;
- if (!process_cu->GetProperty(mojom::PropertyType::kMainThreadTaskLoadIsLow,
- &main_thread_task_load_is_low) ||
- !main_frame_cu->GetProperty(mojom::PropertyType::kNetworkAlmostIdle,
- &is_network_almost_idle)) {
- return false;
- }
- bool is_almost_idle = main_thread_task_load_is_low && is_network_almost_idle;
- if (!was_almost_idle_)
- was_almost_idle_ = is_almost_idle;
- return is_almost_idle;
-}
-
std::set<ProcessCoordinationUnitImpl*>
PageCoordinationUnitImpl::GetAssociatedProcessCoordinationUnits() const {
std::set<ProcessCoordinationUnitImpl*> process_cus;
@@ -97,12 +79,8 @@ PageCoordinationUnitImpl::GetAssociatedProcessCoordinationUnits() const {
return process_cus;
}
-bool PageCoordinationUnitImpl::WasAlmostIdle() const {
- return was_almost_idle_;
-}
-
bool PageCoordinationUnitImpl::IsVisible() const {
- int64_t is_visible;
+ int64_t is_visible = 0;
bool has_property = GetProperty(mojom::PropertyType::kVisible, &is_visible);
DCHECK(has_property && (is_visible == 0 || is_visible == 1));
return is_visible;
@@ -116,7 +94,7 @@ double PageCoordinationUnitImpl::GetCPUUsage() const {
process_cu->GetAssociatedPageCoordinationUnits().size();
DCHECK_LE(1u, pages_in_process);
- int64_t process_cpu_usage;
+ int64_t process_cpu_usage = 0;
if (process_cu->GetProperty(mojom::PropertyType::kCPUUsage,
&process_cpu_usage)) {
cpu_usage += static_cast<double>(process_cpu_usage) / pages_in_process;
@@ -151,10 +129,18 @@ base::TimeDelta PageCoordinationUnitImpl::TimeSinceLastVisibilityChange()
return ResourceCoordinatorClock::NowTicks() - visibility_change_time_;
}
+FrameCoordinationUnitImpl*
+PageCoordinationUnitImpl::GetMainFrameCoordinationUnit() const {
+ for (auto* frame_cu : frame_coordination_units_) {
+ if (frame_cu->IsMainFrame())
+ return frame_cu;
+ }
+ return nullptr;
+}
+
void PageCoordinationUnitImpl::OnEventReceived(mojom::Event event) {
if (event == mojom::Event::kNavigationCommitted) {
navigation_committed_time_ = ResourceCoordinatorClock::NowTicks();
- was_almost_idle_ = false;
}
for (auto& observer : observers())
observer.OnPageEventReceived(this, event);
@@ -180,13 +166,4 @@ bool PageCoordinationUnitImpl::RemoveFrame(
return frame_coordination_units_.erase(frame_cu) > 0;
}
-FrameCoordinationUnitImpl*
-PageCoordinationUnitImpl::GetMainFrameCoordinationUnit() {
- for (auto* frame_cu : frame_coordination_units_) {
- if (frame_cu->IsMainFrame())
- return frame_cu;
- }
- return nullptr;
-}
-
} // namespace resource_coordinator
diff --git a/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h b/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
index c0c02ec1dd8..420608cd99b 100644
--- a/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
+++ b/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h
@@ -29,28 +29,18 @@ class PageCoordinationUnitImpl
// mojom::PageCoordinationUnit implementation.
void AddFrame(const CoordinationUnitID& cu_id) override;
void RemoveFrame(const CoordinationUnitID& cu_id) override;
+ void SetIsLoading(bool is_loading) override;
void SetVisibility(bool visible) override;
void SetUKMSourceId(int64_t ukm_source_id) override;
void OnFaviconUpdated() override;
void OnTitleUpdated() override;
void OnMainFrameNavigationCommitted() override;
- // Returns true when the page is in almost idle state, and updates
- // |was_almost_idle_| to true if and only if the page was not in almost idle
- // state and is now in almost idle state.
- bool CheckAndUpdateAlmostIdleStateIfNeeded();
-
// There is no direct relationship between processes and pages. However,
// frames are accessible by both processes and frames, so we find all of the
// processes that are reachable from the pages's accessible frames.
std::set<ProcessCoordinationUnitImpl*> GetAssociatedProcessCoordinationUnits()
const;
- // In order to not deliver PageAlmostIdle signal multiple times, recording the
- // previous state is needed. WasAlmostIdle() returns whether the page is
- // already in almost idle state, almost idle state will be reset when the main
- // frame navigation of non-same document navigation is committed. And will
- // only be set to true when CheckAndUpdateAlmostIdleStateIfNeeded() is called.
- bool WasAlmostIdle() const;
bool IsVisible() const;
double GetCPUUsage() const;
@@ -66,11 +56,14 @@ class PageCoordinationUnitImpl
// PageCoordinationUnit.
base::TimeDelta TimeSinceLastVisibilityChange() const;
- const std::set<FrameCoordinationUnitImpl*>&
- frame_coordination_units_for_testing() const {
+ const std::set<FrameCoordinationUnitImpl*>& GetFrameCoordinationUnits()
+ const {
return frame_coordination_units_;
}
+ // Returns the main frame CU or nullptr if this page has no main frame.
+ FrameCoordinationUnitImpl* GetMainFrameCoordinationUnit() const;
+
private:
friend class FrameCoordinationUnitImpl;
@@ -82,20 +75,12 @@ class PageCoordinationUnitImpl
bool AddFrame(FrameCoordinationUnitImpl* frame_cu);
bool RemoveFrame(FrameCoordinationUnitImpl* frame_cu);
- // Returns the main frame CU or nullptr if this page has no main frame.
- FrameCoordinationUnitImpl* GetMainFrameCoordinationUnit();
-
std::set<FrameCoordinationUnitImpl*> frame_coordination_units_;
base::TimeTicks visibility_change_time_;
// Main frame navigation committed time.
base::TimeTicks navigation_committed_time_;
- // |was_almost_idle_| is only reset to false when main frame navigation of
- // non-same document navigation is committed. And will be set to true when
- // CheckAndUpdateAlmostIdleStateIfNeeded() is called.
- bool was_almost_idle_;
-
DISALLOW_COPY_AND_ASSIGN(PageCoordinationUnitImpl);
};
diff --git a/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc b/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
index 6e3350fedef..269c60a9800 100644
--- a/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
+++ b/chromium/services/resource_coordinator/coordination_unit/page_coordination_unit_impl_unittest.cc
@@ -52,7 +52,7 @@ TEST_F(PageCoordinationUnitImplTest, AddFrameBasic) {
page_cu->AddFrame(frame1_cu->id());
page_cu->AddFrame(frame2_cu->id());
page_cu->AddFrame(frame3_cu->id());
- EXPECT_EQ(3u, page_cu->frame_coordination_units_for_testing().size());
+ EXPECT_EQ(3u, page_cu->GetFrameCoordinationUnits().size());
}
TEST_F(PageCoordinationUnitImplTest, AddReduplicativeFrame) {
@@ -63,7 +63,7 @@ TEST_F(PageCoordinationUnitImplTest, AddReduplicativeFrame) {
page_cu->AddFrame(frame1_cu->id());
page_cu->AddFrame(frame2_cu->id());
page_cu->AddFrame(frame1_cu->id());
- EXPECT_EQ(2u, page_cu->frame_coordination_units_for_testing().size());
+ EXPECT_EQ(2u, page_cu->GetFrameCoordinationUnits().size());
}
TEST_F(PageCoordinationUnitImplTest, RemoveFrame) {
@@ -71,21 +71,20 @@ TEST_F(PageCoordinationUnitImplTest, RemoveFrame) {
auto frame_cu = CreateCoordinationUnit<FrameCoordinationUnitImpl>();
// Parent-child relationships have not been established yet.
- EXPECT_EQ(0u, page_cu->frame_coordination_units_for_testing().size());
+ EXPECT_EQ(0u, page_cu->GetFrameCoordinationUnits().size());
EXPECT_FALSE(frame_cu->GetPageCoordinationUnit());
page_cu->AddFrame(frame_cu->id());
// Ensure correct Parent-child relationships have been established.
- EXPECT_EQ(1u, page_cu->frame_coordination_units_for_testing().size());
- EXPECT_EQ(1u, page_cu->frame_coordination_units_for_testing().count(
- frame_cu.get()));
+ EXPECT_EQ(1u, page_cu->GetFrameCoordinationUnits().size());
+ EXPECT_EQ(1u, page_cu->GetFrameCoordinationUnits().count(frame_cu.get()));
EXPECT_EQ(page_cu.get(), frame_cu->GetPageCoordinationUnit());
page_cu->RemoveFrame(frame_cu->id());
// Parent-child relationships should no longer exist.
- EXPECT_EQ(0u, page_cu->frame_coordination_units_for_testing().size());
+ EXPECT_EQ(0u, page_cu->GetFrameCoordinationUnits().size());
EXPECT_FALSE(frame_cu->GetPageCoordinationUnit());
}
@@ -182,28 +181,28 @@ TEST_F(PageCoordinationUnitImplTest, TimeSinceLastNavigation) {
cu_graph.page->TimeSinceLastNavigation());
}
-TEST_F(PageCoordinationUnitImplTest, PageAlmostIdle) {
+TEST_F(PageCoordinationUnitImplTest, IsLoading) {
MockSinglePageInSingleProcessCoordinationUnitGraph cu_graph;
- EXPECT_FALSE(cu_graph.page->WasAlmostIdle());
- EXPECT_FALSE(cu_graph.page->CheckAndUpdateAlmostIdleStateIfNeeded());
-
- cu_graph.process->SetMainThreadTaskLoadIsLow(true);
- cu_graph.frame->SetNetworkAlmostIdle(true);
- EXPECT_FALSE(cu_graph.page->WasAlmostIdle());
- EXPECT_TRUE(cu_graph.page->CheckAndUpdateAlmostIdleStateIfNeeded());
- EXPECT_TRUE(cu_graph.page->WasAlmostIdle());
-
- cu_graph.process->SetMainThreadTaskLoadIsLow(false);
- EXPECT_TRUE(cu_graph.page->WasAlmostIdle());
- EXPECT_FALSE(cu_graph.page->CheckAndUpdateAlmostIdleStateIfNeeded());
- EXPECT_TRUE(cu_graph.page->WasAlmostIdle());
-
- cu_graph.page->OnMainFrameNavigationCommitted();
- EXPECT_FALSE(cu_graph.page->WasAlmostIdle());
- cu_graph.process->SetMainThreadTaskLoadIsLow(true);
- EXPECT_FALSE(cu_graph.page->WasAlmostIdle());
- EXPECT_TRUE(cu_graph.page->CheckAndUpdateAlmostIdleStateIfNeeded());
- EXPECT_TRUE(cu_graph.page->WasAlmostIdle());
+ auto* page_cu = cu_graph.page.get();
+
+ // First attempt should fail, as the property is unset.
+ int64_t loading = 0;
+ EXPECT_FALSE(page_cu->GetProperty(mojom::PropertyType::kIsLoading, &loading));
+
+ // Set to false and the property should read false.
+ page_cu->SetIsLoading(false);
+ EXPECT_TRUE(page_cu->GetProperty(mojom::PropertyType::kIsLoading, &loading));
+ EXPECT_EQ(0u, loading);
+
+ // Set to true and the property should read true.
+ page_cu->SetIsLoading(true);
+ EXPECT_TRUE(page_cu->GetProperty(mojom::PropertyType::kIsLoading, &loading));
+ EXPECT_EQ(1u, loading);
+
+ // Set to false and the property should read false again.
+ page_cu->SetIsLoading(false);
+ EXPECT_TRUE(page_cu->GetProperty(mojom::PropertyType::kIsLoading, &loading));
+ EXPECT_EQ(0u, loading);
}
} // namespace resource_coordinator
diff --git a/chromium/services/resource_coordinator/manifest.json b/chromium/services/resource_coordinator/manifest.json
index 0dd7654dc8e..a9d4f28954e 100644
--- a/chromium/services/resource_coordinator/manifest.json
+++ b/chromium/services/resource_coordinator/manifest.json
@@ -5,16 +5,14 @@
"service_manager:connector": {
"provides": {
"app": [
- "memory_instrumentation::mojom::Coordinator",
- "tracing::mojom::AgentRegistry"
+ "memory_instrumentation::mojom::Coordinator"
],
"coordination_unit_introspector": [
"resource_coordinator::mojom::CoordinationUnitIntrospector"
],
"coordination_unit": [ "resource_coordinator::mojom::CoordinationUnitProvider" ],
- "heap_profiling": [ "memory_instrumentation::mojom::HeapProfilerHelper" ],
+ "heap_profiler_helper": [ "memory_instrumentation::mojom::HeapProfilerHelper" ],
"page_signal": [ "resource_coordinator::mojom::PageSignalGenerator" ],
- "tracing": [ "tracing::mojom::Coordinator" ],
"tests": [ "*" ]
},
"requires": {
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
index 74ae3c66dcd..df0d75887af 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
@@ -11,6 +11,7 @@
#include "base/bind.h"
#include "base/bind_helpers.h"
+#include "base/callback_helpers.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/logging.h"
@@ -24,8 +25,8 @@
#include "services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.h"
#include "services/resource_coordinator/memory_instrumentation/switches.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/constants.mojom.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/constants.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "services/service_manager/public/cpp/identity.h"
#if defined(OS_MACOSX) && !defined(OS_IOS)
@@ -41,6 +42,21 @@ namespace {
memory_instrumentation::CoordinatorImpl* g_coordinator_impl;
+constexpr base::TimeDelta kHeapDumpTimeout = base::TimeDelta::FromSeconds(60);
+
+// A wrapper classes that allows a string to be exported as JSON in a trace
+// event.
+class StringWrapper : public base::trace_event::ConvertableToTraceFormat {
+ public:
+ explicit StringWrapper(std::string json) : json_(std::move(json)) {}
+
+ void AppendAsTraceFormat(std::string* out) const override {
+ out->append(json_);
+ }
+
+ std::string json_;
+};
+
} // namespace
@@ -97,17 +113,6 @@ void CoordinatorImpl::RequestGlobalMemoryDump(
MemoryDumpLevelOfDetail level_of_detail,
const std::vector<std::string>& allocator_dump_names,
const RequestGlobalMemoryDumpCallback& callback) {
- // Don't allow arbitary processes to obtain VM regions. Only the heap profiler
- // is allowed to obtain them using the special method on the different
- // interface.
- if (level_of_detail ==
- MemoryDumpLevelOfDetail::VM_REGIONS_ONLY_FOR_HEAP_PROFILER) {
- bindings_.ReportBadMessage(
- "Requested global memory dump using level of detail reserved for the "
- "heap profiler.");
- return;
- }
-
// This merely strips out the |dump_guid| argument.
auto adapter = [](const RequestGlobalMemoryDumpCallback& callback,
bool success, uint64_t,
@@ -149,17 +154,6 @@ void CoordinatorImpl::RequestGlobalMemoryDumpAndAppendToTrace(
MemoryDumpType dump_type,
MemoryDumpLevelOfDetail level_of_detail,
const RequestGlobalMemoryDumpAndAppendToTraceCallback& callback) {
- // Don't allow arbitary processes to obtain VM regions. Only the heap profiler
- // is allowed to obtain them using the special method on its own dedicated
- // interface (HeapProfilingHelper).
- if (level_of_detail ==
- MemoryDumpLevelOfDetail::VM_REGIONS_ONLY_FOR_HEAP_PROFILER) {
- bindings_.ReportBadMessage(
- "Requested global memory dump using level of detail reserved for the "
- "heap profiler.");
- return;
- }
-
// This merely strips out the |dump_ptr| argument.
auto adapter =
[](const RequestGlobalMemoryDumpAndAppendToTraceCallback& callback,
@@ -171,20 +165,35 @@ void CoordinatorImpl::RequestGlobalMemoryDumpAndAppendToTrace(
RequestGlobalMemoryDumpInternal(args, base::BindRepeating(adapter, callback));
}
+void CoordinatorImpl::RegisterHeapProfiler(
+ mojom::HeapProfilerPtr heap_profiler) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ heap_profiler_ = std::move(heap_profiler);
+}
+
void CoordinatorImpl::GetVmRegionsForHeapProfiler(
+ const std::vector<base::ProcessId>& pids,
const GetVmRegionsForHeapProfilerCallback& callback) {
- // This merely strips out the |dump_guid| argument.
- auto adapter = [](const RequestGlobalMemoryDumpCallback& callback,
- bool success, uint64_t dump_guid,
- mojom::GlobalMemoryDumpPtr global_memory_dump) {
- callback.Run(success, std::move(global_memory_dump));
- };
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ uint64_t dump_guid = ++next_dump_id_;
+ std::unique_ptr<QueuedVmRegionRequest> request =
+ std::make_unique<QueuedVmRegionRequest>(dump_guid, callback);
+ in_progress_vm_region_requests_[dump_guid] = std::move(request);
- QueuedRequest::Args args(
- MemoryDumpType::EXPLICITLY_TRIGGERED,
- MemoryDumpLevelOfDetail::VM_REGIONS_ONLY_FOR_HEAP_PROFILER, {},
- false /* add_to_trace */, base::kNullProcessId);
- RequestGlobalMemoryDumpInternal(args, base::BindRepeating(adapter, callback));
+ std::vector<QueuedRequestDispatcher::ClientInfo> clients;
+ for (const auto& kv : clients_) {
+ auto client_identity = kv.second->identity;
+ const base::ProcessId pid = GetProcessIdForClientIdentity(client_identity);
+ clients.emplace_back(kv.second->client.get(), pid, kv.second->process_type);
+ }
+
+ QueuedVmRegionRequest* request_ptr =
+ in_progress_vm_region_requests_[dump_guid].get();
+ auto os_callback = base::Bind(&CoordinatorImpl::OnOSMemoryDumpForVMRegions,
+ base::Unretained(this), dump_guid);
+ QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest(request_ptr, clients,
+ pids, os_callback);
+ FinalizeVmRegionDumpIfAllManagersReplied(dump_guid);
}
void CoordinatorImpl::RegisterClientProcess(
@@ -222,6 +231,29 @@ void CoordinatorImpl::UnregisterClientProcess(
}
FinalizeGlobalMemoryDumpIfAllManagersReplied();
}
+
+ for (auto& pair : in_progress_vm_region_requests_) {
+ QueuedVmRegionRequest* request = pair.second.get();
+ auto it = request->pending_responses.begin();
+ while (it != request->pending_responses.end()) {
+ auto current = it++;
+ if (*current == client_process) {
+ request->pending_responses.erase(current);
+ }
+ }
+ }
+
+ // Try to finalize all outstanding vm region requests.
+ for (auto& pair : in_progress_vm_region_requests_) {
+ // PostTask to avoid re-entrancy or modification of data-structure during
+ // iteration.
+ base::SequencedTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::BindOnce(
+ &CoordinatorImpl::FinalizeVmRegionDumpIfAllManagersReplied,
+ base::Unretained(this), pair.second->dump_guid));
+ }
+
size_t num_deleted = clients_.erase(client_process);
DCHECK(num_deleted == 1);
}
@@ -287,6 +319,24 @@ void CoordinatorImpl::OnQueuedRequestTimedOut(uint64_t dump_guid) {
FinalizeGlobalMemoryDumpIfAllManagersReplied();
}
+void CoordinatorImpl::OnHeapDumpTimeOut(uint64_t dump_guid) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ QueuedRequest* request = GetCurrentRequest();
+
+ // TODO(lalitm): add metrics for how often this happens.
+
+ // Only consider the current request timed out if we fired off this
+ // delayed callback in association with this request.
+ if (!request || request->dump_guid != dump_guid)
+ return;
+
+ // Fail all remaining dumps being waited upon and clear the vector.
+ if (request->heap_dump_in_progress) {
+ request->heap_dump_in_progress = false;
+ FinalizeGlobalMemoryDumpIfAllManagersReplied();
+ }
+}
+
void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
QueuedRequest* request = GetCurrentRequest();
@@ -316,6 +366,29 @@ void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() {
base::Unretained(this), request->dump_guid),
client_process_timeout_);
+ if (request->args.add_to_trace && heap_profiler_) {
+ request->heap_dump_in_progress = true;
+
+ // |IsArgumentFilterEnabled| is the round-about way of asking to anonymize
+ // the trace. The only way that PII gets leaked is if the full path is
+ // emitted for mapped files. Passing |strip_path_from_mapped_files|
+ // is all that is necessary to anonymize the trace.
+ bool strip_path_from_mapped_files =
+ base::trace_event::TraceLog::GetInstance()
+ ->GetCurrentTraceConfig()
+ .IsArgumentFilterEnabled();
+ heap_profiler_->DumpProcessesForTracing(
+ strip_path_from_mapped_files,
+ base::BindRepeating(&CoordinatorImpl::OnDumpProcessesForTracing,
+ base::Unretained(this), request->dump_guid));
+
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&CoordinatorImpl::OnHeapDumpTimeOut,
+ base::Unretained(this), request->dump_guid),
+ kHeapDumpTimeout);
+ }
+
// Run the callback in case there are no client processes registered.
FinalizeGlobalMemoryDumpIfAllManagersReplied();
}
@@ -384,6 +457,88 @@ void CoordinatorImpl::OnOSMemoryDumpResponse(uint64_t dump_guid,
FinalizeGlobalMemoryDumpIfAllManagersReplied();
}
+void CoordinatorImpl::OnOSMemoryDumpForVMRegions(uint64_t dump_guid,
+ mojom::ClientProcess* client,
+ bool success,
+ OSMemDumpMap os_dumps) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ auto request_it = in_progress_vm_region_requests_.find(dump_guid);
+ DCHECK(request_it != in_progress_vm_region_requests_.end());
+
+ QueuedVmRegionRequest* request = request_it->second.get();
+ auto it = request->pending_responses.find(client);
+ DCHECK(it != request->pending_responses.end());
+ request->pending_responses.erase(it);
+ request->responses[client].os_dumps = std::move(os_dumps);
+
+ FinalizeVmRegionDumpIfAllManagersReplied(request->dump_guid);
+}
+
+void CoordinatorImpl::FinalizeVmRegionDumpIfAllManagersReplied(
+ uint64_t dump_guid) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+
+ auto it = in_progress_vm_region_requests_.find(dump_guid);
+ if (it == in_progress_vm_region_requests_.end())
+ return;
+
+ if (!it->second->pending_responses.empty())
+ return;
+
+ QueuedRequestDispatcher::VmRegions results =
+ QueuedRequestDispatcher::FinalizeVmRegionRequest(it->second.get());
+ it->second->callback.Run(std::move(results));
+ in_progress_vm_region_requests_.erase(it);
+}
+
+void CoordinatorImpl::OnDumpProcessesForTracing(
+ uint64_t dump_guid,
+ std::vector<mojom::SharedBufferWithSizePtr> buffers) {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ QueuedRequest* request = GetCurrentRequest();
+ if (!request || request->dump_guid != dump_guid) {
+ return;
+ }
+
+ request->heap_dump_in_progress = false;
+
+ for (auto& buffer_ptr : buffers) {
+ mojo::ScopedSharedBufferHandle& buffer = buffer_ptr->buffer;
+ uint32_t size = buffer_ptr->size;
+
+ if (!buffer->is_valid())
+ continue;
+
+ mojo::ScopedSharedBufferMapping mapping = buffer->Map(size);
+ if (!mapping) {
+ DLOG(ERROR) << "Failed to map buffer";
+ continue;
+ }
+
+ const char* char_buffer = static_cast<const char*>(mapping.get());
+ std::string json(char_buffer, char_buffer + size);
+
+ const int kTraceEventNumArgs = 1;
+ const char* const kTraceEventArgNames[] = {"dumps"};
+ const unsigned char kTraceEventArgTypes[] = {TRACE_VALUE_TYPE_CONVERTABLE};
+ std::unique_ptr<base::trace_event::ConvertableToTraceFormat> wrapper(
+ new StringWrapper(std::move(json)));
+
+ // Using the same id merges all of the heap dumps into a single detailed
+ // dump node in the UI.
+ TRACE_EVENT_API_ADD_TRACE_EVENT_WITH_PROCESS_ID(
+ TRACE_EVENT_PHASE_MEMORY_DUMP,
+ base::trace_event::TraceLog::GetCategoryGroupEnabled(
+ base::trace_event::MemoryDumpManager::kTraceCategory),
+ "periodic_interval", trace_event_internal::kGlobalScope, dump_guid,
+ buffer_ptr->pid, kTraceEventNumArgs, kTraceEventArgNames,
+ kTraceEventArgTypes, nullptr /* arg_values */, &wrapper,
+ TRACE_EVENT_FLAG_HAS_ID);
+ }
+
+ FinalizeGlobalMemoryDumpIfAllManagersReplied();
+}
+
void CoordinatorImpl::RemovePendingResponse(
mojom::ClientProcess* client,
QueuedRequest::PendingResponse::Type type) {
@@ -406,8 +561,10 @@ void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() {
DCHECK(!queued_memory_dump_requests_.empty());
QueuedRequest* request = &queued_memory_dump_requests_.front();
- if (!request->dump_in_progress || request->pending_responses.size() > 0)
+ if (!request->dump_in_progress || request->pending_responses.size() > 0 ||
+ request->heap_dump_in_progress) {
return;
+ }
QueuedRequestDispatcher::Finalize(request, tracing_observer_.get());
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
index 9bd62ddb438..ecebb2060cd 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
+++ b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
@@ -20,7 +20,7 @@
#include "services/resource_coordinator/memory_instrumentation/queued_request.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "services/service_manager/public/cpp/identity.h"
namespace service_manager {
@@ -70,9 +70,11 @@ class CoordinatorImpl : public Coordinator,
base::trace_event::MemoryDumpType,
base::trace_event::MemoryDumpLevelOfDetail,
const RequestGlobalMemoryDumpAndAppendToTraceCallback&) override;
+ void RegisterHeapProfiler(mojom::HeapProfilerPtr heap_profiler) override;
// mojom::HeapProfilerHelper implementation.
void GetVmRegionsForHeapProfiler(
+ const std::vector<base::ProcessId>& pids,
const GetVmRegionsForHeapProfilerCallback&) override;
protected:
@@ -120,10 +122,24 @@ class CoordinatorImpl : public Coordinator,
bool success,
OSMemDumpMap);
+ // Callback of RequestOSMemoryDumpForVmRegions.
+ void OnOSMemoryDumpForVMRegions(uint64_t dump_guid,
+ mojom::ClientProcess* client,
+ bool success,
+ OSMemDumpMap);
+
+ void FinalizeVmRegionDumpIfAllManagersReplied(uint64_t dump_guid);
+
+ // Callback of DumpProcessesForTracing.
+ void OnDumpProcessesForTracing(
+ uint64_t dump_guid,
+ std::vector<mojom::SharedBufferWithSizePtr> buffers);
+
void RemovePendingResponse(mojom::ClientProcess*,
QueuedRequest::PendingResponse::Type);
void OnQueuedRequestTimedOut(uint64_t dump_guid);
+ void OnHeapDumpTimeOut(uint64_t dump_guid);
void PerformNextQueuedGlobalMemoryDump();
void FinalizeGlobalMemoryDumpIfAllManagersReplied();
@@ -139,6 +155,26 @@ class CoordinatorImpl : public Coordinator,
// Outstanding dump requests, enqueued via RequestGlobalMemoryDump().
std::list<QueuedRequest> queued_memory_dump_requests_;
+ // Outstanding vm region requests, enqueued via GetVmRegionsForHeapProfiler().
+ // This is kept in a separate list from |queued_memory_dump_requests_| for two
+ // reasons:
+ // 1) The profiling service is queried during a memory dump request, but the
+ // profiling service in turn needs to query for vm regions. Keeping this in
+ // the same list as |queued_memory_dump_requests_| would require this class
+ // to support concurrent requests.
+ //
+ // 2) Vm region requests are only ever requested by the profiling service,
+ // which uses the HeapProfilerHelper interface. Keeping the requests
+ // separate means we can avoid littering the RequestGlobalMemoryDump
+ // interface with flags intended for HeapProfilerHelper. This was already
+ // technically possible before, but required some additional plumbing. Now
+ // the separation is much cleaner.
+ //
+ // Unlike queued_memory_dump_requests_, all requests are executed in parallel.
+ // The key is a |dump_guid|.
+ std::map<uint64_t, std::unique_ptr<QueuedVmRegionRequest>>
+ in_progress_vm_region_requests_;
+
// There may be extant callbacks in |queued_memory_dump_requests_|. The
// bindings_ must be closed before destroying the un-run callbacks.
mojo::BindingSet<mojom::Coordinator, service_manager::Identity> bindings_;
@@ -150,12 +186,17 @@ class CoordinatorImpl : public Coordinator,
// Maintains a map of service_manager::Identity -> pid for registered clients.
std::unique_ptr<ProcessMap> process_map_;
+
+ // Dump IDs are unique across both heap dump and memory dump requests.
uint64_t next_dump_id_;
std::unique_ptr<TracingObserver> tracing_observer_;
// Timeout for registered client processes to respond to dump requests.
base::TimeDelta client_process_timeout_;
+ // When not null, can be queried for heap dumps.
+ mojom::HeapProfilerPtr heap_profiler_;
+
THREAD_CHECKER(thread_checker_);
DISALLOW_COPY_AND_ASSIGN(CoordinatorImpl);
};
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
index 561610cbddd..ef7eb6f55ea 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/coordinator_impl_unittest.cc
@@ -5,17 +5,15 @@
#include "services/resource_coordinator/memory_instrumentation/coordinator_impl.h"
#include "base/bind.h"
-#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/test/trace_event_analyzer.h"
#include "base/trace_event/memory_dump_request_args.h"
-#include "base/trace_event/trace_buffer.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/resource_coordinator/memory_instrumentation/process_map.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -53,45 +51,12 @@ using base::trace_event::MemoryDumpManager;
using base::trace_event::MemoryDumpRequestArgs;
using base::trace_event::MemoryDumpType;
using base::trace_event::ProcessMemoryDump;
-using base::trace_event::TraceConfig;
using base::trace_event::TraceLog;
-using base::trace_event::TraceResultBuffer;
using memory_instrumentation::mojom::GlobalMemoryDump;
using memory_instrumentation::mojom::GlobalMemoryDumpPtr;
namespace memory_instrumentation {
-namespace {
-
-std::unique_ptr<trace_analyzer::TraceAnalyzer> GetDeserializedTrace() {
- // Flush the trace into JSON.
- TraceResultBuffer buffer;
- TraceResultBuffer::SimpleOutput trace_output;
- buffer.SetOutputCallback(trace_output.GetCallback());
- base::RunLoop run_loop;
- buffer.Start();
- auto on_trace_data_collected =
- [](base::Closure quit_closure, TraceResultBuffer* buffer,
- const scoped_refptr<base::RefCountedString>& json,
- bool has_more_events) {
- buffer->AddFragment(json->data());
- if (!has_more_events)
- quit_closure.Run();
- };
-
- TraceLog::GetInstance()->Flush(Bind(on_trace_data_collected,
- run_loop.QuitClosure(),
- base::Unretained(&buffer)));
- run_loop.Run();
- buffer.Finish();
-
- // Analyze the JSON.
- return base::WrapUnique(
- trace_analyzer::TraceAnalyzer::Create(trace_output.json_output));
-}
-
-} // namespace
-
class FakeCoordinatorImpl : public CoordinatorImpl {
public:
FakeCoordinatorImpl() : CoordinatorImpl(nullptr) {}
@@ -155,8 +120,9 @@ class CoordinatorImplTest : public testing::Test {
}
void GetVmRegionsForHeapProfiler(
+ const std::vector<base::ProcessId>& pids,
GetVmRegionsForHeapProfilerCallback callback) {
- coordinator_->GetVmRegionsForHeapProfiler(callback);
+ coordinator_->GetVmRegionsForHeapProfiler(pids, callback);
}
void ReduceCoordinatorClientProcessTimeout() {
@@ -261,15 +227,19 @@ class MockGlobalMemoryDumpAndAppendToTraceCallback {
class MockGetVmRegionsForHeapProfilerCallback {
public:
MockGetVmRegionsForHeapProfilerCallback() = default;
- MOCK_METHOD2(OnCall, void(bool, GlobalMemoryDump*));
-
- void Run(bool success, GlobalMemoryDumpPtr ptr) {
- OnCall(success, ptr.get());
+ MOCK_METHOD1(
+ OnCall,
+ void(const std::unordered_map<base::ProcessId,
+ std::vector<mojom::VmRegionPtr>>&));
+
+ void Run(std::unordered_map<base::ProcessId, std::vector<mojom::VmRegionPtr>>
+ results) {
+ OnCall(results);
}
GetVmRegionsForHeapProfilerCallback Get() {
- return base::Bind(&MockGetVmRegionsForHeapProfilerCallback::Run,
- base::Unretained(this));
+ return base::BindRepeating(&MockGetVmRegionsForHeapProfilerCallback::Run,
+ base::Unretained(this));
}
};
@@ -730,40 +700,40 @@ TEST_F(CoordinatorImplTest, VmRegionsForHeapProfiler) {
#endif // defined(OS_LINUX)
MockGetVmRegionsForHeapProfilerCallback callback;
- EXPECT_CALL(callback, OnCall(true, NotNull()))
- .WillOnce(Invoke([&run_loop](bool success,
- GlobalMemoryDump* global_dump) {
- ASSERT_EQ(2U, global_dump->process_dumps.size());
- mojom::ProcessMemoryDumpPtr browser_dump = nullptr;
- mojom::ProcessMemoryDumpPtr renderer_dump = nullptr;
- for (mojom::ProcessMemoryDumpPtr& dump : global_dump->process_dumps) {
- if (dump->process_type == mojom::ProcessType::BROWSER) {
- browser_dump = std::move(dump);
- ASSERT_EQ(kBrowserPid, browser_dump->pid);
- } else if (dump->process_type == mojom::ProcessType::RENDERER) {
- renderer_dump = std::move(dump);
- ASSERT_EQ(kRendererPid, renderer_dump->pid);
- }
- }
- const std::vector<mojom::VmRegionPtr>& browser_mmaps =
- browser_dump->os_dump->memory_maps_for_heap_profiler;
- ASSERT_EQ(3u, browser_mmaps.size());
- for (int i = 0; i < 3; i++) {
- EXPECT_EQ(GetFakeAddrForVmRegion(browser_dump->pid, i),
- browser_mmaps[i]->start_address);
- }
-
- const std::vector<mojom::VmRegionPtr>& renderer_mmaps =
- renderer_dump->os_dump->memory_maps_for_heap_profiler;
- ASSERT_EQ(3u, renderer_mmaps.size());
- for (int i = 0; i < 3; i++) {
- EXPECT_EQ(GetFakeAddrForVmRegion(renderer_dump->pid, i),
- renderer_mmaps[i]->start_address);
- }
- run_loop.Quit();
- }));
+ EXPECT_CALL(callback, OnCall(_))
+ .WillOnce(Invoke(
+ [&run_loop](
+ const std::unordered_map<
+ base::ProcessId, std::vector<mojom::VmRegionPtr>>& results) {
+ ASSERT_EQ(2U, results.size());
+
+ auto browser_it = results.find(kBrowserPid);
+ ASSERT_TRUE(browser_it != results.end());
+ auto renderer_it = results.find(kRendererPid);
+ ASSERT_TRUE(renderer_it != results.end());
+
+ const std::vector<mojom::VmRegionPtr>& browser_mmaps =
+ browser_it->second;
+ ASSERT_EQ(3u, browser_mmaps.size());
+ for (int i = 0; i < 3; i++) {
+ EXPECT_EQ(GetFakeAddrForVmRegion(kBrowserPid, i),
+ browser_mmaps[i]->start_address);
+ }
+
+ const std::vector<mojom::VmRegionPtr>& renderer_mmaps =
+ renderer_it->second;
+ ASSERT_EQ(3u, renderer_mmaps.size());
+ for (int i = 0; i < 3; i++) {
+ EXPECT_EQ(GetFakeAddrForVmRegion(kRendererPid, i),
+ renderer_mmaps[i]->start_address);
+ }
+ run_loop.Quit();
+ }));
- GetVmRegionsForHeapProfiler(callback.Get());
+ std::vector<base::ProcessId> pids;
+ pids.push_back(kBrowserPid);
+ pids.push_back(kRendererPid);
+ GetVmRegionsForHeapProfiler(pids, callback.Get());
run_loop.Run();
}
@@ -794,17 +764,13 @@ TEST_F(CoordinatorImplTest, DumpsArentAddedToTraceUnlessRequested) {
IsEmpty()))))
.WillOnce(RunClosure(run_loop.QuitClosure()));
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(MemoryDumpManager::kTraceCategory, ""),
- TraceLog::RECORDING_MODE);
+ trace_analyzer::Start(MemoryDumpManager::kTraceCategory);
RequestGlobalMemoryDump(MemoryDumpType::EXPLICITLY_TRIGGERED,
MemoryDumpLevelOfDetail::DETAILED, {},
callback.Get());
run_loop.Run();
- TraceLog::GetInstance()->SetDisabled();
+ auto analyzer = trace_analyzer::Stop();
- std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer =
- GetDeserializedTrace();
trace_analyzer::TraceEventVector events;
analyzer->FindEvents(
trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
@@ -834,15 +800,11 @@ TEST_F(CoordinatorImplTest, DumpsAreAddedToTraceWhenRequested) {
EXPECT_CALL(callback, OnCall(true, Ne(0ul)))
.WillOnce(RunClosure(run_loop.QuitClosure()));
- TraceLog::GetInstance()->SetEnabled(
- TraceConfig(MemoryDumpManager::kTraceCategory, ""),
- TraceLog::RECORDING_MODE);
+ trace_analyzer::Start(MemoryDumpManager::kTraceCategory);
RequestGlobalMemoryDumpAndAppendToTrace(callback.Get());
run_loop.Run();
- TraceLog::GetInstance()->SetDisabled();
+ auto analyzer = trace_analyzer::Stop();
- std::unique_ptr<trace_analyzer::TraceAnalyzer> analyzer =
- GetDeserializedTrace();
trace_analyzer::TraceEventVector events;
analyzer->FindEvents(
trace_analyzer::Query::EventPhaseIs(TRACE_EVENT_PHASE_MEMORY_DUMP),
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/process_map.cc b/chromium/services/resource_coordinator/memory_instrumentation/process_map.cc
index 4955fdab265..0fa7f97c0d8 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/process_map.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/process_map.cc
@@ -6,11 +6,11 @@
#include "base/process/process_handle.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/interfaces/constants.mojom.h"
-#include "services/service_manager/public/interfaces/service_manager.mojom.h"
+#include "services/service_manager/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/mojom/service_manager.mojom.h"
namespace memory_instrumentation {
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/process_map.h b/chromium/services/resource_coordinator/memory_instrumentation/process_map.h
index ad726f9eeca..df82fa74d79 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/process_map.h
+++ b/chromium/services/resource_coordinator/memory_instrumentation/process_map.h
@@ -12,7 +12,7 @@
#include "base/process/process_handle.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/interfaces/service_manager.mojom.h"
+#include "services/service_manager/public/mojom/service_manager.mojom.h"
namespace service_manager {
class Connector;
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/process_map_unittest.cc b/chromium/services/resource_coordinator/memory_instrumentation/process_map_unittest.cc
index fd7958875d2..434ad101e4c 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/process_map_unittest.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/process_map_unittest.cc
@@ -7,7 +7,7 @@
#include "base/strings/stringprintf.h"
#include "services/resource_coordinator/memory_instrumentation/process_map.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/interfaces/service_manager.mojom.h"
+#include "services/service_manager/public/mojom/service_manager.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace memory_instrumentation {
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/queued_request.cc b/chromium/services/resource_coordinator/memory_instrumentation/queued_request.cc
index 1adc6626119..6c43455f5a8 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/queued_request.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/queued_request.cc
@@ -19,6 +19,16 @@ QueuedRequest::Args::Args(MemoryDumpType dump_type,
QueuedRequest::Args::Args(const Args& args) = default;
QueuedRequest::Args::~Args() = default;
+QueuedRequest::PendingResponse::PendingResponse(
+ const mojom::ClientProcess* client,
+ Type type)
+ : client(client), type(type) {}
+
+bool QueuedRequest::PendingResponse::operator<(
+ const PendingResponse& other) const {
+ return std::tie(client, type) < std::tie(other.client, other.type);
+}
+
QueuedRequest::Response::Response() {}
QueuedRequest::Response::~Response() = default;
@@ -37,14 +47,14 @@ base::trace_event::MemoryDumpRequestArgs QueuedRequest::GetRequestArgs() {
return request_args;
}
-QueuedRequest::PendingResponse::PendingResponse(
- const mojom::ClientProcess* client,
- Type type)
- : client(client), type(type) {}
+QueuedVmRegionRequest::Response::Response() = default;
+QueuedVmRegionRequest::Response::~Response() = default;
-bool QueuedRequest::PendingResponse::operator<(
- const PendingResponse& other) const {
- return std::tie(client, type) < std::tie(other.client, other.type);
-}
+QueuedVmRegionRequest::QueuedVmRegionRequest(
+ uint64_t dump_guid,
+ const mojom::HeapProfilerHelper::GetVmRegionsForHeapProfilerCallback&
+ callback)
+ : dump_guid(dump_guid), callback(callback) {}
+QueuedVmRegionRequest::~QueuedVmRegionRequest() = default;
-} // namespace memory_instrumentation \ No newline at end of file
+} // namespace memory_instrumentation
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/queued_request.h b/chromium/services/resource_coordinator/memory_instrumentation/queued_request.h
index 218f82bdb7d..155c839b05e 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/queued_request.h
+++ b/chromium/services/resource_coordinator/memory_instrumentation/queued_request.h
@@ -12,18 +12,19 @@
#include "base/trace_event/memory_dump_request_args.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
using base::trace_event::MemoryDumpLevelOfDetail;
using base::trace_event::MemoryDumpType;
namespace memory_instrumentation {
+using OSMemDumpMap =
+ std::unordered_map<base::ProcessId,
+ memory_instrumentation::mojom::RawOSMemDumpPtr>;
+
// Holds data for pending requests enqueued via RequestGlobalMemoryDump().
struct QueuedRequest {
- using OSMemDumpMap =
- std::unordered_map<base::ProcessId,
- memory_instrumentation::mojom::RawOSMemDumpPtr>;
using RequestGlobalMemoryDumpInternalCallback = base::Callback<
void(bool, uint64_t, memory_instrumentation::mojom::GlobalMemoryDumpPtr)>;
@@ -60,8 +61,8 @@ struct QueuedRequest {
Response();
~Response();
- base::ProcessId process_id;
- mojom::ProcessType process_type;
+ base::ProcessId process_id = base::kNullProcessId;
+ mojom::ProcessType process_type = mojom::ProcessType::OTHER;
std::unique_ptr<base::trace_event::ProcessMemoryDump> chrome_dump;
OSMemDumpMap os_dumps;
};
@@ -99,16 +100,42 @@ struct QueuedRequest {
// set contains a |PendingResponse| for each |RequestChromeMemoryDump| and
// |RequestOSMemoryDump| call that has not yet replied or been canceled (due
// to the client disconnecting).
- std::set<QueuedRequest::PendingResponse> pending_responses;
+ std::set<PendingResponse> pending_responses;
std::map<mojom::ClientProcess*, Response> responses;
int failed_memory_dump_count = 0;
bool dump_in_progress = false;
+ // This field is set to |true| before a heap dump is requested, and set to
+ // |false| after the heap dump has been added to the trace.
+ bool heap_dump_in_progress = false;
+
// The time we started handling the request (does not including queuing
// time).
base::Time start_time;
};
+// Holds data for pending requests enqueued via GetVmRegionsForHeapProfiler().
+struct QueuedVmRegionRequest {
+ QueuedVmRegionRequest(
+ uint64_t dump_guid,
+ const mojom::HeapProfilerHelper::GetVmRegionsForHeapProfilerCallback&
+ callback);
+ ~QueuedVmRegionRequest();
+ const uint64_t dump_guid;
+ const mojom::HeapProfilerHelper::GetVmRegionsForHeapProfilerCallback callback;
+
+ struct Response {
+ Response();
+ ~Response();
+
+ base::ProcessId process_id = base::kNullProcessId;
+ OSMemDumpMap os_dumps;
+ };
+
+ std::set<mojom::ClientProcess*> pending_responses;
+ std::map<mojom::ClientProcess*, Response> responses;
+};
+
} // namespace memory_instrumentation
-#endif // SERVICES_RESOURCE_COORDINATOR_MEMORY_INSTRUMENTATION_QUEUED_REQUEST_H_ \ No newline at end of file
+#endif // SERVICES_RESOURCE_COORDINATOR_MEMORY_INSTRUMENTATION_QUEUED_REQUEST_H_
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc b/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
index c08cd31d8f4..c5b4a623220 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
+++ b/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.cc
@@ -203,6 +203,7 @@ std::unique_ptr<TracedValue> GetChromeDumpAndGlobalAndEdgesTracedValue(
} // namespace
+// static
void QueuedRequestDispatcher::SetUpAndDispatch(
QueuedRequest* request,
const std::vector<ClientInfo>& clients,
@@ -301,6 +302,89 @@ void QueuedRequestDispatcher::SetUpAndDispatch(
}
}
+// static
+void QueuedRequestDispatcher::SetUpAndDispatchVmRegionRequest(
+ QueuedVmRegionRequest* request,
+ const std::vector<ClientInfo>& clients,
+ const std::vector<base::ProcessId>& desired_pids,
+ const OsCallback& os_callback) {
+// On Linux, OS stats can only be dumped from a privileged process to
+// get around to sandboxing/selinux restrictions (see crbug.com/461788).
+#if defined(OS_LINUX)
+ mojom::ClientProcess* browser_client = nullptr;
+ base::ProcessId browser_client_pid = 0;
+ for (const auto& client_info : clients) {
+ if (client_info.process_type == mojom::ProcessType::BROWSER) {
+ browser_client = client_info.client;
+ browser_client_pid = client_info.pid;
+ break;
+ }
+ }
+
+ if (!browser_client) {
+ DLOG(ERROR) << "Missing browser client.";
+ return;
+ }
+
+ request->pending_responses.insert(browser_client);
+ request->responses[browser_client].process_id = browser_client_pid;
+ const auto callback = base::Bind(os_callback, browser_client);
+ browser_client->RequestOSMemoryDump(true /* wants_mmaps */, desired_pids,
+ callback);
+#else
+ for (const auto& client_info : clients) {
+ if (std::find(desired_pids.begin(), desired_pids.end(), client_info.pid) !=
+ desired_pids.end()) {
+ mojom::ClientProcess* client = client_info.client;
+ request->pending_responses.insert(client);
+ request->responses[client].process_id = client_info.pid;
+ client->RequestOSMemoryDump(true /* wants_mmaps */,
+ {base::kNullProcessId},
+ base::Bind(os_callback, client));
+ }
+ }
+#endif // defined(OS_LINUX)
+}
+
+// static
+QueuedRequestDispatcher::VmRegions
+QueuedRequestDispatcher::FinalizeVmRegionRequest(
+ QueuedVmRegionRequest* request) {
+ VmRegions results;
+ for (auto& response : request->responses) {
+ const base::ProcessId& original_pid = response.second.process_id;
+
+ // |response| accumulates the replies received by each client process.
+ // On Linux, the browser process will provide all OS dumps. On non-Linux,
+ // each client process provides 1 OS dump, % the case where the client is
+ // disconnected mid dump.
+ OSMemDumpMap& extra_os_dumps = response.second.os_dumps;
+#if defined(OS_LINUX)
+ for (auto& kv : extra_os_dumps) {
+ auto pid = kv.first == base::kNullProcessId ? original_pid : kv.first;
+ DCHECK(results.find(pid) == results.end());
+ results.emplace(pid, std::move(kv.second->memory_maps));
+ }
+#else
+ // This can be empty if the client disconnects before providing both
+ // dumps. See UnregisterClientProcess().
+ DCHECK_LE(extra_os_dumps.size(), 1u);
+ for (auto& kv : extra_os_dumps) {
+ // When the OS dump comes from child processes, the pid is supposed to be
+ // not used. We know the child process pid at the time of the request and
+ // also wouldn't trust pids coming from child processes.
+ DCHECK_EQ(base::kNullProcessId, kv.first);
+
+ // Check we don't receive duplicate OS dumps for the same process.
+ DCHECK(results.find(original_pid) == results.end());
+
+ results.emplace(original_pid, std::move(kv.second->memory_maps));
+ }
+#endif
+ }
+ return results;
+}
+
void QueuedRequestDispatcher::Finalize(QueuedRequest* request,
TracingObserver* tracing_observer) {
DCHECK(request->dump_in_progress);
@@ -427,13 +511,6 @@ void QueuedRequestDispatcher::Finalize(QueuedRequest* request,
if (!valid)
continue;
- if (request->args.level_of_detail ==
- MemoryDumpLevelOfDetail::VM_REGIONS_ONLY_FOR_HEAP_PROFILER) {
- DCHECK(request->wants_mmaps());
- os_dump->memory_maps_for_heap_profiler =
- std::move(raw_os_dump->memory_maps);
- }
-
// TODO(hjd): not sure we need an empty instance for the !SUMMARY_ONLY
// requests. Check and make the else branch a nullptr otherwise.
mojom::ChromeMemDumpPtr chrome_dump =
diff --git a/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.h b/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.h
index 56c09f96270..536629d4125 100644
--- a/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.h
+++ b/chromium/services/resource_coordinator/memory_instrumentation/queued_request_dispatcher.h
@@ -30,6 +30,9 @@ class QueuedRequestDispatcher {
std::unique_ptr<base::trace_event::ProcessMemoryDump>)>;
using OsCallback =
base::Callback<void(mojom::ClientProcess*, bool, OSMemDumpMap)>;
+ using VmRegions = std::unordered_map<
+ base::ProcessId,
+ std::vector<memory_instrumentation::mojom::VmRegionPtr>>;
struct ClientInfo {
ClientInfo(mojom::ClientProcess* client,
@@ -55,6 +58,13 @@ class QueuedRequestDispatcher {
static void Finalize(QueuedRequest* request,
TracingObserver* tracing_observer);
+ static void SetUpAndDispatchVmRegionRequest(
+ QueuedVmRegionRequest* request,
+ const std::vector<ClientInfo>& clients,
+ const std::vector<base::ProcessId>& desired_pids,
+ const OsCallback& os_callback);
+ static VmRegions FinalizeVmRegionRequest(QueuedVmRegionRequest* request);
+
private:
static bool AddChromeMemoryDumpToTrace(
const base::trace_event::MemoryDumpRequestArgs& args,
@@ -67,4 +77,4 @@ class QueuedRequestDispatcher {
} // namespace memory_instrumentation
-#endif // SERVICES_RESOURCE_COORDINATOR_MEMORY_INSTRUMENTATION_QUEUED_REQUEST_DISPATCHER_H_ \ No newline at end of file
+#endif // SERVICES_RESOURCE_COORDINATOR_MEMORY_INSTRUMENTATION_QUEUED_REQUEST_DISPATCHER_H_
diff --git a/chromium/services/resource_coordinator/observers/coordination_unit_graph_observer.h b/chromium/services/resource_coordinator/observers/coordination_unit_graph_observer.h
index f33c7438dac..b3809cb00c2 100644
--- a/chromium/services/resource_coordinator/observers/coordination_unit_graph_observer.h
+++ b/chromium/services/resource_coordinator/observers/coordination_unit_graph_observer.h
@@ -6,7 +6,7 @@
#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_COORDINATION_UNIT_GRAPH_OBSERVER_H_
#include "base/macros.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
namespace resource_coordinator {
diff --git a/chromium/services/resource_coordinator/observers/coordination_unit_graph_observer_unittest.cc b/chromium/services/resource_coordinator/observers/coordination_unit_graph_observer_unittest.cc
index fa25e378e27..35ecee1fbbb 100644
--- a/chromium/services/resource_coordinator/observers/coordination_unit_graph_observer_unittest.cc
+++ b/chromium/services/resource_coordinator/observers/coordination_unit_graph_observer_unittest.cc
@@ -11,7 +11,7 @@
#include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
#include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace resource_coordinator {
diff --git a/chromium/services/resource_coordinator/observers/page_signal_generator_impl.cc b/chromium/services/resource_coordinator/observers/page_signal_generator_impl.cc
index a347b9daffd..241191324ab 100644
--- a/chromium/services/resource_coordinator/observers/page_signal_generator_impl.cc
+++ b/chromium/services/resource_coordinator/observers/page_signal_generator_impl.cc
@@ -10,6 +10,7 @@
#include "services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h"
#include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
+#include "services/resource_coordinator/resource_coordinator_clock.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
namespace resource_coordinator {
@@ -19,6 +20,10 @@ namespace resource_coordinator {
receiver->METHOD(__VA_ARGS__); \
});
+// static
+constexpr base::TimeDelta PageSignalGeneratorImpl::kLoadedAndIdlingTimeout =
+ base::TimeDelta::FromSeconds(1);
+
PageSignalGeneratorImpl::PageSignalGeneratorImpl() = default;
PageSignalGeneratorImpl::~PageSignalGeneratorImpl() = default;
@@ -32,19 +37,50 @@ bool PageSignalGeneratorImpl::ShouldObserve(
const CoordinationUnitBase* coordination_unit) {
auto cu_type = coordination_unit->id().type;
return cu_type == CoordinationUnitType::kFrame ||
+ cu_type == CoordinationUnitType::kPage ||
cu_type == CoordinationUnitType::kProcess;
}
+void PageSignalGeneratorImpl::OnCoordinationUnitCreated(
+ const CoordinationUnitBase* cu) {
+ auto cu_type = cu->id().type;
+ if (cu_type != CoordinationUnitType::kPage)
+ return;
+
+ // Create page data exists for this Page CU.
+ auto* page_cu = static_cast<const PageCoordinationUnitImpl*>(cu);
+ DCHECK(!base::ContainsKey(page_data_, page_cu)); // No data should exist yet.
+ page_data_[page_cu].load_idle_state = kLoadingNotStarted;
+}
+
+void PageSignalGeneratorImpl::OnBeforeCoordinationUnitDestroyed(
+ const CoordinationUnitBase* cu) {
+ auto cu_type = cu->id().type;
+ if (cu_type != CoordinationUnitType::kPage)
+ return;
+ auto* page_cu = static_cast<const PageCoordinationUnitImpl*>(cu);
+ size_t count = page_data_.erase(page_cu);
+ DCHECK_EQ(1u, count); // This should always erase exactly one CU.
+}
+
void PageSignalGeneratorImpl::OnFramePropertyChanged(
const FrameCoordinationUnitImpl* frame_cu,
const mojom::PropertyType property_type,
int64_t value) {
- if (property_type == mojom::PropertyType::kNetworkAlmostIdle) {
- // Ignore if network is not idle.
- if (!value)
- return;
- NotifyPageAlmostIdleIfPossible(frame_cu);
- }
+ // Only the network idle state of a frame is of interest.
+ if (property_type != mojom::PropertyType::kNetworkAlmostIdle)
+ return;
+ UpdateLoadIdleStateFrame(frame_cu);
+}
+
+void PageSignalGeneratorImpl::OnPagePropertyChanged(
+ const PageCoordinationUnitImpl* page_cu,
+ const mojom::PropertyType property_type,
+ int64_t value) {
+ // Only the loading state of a page is of interest.
+ if (property_type != mojom::PropertyType::kIsLoading)
+ return;
+ UpdateLoadIdleStatePage(page_cu);
}
void PageSignalGeneratorImpl::OnProcessPropertyChanged(
@@ -64,35 +100,169 @@ void PageSignalGeneratorImpl::OnProcessPropertyChanged(
base::TimeDelta::FromMilliseconds(duration));
}
} else if (property_type == mojom::PropertyType::kMainThreadTaskLoadIsLow) {
- for (auto* frame_cu : process_cu->GetFrameCoordinationUnits())
- NotifyPageAlmostIdleIfPossible(frame_cu);
+ UpdateLoadIdleStateProcess(process_cu);
}
}
+void PageSignalGeneratorImpl::OnPageEventReceived(
+ const PageCoordinationUnitImpl* page_cu,
+ const mojom::Event event) {
+ // Only the navigation committed event is of interest.
+ if (event != mojom::Event::kNavigationCommitted)
+ return;
+
+ // Reset the load-idle state associated with this page as a new navigation has
+ // started.
+ auto* page_data = GetPageData(page_cu);
+ page_data->load_idle_state = kLoadingNotStarted;
+ page_data->idling_timer.Stop();
+}
+
void PageSignalGeneratorImpl::BindToInterface(
resource_coordinator::mojom::PageSignalGeneratorRequest request,
const service_manager::BindSourceInfo& source_info) {
bindings_.AddBinding(this, std::move(request));
}
-void PageSignalGeneratorImpl::NotifyPageAlmostIdleIfPossible(
+void PageSignalGeneratorImpl::UpdateLoadIdleStateFrame(
const FrameCoordinationUnitImpl* frame_cu) {
- DCHECK(IsPageAlmostIdleSignalEnabled());
+ // Only main frames are relevant in the load idle state.
if (!frame_cu->IsMainFrame())
return;
+ // Update the load idle state of the page associated with this frame.
auto* page_cu = frame_cu->GetPageCoordinationUnit();
if (!page_cu)
return;
+ UpdateLoadIdleStatePage(page_cu);
+}
- // If the page is already in almost idle state, don't deliver the signal.
- // PageAlmostIdle signal shouldn't be delivered again if the frame is already
- // in almost idle state.
- if (page_cu->WasAlmostIdle())
- return;
- if (!page_cu->CheckAndUpdateAlmostIdleStateIfNeeded())
+void PageSignalGeneratorImpl::UpdateLoadIdleStatePage(
+ const PageCoordinationUnitImpl* page_cu) {
+ auto* page_data = GetPageData(page_cu);
+
+ // Once the cycle is complete state transitions are no longer tracked for this
+ // page.
+ if (page_data->load_idle_state == kLoadedAndIdle)
return;
- DISPATCH_PAGE_SIGNAL(receivers_, NotifyPageAlmostIdle, page_cu->id());
+
+ // Cancel any ongoing timers. A new timer will be set if necessary.
+ page_data->idling_timer.Stop();
+ base::TimeTicks now = ResourceCoordinatorClock::NowTicks();
+
+ switch (page_data->load_idle_state) {
+ case kLoadingNotStarted: {
+ if (!IsLoading(page_cu))
+ return;
+ page_data->load_idle_state = kLoading;
+ return;
+ }
+
+ case kLoading: {
+ if (IsLoading(page_cu))
+ return;
+ page_data->load_idle_state = kLoadedNotIdling;
+ // Let the kLoadedNotIdling state transition evaluate, allowing an
+ // effective transition directly from kLoading to kLoadedAndIdling.
+ FALLTHROUGH;
+ }
+
+ case kLoadedNotIdling: {
+ if (!IsIdling(page_cu))
+ return;
+ page_data->load_idle_state = kLoadedAndIdling;
+ page_data->idling_started = now;
+ // Break out of the switch statement and set a timer to check for the
+ // next state transition.
+ break;
+ }
+
+ case kLoadedAndIdling: {
+ // If the page is not still idling then transition back a state. The timer
+ // has already been canceled above so future calls will only be due to
+ // potential changes in idling state.
+ if (!IsIdling(page_cu)) {
+ page_data->load_idle_state = kLoadedNotIdling;
+ return;
+ }
+
+ // Idling has been occurred long enough then make the last state
+ // transition.
+ if (now - page_data->idling_started >= kLoadedAndIdlingTimeout) {
+ page_data->load_idle_state = kLoadedAndIdle;
+ // Notify observers that the page is loaded and idle.
+ DISPATCH_PAGE_SIGNAL(receivers_, NotifyPageAlmostIdle, page_cu->id());
+ return;
+ }
+
+ break;
+ }
+
+ // This should never occur.
+ case kLoadedAndIdle:
+ NOTREACHED();
+ }
+
+ // Getting here means a new timer needs to be set.
+ DCHECK_EQ(kLoadedAndIdling, page_data->load_idle_state);
+ base::TimeDelta idling_timeout =
+ (page_data->idling_started + kLoadedAndIdlingTimeout) - now;
+ page_data->idling_timer.Start(
+ FROM_HERE, idling_timeout,
+ base::Bind(&PageSignalGeneratorImpl::UpdateLoadIdleStatePage,
+ base::Unretained(this), page_cu));
+}
+
+void PageSignalGeneratorImpl::UpdateLoadIdleStateProcess(
+ const ProcessCoordinationUnitImpl* process_cu) {
+ for (auto* frame_cu : process_cu->GetFrameCoordinationUnits())
+ UpdateLoadIdleStateFrame(frame_cu);
+}
+
+PageSignalGeneratorImpl::PageData* PageSignalGeneratorImpl::GetPageData(
+ const PageCoordinationUnitImpl* page_cu) {
+ // There are two ways to enter this function:
+ // 1. Via On*PropertyChange calls. The backing PageData is guaranteed to
+ // exist in this case as the lifetimes are managed by the CU graph.
+ // 2. Via a timer stored in a PageData. The backing PageData will be
+ // guaranteed to exist in this case as well, as otherwise the timer will
+ // have been canceled.
+ DCHECK(base::ContainsKey(page_data_, page_cu));
+ return &page_data_[page_cu];
+}
+
+bool PageSignalGeneratorImpl::IsLoading(
+ const PageCoordinationUnitImpl* page_cu) {
+ int64_t is_loading = 0;
+ if (!page_cu->GetProperty(mojom::PropertyType::kIsLoading, &is_loading))
+ return false;
+ return is_loading;
+}
+
+bool PageSignalGeneratorImpl::IsIdling(
+ const PageCoordinationUnitImpl* page_cu) {
+ // Get the Frame CU for the main frame associated with this page.
+ const FrameCoordinationUnitImpl* main_frame_cu =
+ page_cu->GetMainFrameCoordinationUnit();
+ if (!main_frame_cu)
+ return false;
+
+ // Get the process CU associated with this main frame.
+ const auto* process_cu = main_frame_cu->GetProcessCoordinationUnit();
+ if (!process_cu)
+ return false;
+
+ // Note that it's possible for one misbehaving frame hosted in the same
+ // process as this page's main frame to keep the main thread task low high.
+ // In this case the IsIdling signal will be delayed, despite the task load
+ // associated with this page's main frame actually being low. In the case
+ // of session restore this is mitigated by having a timeout while waiting for
+ // this signal.
+ return
+ main_frame_cu->GetPropertyOrDefault(
+ mojom::PropertyType::kNetworkAlmostIdle, 0u) &&
+ process_cu->GetPropertyOrDefault(
+ mojom::PropertyType::kMainThreadTaskLoadIsLow, 0u);
}
} // namespace resource_coordinator
diff --git a/chromium/services/resource_coordinator/observers/page_signal_generator_impl.h b/chromium/services/resource_coordinator/observers/page_signal_generator_impl.h
index 9e79a99722c..999e3127438 100644
--- a/chromium/services/resource_coordinator/observers/page_signal_generator_impl.h
+++ b/chromium/services/resource_coordinator/observers/page_signal_generator_impl.h
@@ -5,11 +5,15 @@
#ifndef SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_PAGE_SIGNAL_GENERATOR_IMPL_H_
#define SERVICES_RESOURCE_COORDINATOR_COORDINATION_UNIT_PAGE_SIGNAL_GENERATOR_IMPL_H_
+#include <map>
+
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
+#include "base/timer/timer.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/resource_coordinator/observers/coordination_unit_graph_observer.h"
-#include "services/resource_coordinator/public/interfaces/page_signal.mojom.h"
+#include "services/resource_coordinator/public/mojom/page_signal.mojom.h"
namespace service_manager {
struct BindSourceInfo;
@@ -19,11 +23,16 @@ namespace resource_coordinator {
// The PageSignalGenerator is a dedicated |CoordinationUnitGraphObserver| for
// calculating and emitting page-scoped signals. This observer observes
-// ProcessCoordinationUnits and FrameCoordinationUnits, utilize information from
-// the graph and generate page level signals.
+// PageCoordinationUnits, ProcessCoordinationUnits and FrameCoordinationUnits,
+// combining information from the graph to generate page level signals.
class PageSignalGeneratorImpl : public CoordinationUnitGraphObserver,
public mojom::PageSignalGenerator {
public:
+ // The amount of time a page has to be idle post-loading in order for it to be
+ // considered loaded and idle. This is used in UpdateLoadIdleState
+ // transitions.
+ static const base::TimeDelta kLoadedAndIdlingTimeout;
+
PageSignalGeneratorImpl();
~PageSignalGeneratorImpl() override;
@@ -32,24 +41,89 @@ class PageSignalGeneratorImpl : public CoordinationUnitGraphObserver,
// CoordinationUnitGraphObserver implementation.
bool ShouldObserve(const CoordinationUnitBase* coordination_unit) override;
+ void OnCoordinationUnitCreated(const CoordinationUnitBase* cu) override;
+ void OnBeforeCoordinationUnitDestroyed(
+ const CoordinationUnitBase* cu) override;
void OnFramePropertyChanged(const FrameCoordinationUnitImpl* frame_cu,
const mojom::PropertyType property_type,
int64_t value) override;
+ void OnPagePropertyChanged(const PageCoordinationUnitImpl* page_cu,
+ const mojom::PropertyType property_type,
+ int64_t value) override;
void OnProcessPropertyChanged(const ProcessCoordinationUnitImpl* process_cu,
const mojom::PropertyType property_type,
int64_t value) override;
+ void OnPageEventReceived(const PageCoordinationUnitImpl* page_cu,
+ const mojom::Event event) override;
void BindToInterface(
resource_coordinator::mojom::PageSignalGeneratorRequest request,
const service_manager::BindSourceInfo& source_info);
private:
- void NotifyPageAlmostIdleIfPossible(
- const FrameCoordinationUnitImpl* frame_cu);
+ FRIEND_TEST_ALL_PREFIXES(PageSignalGeneratorImplTest, IsLoading);
+ FRIEND_TEST_ALL_PREFIXES(PageSignalGeneratorImplTest, IsIdling);
+ FRIEND_TEST_ALL_PREFIXES(PageSignalGeneratorImplTest,
+ PageDataCorrectlyManaged);
+ FRIEND_TEST_ALL_PREFIXES(PageSignalGeneratorImplTest,
+ PageAlmostIdleTransitions);
+
+ // The state transitions for the PageAlmostIdle signal. In general a page
+ // transitions through these states from top to bottom.
+ enum LoadIdleState {
+ // The initial state. Can only transition to kLoading from here.
+ kLoadingNotStarted,
+ // Loading has started. Almost idle signals are ignored in this state.
+ // Can transition to kLoadedNotIdling and kLoadedAndIdling from here.
+ kLoading,
+ // Loading has completed, but the page has not started idling. Can only
+ // transition to kLoadedAndIdling from here.
+ kLoadedNotIdling,
+ // Loading has completed, and the page is idling. Can transition to
+ // kLoadedNotIdling or kLoadedAndIdle from here.
+ kLoadedAndIdling,
+ // Loading has completed and the page has been idling for sufficiently long.
+ // This is the final state. Once this state has been reached a signal will
+ // be emitted and no further state transitions will be tracked. Committing a
+ // new non-same document navigation can start the cycle over again.
+ kLoadedAndIdle
+ };
+
+ // Holds state per page CU. These are created via OnCoordinationUnitCreated
+ // and destroyed via OnBeforeCoordinationUnitDestroyed.
+ struct PageData {
+ // Initially at kLoadingNotStarted. Transitions through the states via calls
+ // to UpdateLoadIdleState. Is reset to kLoadingNotStarted when a non-same
+ // document navigation is committed.
+ LoadIdleState load_idle_state;
+ // Marks the point in time when the transition to kLoadedAndIdling occurred.
+ // Used for gating the transition to kLoadedAndIdle.
+ base::TimeTicks idling_started;
+ // A one-shot timer used for transitioning between kLoadedAndIdling and
+ // kLoadedAndIdle.
+ base::OneShotTimer idling_timer;
+ };
+
+ // These are called when properties/events affecting the load-idle state are
+ // observed. Frame and Process variants will eventually all redirect to the
+ // appropriate Page variant, where the real work is done.
+ void UpdateLoadIdleStateFrame(const FrameCoordinationUnitImpl* frame_cu);
+ void UpdateLoadIdleStatePage(const PageCoordinationUnitImpl* page_cu);
+ void UpdateLoadIdleStateProcess(
+ const ProcessCoordinationUnitImpl* process_cu);
+
+ // Convenience accessors for state associated with a |page_cu|.
+ PageData* GetPageData(const PageCoordinationUnitImpl* page_cu);
+ bool IsLoading(const PageCoordinationUnitImpl* page_cu);
+ bool IsIdling(const PageCoordinationUnitImpl* page_cu);
mojo::BindingSet<mojom::PageSignalGenerator> bindings_;
mojo::InterfacePtrSet<mojom::PageSignalReceiver> receivers_;
+ // Stores per Page CU data. This set is maintained by
+ // OnCoordinationUnitCreated and OnBeforeCoordinationUnitDestroyed.
+ std::map<const PageCoordinationUnitImpl*, PageData> page_data_;
+
DISALLOW_COPY_AND_ASSIGN(PageSignalGeneratorImpl);
};
diff --git a/chromium/services/resource_coordinator/observers/page_signal_generator_impl_unittest.cc b/chromium/services/resource_coordinator/observers/page_signal_generator_impl_unittest.cc
index b23d9aabd2b..1a336721d5c 100644
--- a/chromium/services/resource_coordinator/observers/page_signal_generator_impl_unittest.cc
+++ b/chromium/services/resource_coordinator/observers/page_signal_generator_impl_unittest.cc
@@ -4,10 +4,14 @@
#include "services/resource_coordinator/observers/page_signal_generator_impl.h"
+#include "base/test/simple_test_tick_clock.h"
#include "services/resource_coordinator/coordination_unit/coordination_unit_test_harness.h"
+#include "services/resource_coordinator/coordination_unit/frame_coordination_unit_impl.h"
#include "services/resource_coordinator/coordination_unit/mock_coordination_unit_graphs.h"
#include "services/resource_coordinator/coordination_unit/page_coordination_unit_impl.h"
#include "services/resource_coordinator/coordination_unit/process_coordination_unit_impl.h"
+#include "services/resource_coordinator/resource_coordinator_clock.h"
+
#include "testing/gtest/include/gtest/gtest.h"
namespace resource_coordinator {
@@ -56,4 +60,162 @@ TEST_F(PageSignalGeneratorImplTest,
EXPECT_EQ(1, eqt);
}
+TEST_F(PageSignalGeneratorImplTest, IsLoading) {
+ MockSinglePageInSingleProcessCoordinationUnitGraph cu_graph;
+ auto* page_cu = cu_graph.page.get();
+ auto* psg = page_signal_generator();
+ // The observer relationship isn't required for testing IsLoading.
+
+ // The loading property hasn't yet been set. Then IsLoading should return
+ // false as the default value.
+ EXPECT_FALSE(psg->IsLoading(page_cu));
+
+ // Once the loading property has been set it should return that value.
+ page_cu->SetIsLoading(false);
+ EXPECT_FALSE(psg->IsLoading(page_cu));
+ page_cu->SetIsLoading(true);
+ EXPECT_TRUE(psg->IsLoading(page_cu));
+ page_cu->SetIsLoading(false);
+ EXPECT_FALSE(psg->IsLoading(page_cu));
+}
+
+TEST_F(PageSignalGeneratorImplTest, IsIdling) {
+ MockSinglePageInSingleProcessCoordinationUnitGraph cu_graph;
+ auto* frame_cu = cu_graph.frame.get();
+ auto* page_cu = cu_graph.page.get();
+ auto* proc_cu = cu_graph.process.get();
+ auto* psg = page_signal_generator();
+ // The observer relationship isn't required for testing IsIdling.
+
+ // Neither of the idling properties are set, so IsIdling should return false.
+ EXPECT_FALSE(psg->IsIdling(page_cu));
+
+ // Should still return false after main thread task is low.
+ proc_cu->SetMainThreadTaskLoadIsLow(true);
+ EXPECT_FALSE(psg->IsIdling(page_cu));
+
+ // Should return true when network is idle.
+ frame_cu->SetNetworkAlmostIdle(true);
+ EXPECT_TRUE(psg->IsIdling(page_cu));
+
+ // Should toggle with main thread task low.
+ proc_cu->SetMainThreadTaskLoadIsLow(false);
+ EXPECT_FALSE(psg->IsIdling(page_cu));
+ proc_cu->SetMainThreadTaskLoadIsLow(true);
+ EXPECT_TRUE(psg->IsIdling(page_cu));
+
+ // Should return false when network is no longer idle.
+ frame_cu->SetNetworkAlmostIdle(false);
+ EXPECT_FALSE(psg->IsIdling(page_cu));
+
+ // And should stay false if main thread task also goes low again.
+ proc_cu->SetMainThreadTaskLoadIsLow(false);
+ EXPECT_FALSE(psg->IsIdling(page_cu));
+}
+
+TEST_F(PageSignalGeneratorImplTest, PageDataCorrectlyManaged) {
+ MockSinglePageInSingleProcessCoordinationUnitGraph cu_graph;
+ auto* page_cu = cu_graph.page.get();
+ auto* psg = page_signal_generator();
+ // The observer relationship isn't required for testing GetPageData.
+
+ EXPECT_EQ(0u, psg->page_data_.count(page_cu));
+ psg->OnCoordinationUnitCreated(page_cu);
+ EXPECT_EQ(1u, psg->page_data_.count(page_cu));
+ EXPECT_TRUE(psg->GetPageData(page_cu));
+ psg->OnBeforeCoordinationUnitDestroyed(page_cu);
+ EXPECT_EQ(0u, psg->page_data_.count(page_cu));
+}
+
+TEST_F(PageSignalGeneratorImplTest, PageAlmostIdleTransitions) {
+ ResourceCoordinatorClock::SetClockForTesting(
+ std::make_unique<base::SimpleTestTickClock>());
+ auto* test_clock = static_cast<base::SimpleTestTickClock*>(
+ ResourceCoordinatorClock::GetClockForTesting());
+ test_clock->Advance(base::TimeDelta::FromSeconds(1));
+
+ MockSinglePageInSingleProcessCoordinationUnitGraph cu_graph;
+ auto* frame_cu = cu_graph.frame.get();
+ auto* page_cu = cu_graph.page.get();
+ auto* proc_cu = cu_graph.process.get();
+ auto* psg = page_signal_generator();
+
+ // Set up observers, as the PAI logic depends on them.
+ frame_cu->AddObserver(psg);
+ page_cu->AddObserver(psg);
+ proc_cu->AddObserver(psg);
+
+ // Ensure the page_cu creation is witnessed and get the associated
+ // page data for testing, then bind the timer to the test task runner.
+ psg->OnCoordinationUnitCreated(page_cu);
+ PageSignalGeneratorImpl::PageData* page_data = psg->GetPageData(page_cu);
+ page_data->idling_timer.SetTaskRunner(task_env().GetMainThreadTaskRunner());
+
+ // Aliasing these here makes this unittest much more legible.
+ using LIS = PageSignalGeneratorImpl::LoadIdleState;
+
+ // Initially the page should be in a loading not started state.
+ EXPECT_EQ(LIS::kLoadingNotStarted, page_data->load_idle_state);
+ EXPECT_FALSE(page_data->idling_timer.IsRunning());
+
+ // The state should not transition when a not loading state is explicitly
+ // set.
+ page_cu->SetIsLoading(false);
+ EXPECT_EQ(LIS::kLoadingNotStarted, page_data->load_idle_state);
+ EXPECT_FALSE(page_data->idling_timer.IsRunning());
+
+ // The state should transition to loading when loading starts.
+ page_cu->SetIsLoading(true);
+ EXPECT_EQ(LIS::kLoading, page_data->load_idle_state);
+ EXPECT_FALSE(page_data->idling_timer.IsRunning());
+
+ // Mark the page as idling. It should transition from kLoading directly
+ // to kLoadedAndIdling after this.
+ frame_cu->SetNetworkAlmostIdle(true);
+ proc_cu->SetMainThreadTaskLoadIsLow(true);
+ page_cu->SetIsLoading(false);
+ EXPECT_EQ(LIS::kLoadedAndIdling, page_data->load_idle_state);
+ EXPECT_TRUE(page_data->idling_timer.IsRunning());
+
+ // Indicate loading is happening again. This should be ignored.
+ page_cu->SetIsLoading(true);
+ EXPECT_EQ(LIS::kLoadedAndIdling, page_data->load_idle_state);
+ EXPECT_TRUE(page_data->idling_timer.IsRunning());
+ page_cu->SetIsLoading(false);
+ EXPECT_EQ(LIS::kLoadedAndIdling, page_data->load_idle_state);
+ EXPECT_TRUE(page_data->idling_timer.IsRunning());
+
+ // Go back to not idling. We should transition back to kLoadedNotIdling.
+ frame_cu->SetNetworkAlmostIdle(false);
+ EXPECT_EQ(LIS::kLoadedNotIdling, page_data->load_idle_state);
+ EXPECT_FALSE(page_data->idling_timer.IsRunning());
+
+ // Go back to idling.
+ frame_cu->SetNetworkAlmostIdle(true);
+ EXPECT_EQ(LIS::kLoadedAndIdling, page_data->load_idle_state);
+ EXPECT_TRUE(page_data->idling_timer.IsRunning());
+
+ // Let the timer evaluate. The final state transition should occur.
+ // TODO(chrisha): Expose the tick clock from the ScopedTaskEnvironment, and
+ // use that clock in the ResourceCoordinatorClock. Beats having two separate
+ // fake clocks that need to be manually kept in sync.
+ test_clock->Advance(PageSignalGeneratorImpl::kLoadedAndIdlingTimeout);
+ task_env().FastForwardUntilNoTasksRemain();
+ EXPECT_EQ(LIS::kLoadedAndIdle, page_data->load_idle_state);
+ EXPECT_FALSE(page_data->idling_timer.IsRunning());
+
+ // Firing other signals should not change the state at all.
+ proc_cu->SetMainThreadTaskLoadIsLow(false);
+ EXPECT_EQ(LIS::kLoadedAndIdle, page_data->load_idle_state);
+ EXPECT_FALSE(page_data->idling_timer.IsRunning());
+ frame_cu->SetNetworkAlmostIdle(false);
+ EXPECT_EQ(LIS::kLoadedAndIdle, page_data->load_idle_state);
+ EXPECT_FALSE(page_data->idling_timer.IsRunning());
+
+ // Post a navigation. The state should reset.
+ page_cu->OnMainFrameNavigationCommitted();
+ EXPECT_EQ(LIS::kLoadingNotStarted, page_data->load_idle_state);
+ EXPECT_FALSE(page_data->idling_timer.IsRunning());
+}
+
} // namespace resource_coordinator
diff --git a/chromium/services/resource_coordinator/public/cpp/BUILD.gn b/chromium/services/resource_coordinator/public/cpp/BUILD.gn
index a0f04d518c4..7621257c9c5 100644
--- a/chromium/services/resource_coordinator/public/cpp/BUILD.gn
+++ b/chromium/services/resource_coordinator/public/cpp/BUILD.gn
@@ -42,8 +42,6 @@ component("resource_coordinator_cpp") {
"resource_coordinator_features.cc",
"resource_coordinator_features.h",
"resource_coordinator_interface.h",
- "tracing/chrome_trace_event_agent.cc",
- "tracing/chrome_trace_event_agent.h",
]
if (is_android) {
@@ -67,7 +65,7 @@ component("resource_coordinator_cpp") {
":resource_coordinator_cpp_base",
"//base",
"//mojo/public/cpp/bindings",
- "//services/resource_coordinator/public/interfaces",
+ "//services/resource_coordinator/public/mojom",
"//services/service_manager/public/cpp",
]
}
diff --git a/chromium/services/resource_coordinator/public/cpp/OWNERS b/chromium/services/resource_coordinator/public/cpp/OWNERS
index 8d2da1aa86f..a605b82578c 100644
--- a/chromium/services/resource_coordinator/public/cpp/OWNERS
+++ b/chromium/services/resource_coordinator/public/cpp/OWNERS
@@ -3,5 +3,5 @@ per-file BUILD.gn=file://services/resource_coordinator/memory_instrumentation/OW
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/resource_coordinator/public/cpp/coordination_unit.typemap b/chromium/services/resource_coordinator/public/cpp/coordination_unit.typemap
index 3eaaecad4b7..4ba96ad1b7a 100644
--- a/chromium/services/resource_coordinator/public/cpp/coordination_unit.typemap
+++ b/chromium/services/resource_coordinator/public/cpp/coordination_unit.typemap
@@ -2,17 +2,18 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom =
- "//services/resource_coordinator/public/interfaces/coordination_unit.mojom"
+mojom = "//services/resource_coordinator/public/mojom/coordination_unit.mojom"
public_headers = [
"//services/resource_coordinator/public/cpp/coordination_unit_id.h",
"//services/resource_coordinator/public/cpp/coordination_unit_types.h",
]
-traits_headers = [ "//services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h" ]
+traits_headers = [
+ "//services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.h",
+]
sources = [
- "//services/resource_coordinator/public/cpp/coordination_unit_struct_traits.cc",
- "//services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h",
+ "//services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.cc",
+ "//services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.h",
]
public_deps = [
"//services/resource_coordinator/public/cpp:resource_coordinator_cpp_base",
diff --git a/chromium/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.cc b/chromium/services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.cc
index 87216451232..59ef31aa1a7 100644
--- a/chromium/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.cc
+++ b/chromium/services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h"
+#include "services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.h"
namespace mojo {
diff --git a/chromium/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h b/chromium/services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.h
index cd74154c170..971ebb72ea6 100644
--- a/chromium/services/resource_coordinator/public/cpp/coordination_unit_struct_traits.h
+++ b/chromium/services/resource_coordinator/public/cpp/coordination_unit_mojom_traits.h
@@ -2,17 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_STRUCT_TRAITS_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_STRUCT_TRAITS_H_
+#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_MOJOM_TRAITS_H_
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_MOJOM_TRAITS_H_
+#include "base/component_export.h"
#include "services/resource_coordinator/public/cpp/coordination_unit_types.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
-#include "services/resource_coordinator/public/interfaces/interfaces_export.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
namespace mojo {
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
EnumTraits<resource_coordinator::mojom::CoordinationUnitType,
resource_coordinator::CoordinationUnitType> {
static resource_coordinator::mojom::CoordinationUnitType ToMojom(
@@ -22,7 +22,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
StructTraits<resource_coordinator::mojom::CoordinationUnitIDDataView,
resource_coordinator::CoordinationUnitID> {
static uint64_t id(const resource_coordinator::CoordinationUnitID& id) {
@@ -39,4 +39,4 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
} // namespace mojo
-#endif // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_STRUCT_TRAITS_H_
+#endif // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_COORDINATION_UNIT_MOJOM_TRAITS_H_
diff --git a/chromium/services/resource_coordinator/public/cpp/frame_resource_coordinator.h b/chromium/services/resource_coordinator/public/cpp/frame_resource_coordinator.h
index 0f5875fe427..0921fafff6c 100644
--- a/chromium/services/resource_coordinator/public/cpp/frame_resource_coordinator.h
+++ b/chromium/services/resource_coordinator/public/cpp/frame_resource_coordinator.h
@@ -8,7 +8,7 @@
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_interface.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
namespace resource_coordinator {
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/OWNERS b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/OWNERS
index eb6a334dcf0..a5521d03293 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/OWNERS
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/OWNERS
@@ -3,5 +3,5 @@ file://services/resource_coordinator/memory_instrumentation/OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
index 98764e8e3dd..5c9a38f19ab 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.cc
@@ -15,7 +15,7 @@
#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
#include "services/service_manager/public/cpp/connector.h"
@@ -129,18 +129,19 @@ void ClientProcessImpl::RequestOSMemoryDump(
bool want_mmaps,
const std::vector<base::ProcessId>& pids,
const RequestOSMemoryDumpCallback& callback) {
+ bool global_success = true;
std::unordered_map<base::ProcessId, mojom::RawOSMemDumpPtr> results;
for (const base::ProcessId& pid : pids) {
mojom::RawOSMemDumpPtr result = mojom::RawOSMemDump::New();
result->platform_private_footprint = mojom::PlatformPrivateFootprint::New();
- bool success = true;
- success = success && OSMetrics::FillOSMemoryDump(pid, result.get());
+ bool success = OSMetrics::FillOSMemoryDump(pid, result.get());
if (want_mmaps)
success = success && OSMetrics::FillProcessMemoryMaps(pid, result.get());
if (success)
results[pid] = std::move(result);
+ global_success = global_success && success;
}
- callback.Run(true, std::move(results));
+ callback.Run(global_success, std::move(results));
}
ClientProcessImpl::Config::Config(service_manager::Connector* connector,
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h
index a75aeca5c2e..8000109366f 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/client_process_impl.h
@@ -13,7 +13,7 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace memory_instrumentation {
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h
index 83b3a403dca..dad877d2c2c 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_COORDINATOR_H_
#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_COORDINATOR_H_
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
namespace service_manager {
struct BindSourceInfo;
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.cc
index 0448d91895f..9c11149f3f7 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.cc
@@ -29,14 +29,14 @@ GlobalMemoryDump::ProcessDump::~ProcessDump() = default;
base::Optional<uint64_t> GlobalMemoryDump::ProcessDump::GetMetric(
const std::string& dump_name,
- const std::string& metric_name) {
+ const std::string& metric_name) const {
auto dump_it =
raw_dump_->chrome_dump->entries_for_allocator_dumps.find(dump_name);
- if (dump_it == raw_dump_->chrome_dump->entries_for_allocator_dumps.end())
+ if (dump_it == raw_dump_->chrome_dump->entries_for_allocator_dumps.cend())
return base::nullopt;
auto metric_it = dump_it->second->numeric_entries.find(metric_name);
- if (metric_it == dump_it->second->numeric_entries.end())
+ if (metric_it == dump_it->second->numeric_entries.cend())
return base::nullopt;
return base::Optional<uint64_t>(metric_it->second);
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h
index ecb4819d03d..1aa720451d7 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h
@@ -7,7 +7,7 @@
#include "base/optional.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
namespace memory_instrumentation {
@@ -15,7 +15,7 @@ namespace memory_instrumentation {
// service containing dumps for each process.
class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT GlobalMemoryDump {
public:
- class ProcessDump {
+ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ProcessDump {
public:
ProcessDump(mojom::ProcessMemoryDumpPtr process_memory_dump);
~ProcessDump();
@@ -24,7 +24,7 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT GlobalMemoryDump {
// GetMetric("blink", "size") would return the aggregated sze of the
// "blink/" dump.
base::Optional<uint64_t> GetMetric(const std::string& dump_name,
- const std::string& metric_name);
+ const std::string& metric_name) const;
base::ProcessId pid() const { return raw_dump_->pid; }
mojom::ProcessType process_type() const { return raw_dump_->process_type; }
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h
index f51a00dbafd..6e305099a9c 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.h
@@ -12,7 +12,7 @@
#include "services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/global_memory_dump.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace base {
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap
index e53485529d8..03a1c5a9cf4 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation.typemap
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom"
+mojom = "//services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom"
public_headers = [
"//base/trace_event/memory_dump_request_args.h",
@@ -10,10 +10,10 @@ public_headers = [
"//base/trace_event/memory_allocator_dump.h",
"//base/trace_event/memory_dump_manager.h",
]
-traits_headers = [ "//services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.h" ]
+traits_headers = [ "//services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h" ]
sources = [
- "//services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.cc",
- "//services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.h",
+ "//services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.cc",
+ "//services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h",
]
deps = [
"//base",
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.cc
index d56d4f5e2b1..f7aae6cd2af 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h"
namespace mojo {
@@ -62,10 +62,6 @@ EnumTraits<memory_instrumentation::mojom::LevelOfDetail,
return memory_instrumentation::mojom::LevelOfDetail::BACKGROUND;
case base::trace_event::MemoryDumpLevelOfDetail::LIGHT:
return memory_instrumentation::mojom::LevelOfDetail::LIGHT;
- case base::trace_event::MemoryDumpLevelOfDetail::
- VM_REGIONS_ONLY_FOR_HEAP_PROFILER:
- return memory_instrumentation::mojom::LevelOfDetail::
- VM_REGIONS_ONLY_FOR_HEAP_PROFILER;
case base::trace_event::MemoryDumpLevelOfDetail::DETAILED:
return memory_instrumentation::mojom::LevelOfDetail::DETAILED;
default:
@@ -87,11 +83,6 @@ bool EnumTraits<memory_instrumentation::mojom::LevelOfDetail,
case memory_instrumentation::mojom::LevelOfDetail::LIGHT:
*out = base::trace_event::MemoryDumpLevelOfDetail::LIGHT;
break;
- case memory_instrumentation::mojom::LevelOfDetail::
- VM_REGIONS_ONLY_FOR_HEAP_PROFILER:
- *out = base::trace_event::MemoryDumpLevelOfDetail::
- VM_REGIONS_ONLY_FOR_HEAP_PROFILER;
- break;
case memory_instrumentation::mojom::LevelOfDetail::DETAILED:
*out = base::trace_event::MemoryDumpLevelOfDetail::DETAILED;
break;
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.h b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h
index 67e3c54aa83..c9b5d2cd9d8 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h
@@ -2,21 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_MEMORY_INSTRUMENTATION_STRUCT_TRAITS_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_MEMORY_INSTRUMENTATION_STRUCT_TRAITS_H_
+#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_MEMORY_INSTRUMENTATION_MOJOM_TRAITS_H_
+#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_MEMORY_INSTRUMENTATION_MOJOM_TRAITS_H_
+#include "base/component_export.h"
#include "base/process/process_handle.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "mojo/common/common_custom_types_struct_traits.h"
-#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-#include "services/resource_coordinator/public/interfaces/interfaces_export.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
namespace mojo {
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
EnumTraits<memory_instrumentation::mojom::DumpType,
base::trace_event::MemoryDumpType> {
static memory_instrumentation::mojom::DumpType ToMojom(
@@ -26,7 +25,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
EnumTraits<memory_instrumentation::mojom::LevelOfDetail,
base::trace_event::MemoryDumpLevelOfDetail> {
static memory_instrumentation::mojom::LevelOfDetail ToMojom(
@@ -36,7 +35,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
EnumTraits<memory_instrumentation::mojom::HeapProfilingMode,
base::trace_event::HeapProfilingMode> {
static memory_instrumentation::mojom::HeapProfilingMode ToMojom(
@@ -46,7 +45,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
StructTraits<memory_instrumentation::mojom::RequestArgsDataView,
base::trace_event::MemoryDumpRequestArgs> {
static uint64_t dump_guid(
@@ -66,7 +65,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT StructTraits<
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM) StructTraits<
memory_instrumentation::mojom::RawAllocatorDumpEdgeDataView,
base::trace_event::ProcessMemoryDump::MemoryAllocatorDumpEdge> {
static uint64_t source_id(
@@ -95,7 +94,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT StructTraits<
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT UnionTraits<
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM) UnionTraits<
memory_instrumentation::mojom::RawAllocatorDumpEntryValueDataView,
base::trace_event::MemoryAllocatorDump::Entry> {
static memory_instrumentation::mojom::RawAllocatorDumpEntryValue::Tag GetTag(
@@ -129,7 +128,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT UnionTraits<
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
StructTraits<memory_instrumentation::mojom::RawAllocatorDumpEntryDataView,
base::trace_event::MemoryAllocatorDump::Entry> {
static const std::string& name(
@@ -150,7 +149,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
StructTraits<memory_instrumentation::mojom::RawAllocatorDumpDataView,
std::unique_ptr<base::trace_event::MemoryAllocatorDump>> {
static uint64_t id(
@@ -179,7 +178,7 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
};
template <>
-struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
+struct COMPONENT_EXPORT(RESOURCE_COORDINATOR_PUBLIC_MOJOM)
StructTraits<memory_instrumentation::mojom::RawProcessMemoryDumpDataView,
std::unique_ptr<base::trace_event::ProcessMemoryDump>> {
// TODO(primiano): Remove this wrapping vector to adapt the underlying map<>
@@ -221,4 +220,4 @@ struct RESOURCE_COORDINATOR_PUBLIC_INTERFACES_EXPORT
} // namespace mojo
-#endif // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_MEMORY_INSTRUMENTATION_STRUCT_TRAITS_H_
+#endif // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_INSTRUMENTATION_MEMORY_INSTRUMENTATION_MOJOM_TRAITS_H_
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/struct_traits_unittest.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits_unittest.cc
index 0558426e11a..e0520417256 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/struct_traits_unittest.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits_unittest.cc
@@ -8,8 +8,8 @@
#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "base/trace_event/process_memory_dump.h"
-#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_struct_traits.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/cpp/memory_instrumentation/memory_instrumentation_mojom_traits.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "testing/gmock/include/gmock/gmock.h" // for testing::Contains.
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
index 804c869794f..358de0eafca 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics.h
@@ -9,7 +9,7 @@
#include "base/trace_event/process_memory_dump.h"
#include "build/build_config.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
namespace profiling {
FORWARD_DECLARE_TEST(ProfilingJsonExporterTest, MemoryMaps);
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc
index 5a9b10f00ee..3c2e4379695 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/os_metrics_mac.cc
@@ -136,6 +136,7 @@ void PopulateByteStats(VMRegion* region,
case SM_PRIVATE:
case SM_COW:
region->byte_stats_private_dirty_resident = dirty_bytes;
+ break;
case SM_SHARED:
case SM_PRIVATE_ALIASED:
case SM_TRUESHARED:
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
index 0d9dbcb65d0..44361915bdd 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_integration_unittest.cc
@@ -22,7 +22,7 @@
#include "base/trace_event/trace_log.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/resource_coordinator/public/cpp/memory_instrumentation/coordinator.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -115,6 +115,8 @@ class MockCoordinator : public Coordinator, public mojom::Coordinator {
void RegisterClientProcess(mojom::ClientProcessPtr,
mojom::ProcessType) override {}
+ void RegisterHeapProfiler(mojom::HeapProfilerPtr heap_profiler) override {}
+
void RequestGlobalMemoryDump(
MemoryDumpType dump_type,
MemoryDumpLevelOfDetail level_of_detail,
@@ -157,7 +159,7 @@ class MemoryTracingIntegrationTest : public testing::Test {
client_process_.reset();
coordinator_.reset();
message_loop_.reset();
- TraceLog::DeleteForTesting();
+ TraceLog::ResetForTesting();
}
// Blocks the current thread (spinning a nested message loop) until the
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.cc b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.cc
index c61bccce27c..94a588c5b66 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.cc
@@ -30,10 +30,6 @@ bool IsMemoryInfraTracingEnabled() {
void OsDumpAsValueInto(TracedValue* value, const mojom::OSMemDump& os_dump) {
value->SetString(
- "resident_set_bytes",
- base::StringPrintf(
- "%" PRIx64, static_cast<uint64_t>(os_dump.resident_set_kb) * 1024));
- value->SetString(
"private_footprint_bytes",
base::StringPrintf(
"%" PRIx64,
diff --git a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h
index 02f9192f178..6950341837b 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory_instrumentation/tracing_observer.h
@@ -9,7 +9,7 @@
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_event.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-#include "services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom.h"
+#include "services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom.h"
namespace memory_instrumentation {
diff --git a/chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.cc b/chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.cc
index 96abd82c46a..37ab4429745 100644
--- a/chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.cc
+++ b/chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.cc
@@ -15,6 +15,12 @@ PageResourceCoordinator::PageResourceCoordinator(
PageResourceCoordinator::~PageResourceCoordinator() = default;
+void PageResourceCoordinator::SetIsLoading(bool is_loading) {
+ if (!service_)
+ return;
+ service_->SetIsLoading(is_loading);
+}
+
void PageResourceCoordinator::SetVisibility(bool visible) {
if (!service_)
return;
diff --git a/chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.h b/chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.h
index bd49552abd6..8167ab8e0b7 100644
--- a/chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.h
+++ b/chromium/services/resource_coordinator/public/cpp/page_resource_coordinator.h
@@ -9,7 +9,7 @@
#include "base/threading/thread_checker.h"
#include "services/resource_coordinator/public/cpp/frame_resource_coordinator.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_interface.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
namespace resource_coordinator {
@@ -20,6 +20,7 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT PageResourceCoordinator
PageResourceCoordinator(service_manager::Connector* connector);
~PageResourceCoordinator() override;
+ void SetIsLoading(bool is_loading);
void SetVisibility(bool visible);
void SetUKMSourceId(int64_t ukm_source_id);
void OnFaviconUpdated();
diff --git a/chromium/services/resource_coordinator/public/cpp/process_resource_coordinator.h b/chromium/services/resource_coordinator/public/cpp/process_resource_coordinator.h
index 75c68db271a..9f56dc73ceb 100644
--- a/chromium/services/resource_coordinator/public/cpp/process_resource_coordinator.h
+++ b/chromium/services/resource_coordinator/public/cpp/process_resource_coordinator.h
@@ -9,7 +9,7 @@
#include "base/threading/thread_checker.h"
#include "services/resource_coordinator/public/cpp/frame_resource_coordinator.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_interface.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit.mojom.h"
namespace resource_coordinator {
diff --git a/chromium/services/resource_coordinator/public/cpp/resource_coordinator_interface.h b/chromium/services/resource_coordinator/public/cpp/resource_coordinator_interface.h
index 3d6e08f3c9e..014567fa318 100644
--- a/chromium/services/resource_coordinator/public/cpp/resource_coordinator_interface.h
+++ b/chromium/services/resource_coordinator/public/cpp/resource_coordinator_interface.h
@@ -10,8 +10,8 @@
#include "base/macros.h"
#include "services/resource_coordinator/public/cpp/coordination_unit_id.h"
#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom.h"
-#include "services/resource_coordinator/public/interfaces/service_constants.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit_provider.mojom.h"
+#include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
namespace resource_coordinator {
diff --git a/chromium/services/resource_coordinator/public/cpp/tracing/OWNERS b/chromium/services/resource_coordinator/public/cpp/tracing/OWNERS
deleted file mode 100644
index dd009224ba7..00000000000
--- a/chromium/services/resource_coordinator/public/cpp/tracing/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-file://base/trace_event/OWNERS
-chiniforooshan@chromium.org
diff --git a/chromium/services/resource_coordinator/public/interfaces/BUILD.gn b/chromium/services/resource_coordinator/public/mojom/BUILD.gn
index a6263d6450d..a0297d63723 100644
--- a/chromium/services/resource_coordinator/public/interfaces/BUILD.gn
+++ b/chromium/services/resource_coordinator/public/mojom/BUILD.gn
@@ -4,9 +4,9 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom_component("interfaces") {
- output_prefix = "resource_coordinator_public_interfaces"
- macro_prefix = "RESOURCE_COORDINATOR_PUBLIC_INTERFACES"
+mojom_component("mojom") {
+ output_prefix = "resource_coordinator_public_mojom"
+ macro_prefix = "RESOURCE_COORDINATOR_PUBLIC_MOJOM"
sources = [
"coordination_unit.mojom",
@@ -17,15 +17,18 @@ mojom_component("interfaces") {
"page_signal.mojom",
"service_constants.mojom",
"signals.mojom",
- "tracing/tracing.mojom",
- "tracing/tracing_constants.mojom",
]
public_deps = [
"//mojo/common:common_custom_types",
- "//services/metrics/public/interfaces",
+ "//services/metrics/public/mojom",
]
+ enabled_features = []
+ if (is_linux || is_android) {
+ enabled_features += [ "private_swap_info" ]
+ }
+
# TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
use_once_callback = false
}
diff --git a/chromium/services/resource_coordinator/public/interfaces/OWNERS b/chromium/services/resource_coordinator/public/mojom/OWNERS
index 5c3a6ac434e..5c3a6ac434e 100644
--- a/chromium/services/resource_coordinator/public/interfaces/OWNERS
+++ b/chromium/services/resource_coordinator/public/mojom/OWNERS
diff --git a/chromium/services/resource_coordinator/public/interfaces/coordination_unit.mojom b/chromium/services/resource_coordinator/public/mojom/coordination_unit.mojom
index 49852f63ab5..ab653987938 100644
--- a/chromium/services/resource_coordinator/public/interfaces/coordination_unit.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/coordination_unit.mojom
@@ -56,6 +56,7 @@ interface PageCoordinationUnit {
RemoveFrame(CoordinationUnitID cu_id);
// Property signals.
+ SetIsLoading(bool is_loading);
SetVisibility(bool visible);
SetUKMSourceId(int64 ukm_source_id);
diff --git a/chromium/services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom b/chromium/services/resource_coordinator/public/mojom/coordination_unit_introspector.mojom
index 3767566c86f..3767566c86f 100644
--- a/chromium/services/resource_coordinator/public/interfaces/coordination_unit_introspector.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/coordination_unit_introspector.mojom
diff --git a/chromium/services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom b/chromium/services/resource_coordinator/public/mojom/coordination_unit_provider.mojom
index d96fc304505..d96fc304505 100644
--- a/chromium/services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/coordination_unit_provider.mojom
diff --git a/chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/OWNERS b/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/OWNERS
+++ b/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/OWNERS
diff --git a/chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/constants.mojom b/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/constants.mojom
index 8a0387f8899..8a0387f8899 100644
--- a/chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/constants.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/constants.mojom
diff --git a/chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom b/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
index 3a917acc601..1b4b2d12553 100644
--- a/chromium/services/resource_coordinator/public/interfaces/memory_instrumentation/memory_instrumentation.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/memory_instrumentation/memory_instrumentation.mojom
@@ -18,7 +18,6 @@ enum DumpType {
enum LevelOfDetail {
BACKGROUND,
LIGHT,
- VM_REGIONS_ONLY_FOR_HEAP_PROFILER,
DETAILED
};
@@ -147,15 +146,9 @@ struct OSMemDump {
// in kilobytes. For more details, see https://goo.gl/3kPb9S.
uint32 shared_footprint_kb = 0;
- // This field is present only when the dump is obtained through
- // Coordinator.GetVmRegionsForHeapProfiler(), empty in the generic case of
- // RequestGlobalMemoryDump().
- array<VmRegion> memory_maps_for_heap_profiler;
-
// This is private swapped memory in kilobytes reported on Linux and Android
// only.
- // TODO(crbug.com/676224): add platform restrictions when preprocessing in
- // mojoms is supported.
+ [EnableIf=private_swap_info]
uint32 private_footprint_swap_kb = 0;
};
@@ -232,6 +225,42 @@ interface ClientProcess {
(bool success, map<mojo.common.mojom.ProcessId, RawOSMemDump> dumps);
};
+struct SharedBufferWithSize {
+ handle<shared_buffer> buffer;
+ uint32 size;
+ mojo.common.mojom.ProcessId pid;
+};
+
+// HeapProfilers expose a single interface to memory_instrumentation, allowing
+// the latter to query for heap dumps when necessary.
+//
+// This interface is NOT implemented in resource_coordinator but by the
+// profiling service in chrome/profiler. The profiling service registers itself
+// with the Coordinator (see RegisterHeapProfiler) and is invoked when a memory
+// dump is requested (via Coordinator::RequestGlobalMemoryDump).
+interface HeapProfiler {
+ // Dumps the memory log of all profiled processes into shared buffers. The
+ // contents of each shared buffer is a JSON string compatible with
+ // TRACE_EVENT* macros. Processes that fail to dump will be omitted from
+ // |buffers|. When |strip_path_from_mapped_files| is true, only the base name
+ // of mapped files is emitted. This prevents usernames from sneaking into the
+ // trace.
+ // |strip_path_from_mapped_files| should only be true for traces that will be
+ // uploaded to the crash servers - this strips potential PII, but prevents
+ // symbolization of local builds.
+ DumpProcessesForTracing(bool strip_path_from_mapped_files) =>
+ (array<SharedBufferWithSize> buffers);
+};
+
+// Implemented by resource_coordinator to provide additional information needed
+// by the HeapProfiler.
+interface HeapProfilerHelper {
+ // Broadcasts a RequestOSMemoryDump-only request for all registered client
+ // processes and retrieves only their memory maps.
+ GetVmRegionsForHeapProfiler(array<mojo.common.mojom.ProcessId> pids) =>
+ (map<mojo.common.mojom.ProcessId, array<VmRegion>> vm_regions);
+};
+
// The memory-infra service implements this interface. There is one instance for
// the whole system. The coordinator maintains a list of registered client
// processes and polls them whenever a global dump is required.
@@ -259,13 +288,11 @@ interface Coordinator {
RequestGlobalMemoryDumpAndAppendToTrace(DumpType dump_type,
LevelOfDetail level_of_detail) =>
(bool success, uint64 dump_id);
-};
-// Used by the Chrome heap profiler
-interface HeapProfilerHelper {
- // Broadcasts a RequestOSMemoryDump-only request for all registered client
- // processes, retrieves only their memory maps and returns them in the field
- // |global_memory_dump.process_dumps.os_dump.memory_maps_for_heap_profiler|.
- GetVmRegionsForHeapProfiler() =>
- (bool success, GlobalMemoryDump? global_memory_dump);
+ // When a heap profiler is registered, heap dumps will be added to the trace
+ // any time RequestGlobalMemoryDumpAndAppendToTrace is called.
+ // This is cleaner than having the memory_instrumentation service talk
+ // directly to the HeapProfiler, since that will spawn the HeapProfiler in a
+ // new process if it isn't already running.
+ RegisterHeapProfiler(HeapProfiler heap_profiler);
};
diff --git a/chromium/services/resource_coordinator/public/interfaces/page_signal.mojom b/chromium/services/resource_coordinator/public/mojom/page_signal.mojom
index 8ff3be062a9..8ff3be062a9 100644
--- a/chromium/services/resource_coordinator/public/interfaces/page_signal.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/page_signal.mojom
diff --git a/chromium/services/resource_coordinator/public/interfaces/service_constants.mojom b/chromium/services/resource_coordinator/public/mojom/service_constants.mojom
index 92df94e0c92..92df94e0c92 100644
--- a/chromium/services/resource_coordinator/public/interfaces/service_constants.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/service_constants.mojom
diff --git a/chromium/services/resource_coordinator/public/interfaces/signals.mojom b/chromium/services/resource_coordinator/public/mojom/signals.mojom
index 5b15878ec7b..34200d9d174 100644
--- a/chromium/services/resource_coordinator/public/interfaces/signals.mojom
+++ b/chromium/services/resource_coordinator/public/mojom/signals.mojom
@@ -31,4 +31,6 @@ enum PropertyType {
kPID,
kVisible,
kUKMSourceId,
+ // Used by Page CUs to store current loading state.
+ kIsLoading,
};
diff --git a/chromium/services/resource_coordinator/resource_coordinator_service.cc b/chromium/services/resource_coordinator/resource_coordinator_service.cc
index 51e296ff661..52a88f8b140 100644
--- a/chromium/services/resource_coordinator/resource_coordinator_service.cc
+++ b/chromium/services/resource_coordinator/resource_coordinator_service.cc
@@ -12,8 +12,6 @@
#include "services/resource_coordinator/observers/ipc_volume_reporter.h"
#include "services/resource_coordinator/observers/metrics_collector.h"
#include "services/resource_coordinator/observers/page_signal_generator_impl.h"
-#include "services/resource_coordinator/tracing/agent_registry.h"
-#include "services/resource_coordinator/tracing/coordinator.h"
#include "services/service_manager/public/cpp/service_context.h"
namespace resource_coordinator {
@@ -28,14 +26,11 @@ std::unique_ptr<service_manager::Service> ResourceCoordinatorService::Create() {
ResourceCoordinatorService::ResourceCoordinatorService()
: weak_factory_(this) {}
-ResourceCoordinatorService::~ResourceCoordinatorService() {
- ref_factory_.reset();
-}
+ResourceCoordinatorService::~ResourceCoordinatorService() = default;
void ResourceCoordinatorService::OnStart() {
ref_factory_.reset(new service_manager::ServiceContextRefFactory(
- base::Bind(&service_manager::ServiceContext::RequestQuit,
- base::Unretained(context()))));
+ context()->CreateQuitClosure()));
ukm_recorder_ = ukm::MojoUkmRecorder::Create(context()->connector());
@@ -75,16 +70,6 @@ void ResourceCoordinatorService::OnStart() {
registry_.AddInterface(base::BindRepeating(
&memory_instrumentation::CoordinatorImpl::BindHeapProfilerHelperRequest,
base::Unretained(memory_instrumentation_coordinator_.get())));
-
- tracing_agent_registry_ = std::make_unique<tracing::AgentRegistry>();
- registry_.AddInterface(
- base::BindRepeating(&tracing::AgentRegistry::BindAgentRegistryRequest,
- base::Unretained(tracing_agent_registry_.get())));
-
- tracing_coordinator_ = std::make_unique<tracing::Coordinator>();
- registry_.AddInterface(
- base::BindRepeating(&tracing::Coordinator::BindCoordinatorRequest,
- base::Unretained(tracing_coordinator_.get())));
}
void ResourceCoordinatorService::OnBindInterface(
diff --git a/chromium/services/resource_coordinator/resource_coordinator_service.h b/chromium/services/resource_coordinator/resource_coordinator_service.h
index 61fbf4c6525..6ffa3ededd9 100644
--- a/chromium/services/resource_coordinator/resource_coordinator_service.h
+++ b/chromium/services/resource_coordinator/resource_coordinator_service.h
@@ -15,8 +15,6 @@
#include "services/resource_coordinator/coordination_unit/coordination_unit_introspector_impl.h"
#include "services/resource_coordinator/coordination_unit/coordination_unit_manager.h"
#include "services/resource_coordinator/memory_instrumentation/coordinator_impl.h"
-#include "services/resource_coordinator/tracing/agent_registry.h"
-#include "services/resource_coordinator/tracing/coordinator.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
@@ -50,14 +48,12 @@ class ResourceCoordinatorService : public service_manager::Service {
service_manager::BinderRegistryWithArgs<
const service_manager::BindSourceInfo&>
registry_;
- std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
CoordinationUnitManager coordination_unit_manager_;
CoordinationUnitIntrospectorImpl introspector_;
std::unique_ptr<ukm::MojoUkmRecorder> ukm_recorder_;
std::unique_ptr<memory_instrumentation::CoordinatorImpl>
memory_instrumentation_coordinator_;
- std::unique_ptr<tracing::AgentRegistry> tracing_agent_registry_;
- std::unique_ptr<tracing::Coordinator> tracing_coordinator_;
+ std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
// WeakPtrFactory members should always come last so WeakPtrs are destructed
// before other members.
diff --git a/chromium/services/resource_coordinator/resource_coordinator_service_unittest.cc b/chromium/services/resource_coordinator/resource_coordinator_service_unittest.cc
index 20147aaacb8..eb4cc9c7ed1 100644
--- a/chromium/services/resource_coordinator/resource_coordinator_service_unittest.cc
+++ b/chromium/services/resource_coordinator/resource_coordinator_service_unittest.cc
@@ -7,8 +7,8 @@
#include "base/macros.h"
#include "base/run_loop.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/resource_coordinator/public/interfaces/coordination_unit_provider.mojom.h"
-#include "services/resource_coordinator/public/interfaces/service_constants.mojom.h"
+#include "services/resource_coordinator/public/mojom/coordination_unit_provider.mojom.h"
+#include "services/resource_coordinator/public/mojom/service_constants.mojom.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_test.h"
diff --git a/chromium/services/resource_coordinator/tracing/BUILD.gn b/chromium/services/resource_coordinator/tracing/BUILD.gn
deleted file mode 100644
index a4182cc520e..00000000000
--- a/chromium/services/resource_coordinator/tracing/BUILD.gn
+++ /dev/null
@@ -1,20 +0,0 @@
-# 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.
-
-source_set("lib") {
- sources = [
- "agent_registry.cc",
- "agent_registry.h",
- "coordinator.cc",
- "coordinator.h",
- "recorder.cc",
- "recorder.h",
- ]
-
- public_deps = [
- "//base",
- "//mojo/common",
- "//services/resource_coordinator/public/cpp:resource_coordinator_cpp",
- ]
-}
diff --git a/chromium/services/resource_coordinator/tracing/OWNER b/chromium/services/resource_coordinator/tracing/OWNER
deleted file mode 100644
index b67fe432af9..00000000000
--- a/chromium/services/resource_coordinator/tracing/OWNER
+++ /dev/null
@@ -1 +0,0 @@
-chiniforooshan@chromium.org
diff --git a/chromium/services/service_manager/BUILD.gn b/chromium/services/service_manager/BUILD.gn
index 9643822df46..55cdc1339c4 100644
--- a/chromium/services/service_manager/BUILD.gn
+++ b/chromium/services/service_manager/BUILD.gn
@@ -45,9 +45,9 @@ source_set("service_manager") {
"//base",
"//mojo/public/cpp/bindings",
"//services/catalog:lib",
- "//services/catalog/public/interfaces:constants",
+ "//services/catalog/public/mojom:constants",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/service_manager/runner/host:lib",
"//services/service_manager/sandbox",
]
diff --git a/chromium/services/service_manager/README.md b/chromium/services/service_manager/README.md
index a50bd566356..a5fbbc279bd 100644
--- a/chromium/services/service_manager/README.md
+++ b/chromium/services/service_manager/README.md
@@ -19,7 +19,7 @@ The Service Manager performs the following functions:
system state.
The Service Manager presents a series of Mojo
-[interfaces](https://cs.chromium.org/chromium/src/services/service_manager/public/interfaces/)
+[interfaces](https://cs.chromium.org/chromium/src/services/service_manager/public/mojom/)
to services, though in practice most interaction with the Service Manager is
made simpler by using its corresponding
[C++ client library](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/).
@@ -69,7 +69,7 @@ ID**, and **instance qualifier**:
As long as a service instance is running it must maintain an implementation of
the
-[`service_manager.mojom.Service`](https://cs.chromium.org/chromium/src/services/service_manager/public/interfaces/service.mojom)
+[`service_manager.mojom.Service`](https://cs.chromium.org/chromium/src/services/service_manager/public/mojom/service.mojom)
interface. Typically this is done in C++ code by implementing the C++ client
library's
[`service_manager::Service`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/service.h)
@@ -80,7 +80,7 @@ other services.
Every service instance also has an outgoing link back to the Service Manager
which it can use to make interface requests to other services in the system.
This is the
-[`service_manager.mojom.Connector`](https://cs.chromium.org/chromium/src/services/service_manager/public/interfaces/connector.mojom)
+[`service_manager.mojom.Connector`](https://cs.chromium.org/chromium/src/services/service_manager/public/mojom/connector.mojom)
interface, and it's commonly used via the C++ client library's
[`service_manager::Connector`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/connector.h)
class.
diff --git a/chromium/services/service_manager/background/background_service_manager.h b/chromium/services/service_manager/background/background_service_manager.h
index ef62ffa3b5e..edea2b394b8 100644
--- a/chromium/services/service_manager/background/background_service_manager.h
+++ b/chromium/services/service_manager/background/background_service_manager.h
@@ -11,8 +11,8 @@
#include "base/threading/thread.h"
#include "base/values.h"
#include "build/build_config.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
#include "services/service_manager/runner/host/service_process_launcher_delegate.h"
namespace base {
diff --git a/chromium/services/service_manager/background/tests/BUILD.gn b/chromium/services/service_manager/background/tests/BUILD.gn
index bd9663b03cf..43f1cdeadfb 100644
--- a/chromium/services/service_manager/background/tests/BUILD.gn
+++ b/chromium/services/service_manager/background/tests/BUILD.gn
@@ -44,7 +44,7 @@ service("background_service_manager_test_service") {
":test_service_interfaces",
"//base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
diff --git a/chromium/services/service_manager/connect_params.h b/chromium/services/service_manager/connect_params.h
index 7089ed18928..a732ac684ed 100644
--- a/chromium/services/service_manager/connect_params.h
+++ b/chromium/services/service_manager/connect_params.h
@@ -12,8 +12,8 @@
#include "base/macros.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
namespace service_manager {
diff --git a/chromium/services/service_manager/connect_util.cc b/chromium/services/service_manager/connect_util.cc
index 085fdf601d9..f8636f4b9dd 100644
--- a/chromium/services/service_manager/connect_util.cc
+++ b/chromium/services/service_manager/connect_util.cc
@@ -13,12 +13,6 @@
namespace service_manager {
-namespace {
-
-void EmptyStartServiceCallback(mojom::ConnectResult result,
- const Identity& resolved_identity) {}
-}
-
mojo::ScopedMessagePipeHandle BindInterface(
ServiceManager* service_manager,
const Identity& source,
@@ -29,7 +23,7 @@ mojo::ScopedMessagePipeHandle BindInterface(
params->set_target(target);
mojo::MessagePipe pipe;
params->set_interface_request_info(interface_name, std::move(pipe.handle1));
- params->set_start_service_callback(base::Bind(&EmptyStartServiceCallback));
+ params->set_start_service_callback(base::DoNothing());
service_manager->Connect(std::move(params));
return std::move(pipe.handle0);
}
diff --git a/chromium/services/service_manager/connect_util.h b/chromium/services/service_manager/connect_util.h
index c31f0373e96..c57256a2115 100644
--- a/chromium/services/service_manager/connect_util.h
+++ b/chromium/services/service_manager/connect_util.h
@@ -8,7 +8,7 @@
#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/system/handle.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
namespace service_manager {
diff --git a/chromium/services/service_manager/embedder/BUILD.gn b/chromium/services/service_manager/embedder/BUILD.gn
index 212cc8d4375..67efc260e53 100644
--- a/chromium/services/service_manager/embedder/BUILD.gn
+++ b/chromium/services/service_manager/embedder/BUILD.gn
@@ -59,7 +59,7 @@ component("embedder") {
if (!is_ios) {
# deps of ServiceManager::Main and related functionality.
deps += [
- "//base/allocator:features",
+ "//base/allocator:buildflags",
"//components/tracing:startup_tracing",
"//ui/base",
]
diff --git a/chromium/services/service_manager/embedder/embedded_instance_manager_unittest.cc b/chromium/services/service_manager/embedder/embedded_instance_manager_unittest.cc
index 30997e8a3ab..52634177975 100644
--- a/chromium/services/service_manager/embedder/embedded_instance_manager_unittest.cc
+++ b/chromium/services/service_manager/embedder/embedded_instance_manager_unittest.cc
@@ -58,8 +58,7 @@ TEST(EmbeddedInstanceManager, ShutdownWaitsForThreadToQuit) {
instance_manager->ShutDown();
EXPECT_FALSE(test_api.GetThread());
// Further verification the thread was shutdown.
- EXPECT_FALSE(
- thread_task_runner->PostTask(FROM_HERE, base::Bind(&base::DoNothing)));
+ EXPECT_FALSE(thread_task_runner->PostTask(FROM_HERE, base::DoNothing()));
// Because Shutdown() was explicitly called with the thread running the
// quit closure should not have run.
EXPECT_FALSE(quit_called);
diff --git a/chromium/services/service_manager/embedder/embedded_service_runner.h b/chromium/services/service_manager/embedder/embedded_service_runner.h
index 11f767828c9..5aa19f1fb41 100644
--- a/chromium/services/service_manager/embedder/embedded_service_runner.h
+++ b/chromium/services/service_manager/embedder/embedded_service_runner.h
@@ -16,7 +16,7 @@
#include "services/service_manager/embedder/embedded_service_info.h"
#include "services/service_manager/embedder/service_manager_embedder_export.h"
#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
namespace service_manager {
diff --git a/chromium/services/service_manager/embedder/main.cc b/chromium/services/service_manager/embedder/main.cc
index 08ea94a1177..ed36168629a 100644
--- a/chromium/services/service_manager/embedder/main.cc
+++ b/chromium/services/service_manager/embedder/main.cc
@@ -4,7 +4,7 @@
#include "services/service_manager/embedder/main.h"
-#include "base/allocator/features.h"
+#include "base/allocator/buildflags.h"
#include "base/at_exit.h"
#include "base/base_switches.h"
#include "base/command_line.h"
@@ -21,7 +21,6 @@
#include "base/process/process.h"
#include "base/run_loop.h"
#include "base/task_scheduler/task_scheduler.h"
-#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread.h"
#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_log.h"
@@ -227,8 +226,6 @@ int RunServiceManager(MainDelegate* delegate) {
base::MessageLoop message_loop(base::MessageLoop::TYPE_UI);
- base::SequencedWorkerPool::EnableWithRedirectionToTaskSchedulerForProcess();
-
base::Thread ipc_thread("IPC thread");
ipc_thread.StartWithOptions(
base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
diff --git a/chromium/services/service_manager/public/cpp/BUILD.gn b/chromium/services/service_manager/public/cpp/BUILD.gn
index 03f7d51b093..fc22798eb41 100644
--- a/chromium/services/service_manager/public/cpp/BUILD.gn
+++ b/chromium/services/service_manager/public/cpp/BUILD.gn
@@ -30,8 +30,8 @@ component("cpp") {
"//base",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
- "//services/service_manager/public/interfaces",
- "//services/service_manager/public/interfaces:constants",
+ "//services/service_manager/public/mojom",
+ "//services/service_manager/public/mojom:constants",
"//url",
]
@@ -55,7 +55,7 @@ component("cpp_types") {
]
deps = [
- "//services/service_manager/public/interfaces:constants",
+ "//services/service_manager/public/mojom:constants",
]
defines = [ "SERVICE_MANAGER_PUBLIC_CPP_TYPES_IMPL" ]
@@ -80,7 +80,7 @@ static_library("service_test_support") {
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/system",
"//services/service_manager/background:lib",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
data_deps = []
diff --git a/chromium/services/service_manager/public/cpp/OWNERS b/chromium/services/service_manager/public/cpp/OWNERS
index 4df0c71cc7d..7aebc8abbf8 100644
--- a/chromium/services/service_manager/public/cpp/OWNERS
+++ b/chromium/services/service_manager/public/cpp/OWNERS
@@ -1,4 +1,4 @@
-per-file *_struct_traits*.*=set noparent
-per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+per-file *_mojom_traits*.*=set noparent
+per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
per-file *.typemap=set noparent
per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/service_manager/public/cpp/bind_source_info.typemap b/chromium/services/service_manager/public/cpp/bind_source_info.typemap
index eaaba31dee7..120f6d9dc07 100644
--- a/chromium/services/service_manager/public/cpp/bind_source_info.typemap
+++ b/chromium/services/service_manager/public/cpp/bind_source_info.typemap
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/service_manager/public/interfaces/service.mojom"
+mojom = "//services/service_manager/public/mojom/service.mojom"
public_headers = [ "//services/service_manager/public/cpp/bind_source_info.h" ]
traits_headers =
- [ "//services/service_manager/public/cpp/bind_source_info_struct_traits.h" ]
+ [ "//services/service_manager/public/cpp/bind_source_info_mojom_traits.h" ]
public_deps = [
"//services/service_manager/public/cpp:cpp_types",
]
diff --git a/chromium/services/service_manager/public/cpp/bind_source_info_struct_traits.h b/chromium/services/service_manager/public/cpp/bind_source_info_mojom_traits.h
index 1057dd7e29b..531323e7c6a 100644
--- a/chromium/services/service_manager/public/cpp/bind_source_info_struct_traits.h
+++ b/chromium/services/service_manager/public/cpp/bind_source_info_mojom_traits.h
@@ -6,13 +6,12 @@
#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_BIND_SOURCE_INFO_STRUCT_TRAITS_H_
#include "services/service_manager/public/cpp/bind_source_info.h"
-#include "services/service_manager/public/interfaces/interfaces_export.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
namespace mojo {
template <>
-struct SERVICE_MANAGER_MOJOM_EXPORT
+struct COMPONENT_EXPORT(SERVICE_MANAGER_MOJOM)
StructTraits<service_manager::mojom::BindSourceInfo::DataView,
service_manager::BindSourceInfo> {
static const service_manager::Identity& identity(
diff --git a/chromium/services/service_manager/public/cpp/connect.h b/chromium/services/service_manager/public/cpp/connect.h
index 87311331d26..42338037ac3 100644
--- a/chromium/services/service_manager/public/cpp/connect.h
+++ b/chromium/services/service_manager/public/cpp/connect.h
@@ -7,7 +7,7 @@
#include <utility>
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
+#include "services/service_manager/public/mojom/interface_provider.mojom.h"
namespace service_manager {
diff --git a/chromium/services/service_manager/public/cpp/connector.cc b/chromium/services/service_manager/public/cpp/connector.cc
index cdbbd817f8e..776b9a78e4b 100644
--- a/chromium/services/service_manager/public/cpp/connector.cc
+++ b/chromium/services/service_manager/public/cpp/connector.cc
@@ -69,7 +69,7 @@ void Connector::QueryService(const Identity& identity,
void Connector::BindInterface(const Identity& target,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) {
- auto service_overrides_iter = local_binder_overrides_.find(target.name());
+ auto service_overrides_iter = local_binder_overrides_.find(target);
if (service_overrides_iter != local_binder_overrides_.end()) {
auto override_iter = service_overrides_iter->second.find(interface_name);
if (override_iter != service_overrides_iter->second.end()) {
@@ -126,24 +126,25 @@ void Connector::OnConnectionError() {
connector_.reset();
}
-void Connector::OverrideBinderForTesting(const std::string& service_name,
- const std::string& interface_name,
- const TestApi::Binder& binder) {
- local_binder_overrides_[service_name][interface_name] = binder;
+void Connector::OverrideBinderForTesting(
+ const service_manager::Identity& identity,
+ const std::string& interface_name,
+ const TestApi::Binder& binder) {
+ local_binder_overrides_[identity][interface_name] = binder;
}
-bool Connector::HasBinderOverride(const std::string& service_name,
+bool Connector::HasBinderOverride(const service_manager::Identity& identity,
const std::string& interface_name) {
- auto service_overrides = local_binder_overrides_.find(service_name);
+ auto service_overrides = local_binder_overrides_.find(identity);
if (service_overrides == local_binder_overrides_.end())
return false;
return base::ContainsKey(service_overrides->second, interface_name);
}
-void Connector::ClearBinderOverride(const std::string& service_name,
+void Connector::ClearBinderOverride(const service_manager::Identity& identity,
const std::string& interface_name) {
- auto service_overrides = local_binder_overrides_.find(service_name);
+ auto service_overrides = local_binder_overrides_.find(identity);
if (service_overrides == local_binder_overrides_.end())
return;
diff --git a/chromium/services/service_manager/public/cpp/connector.h b/chromium/services/service_manager/public/cpp/connector.h
index 93240907918..447ece62389 100644
--- a/chromium/services/service_manager/public/cpp/connector.h
+++ b/chromium/services/service_manager/public/cpp/connector.h
@@ -12,9 +12,9 @@
#include "base/sequence_checker.h"
#include "services/service_manager/public/cpp/export.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
-#include "services/service_manager/public/interfaces/service_manager.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
+#include "services/service_manager/public/mojom/service_manager.mojom.h"
namespace service_manager {
@@ -49,19 +49,18 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT Connector {
// Allows caller to specify a callback to bind requests for |interface_name|
// from |service_name| locally, rather than passing the request through the
// Service Manager.
- void OverrideBinderForTesting(const std::string& service_name,
+ void OverrideBinderForTesting(const service_manager::Identity& identity,
const std::string& interface_name,
const Binder& binder) {
- connector_->OverrideBinderForTesting(service_name, interface_name,
- binder);
+ connector_->OverrideBinderForTesting(identity, interface_name, binder);
}
- bool HasBinderOverride(const std::string& service_name,
+ bool HasBinderOverride(const service_manager::Identity& identity,
const std::string& interface_name) {
- return connector_->HasBinderOverride(service_name, interface_name);
+ return connector_->HasBinderOverride(identity, interface_name);
}
- void ClearBinderOverride(const std::string& service_name,
+ void ClearBinderOverride(const service_manager::Identity& identity,
const std::string& interface_name) {
- connector_->ClearBinderOverride(service_name, interface_name);
+ connector_->ClearBinderOverride(identity, interface_name);
}
void ClearBinderOverrides() { connector_->ClearBinderOverrides(); }
@@ -149,12 +148,12 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT Connector {
void OnConnectionError();
- void OverrideBinderForTesting(const std::string& service_name,
+ void OverrideBinderForTesting(const service_manager::Identity& identity,
const std::string& interface_name,
const TestApi::Binder& binder);
- bool HasBinderOverride(const std::string& service_name,
+ bool HasBinderOverride(const service_manager::Identity& identity,
const std::string& interface_name);
- void ClearBinderOverride(const std::string& service_name,
+ void ClearBinderOverride(const service_manager::Identity& identity,
const std::string& interface_name);
void ClearBinderOverrides();
void SetStartServiceCallback(const StartServiceCallback& callback);
@@ -171,7 +170,8 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT Connector {
SEQUENCE_CHECKER(sequence_checker_);
- std::map<std::string, BinderOverrideMap> local_binder_overrides_;
+ std::map<service_manager::Identity, BinderOverrideMap>
+ local_binder_overrides_;
StartServiceCallback start_service_callback_;
base::WeakPtrFactory<Connector> weak_factory_;
diff --git a/chromium/services/service_manager/public/cpp/identity.cc b/chromium/services/service_manager/public/cpp/identity.cc
index 13db9b0e69e..50fb37211fe 100644
--- a/chromium/services/service_manager/public/cpp/identity.cc
+++ b/chromium/services/service_manager/public/cpp/identity.cc
@@ -5,7 +5,7 @@
#include "services/service_manager/public/cpp/identity.h"
#include "base/guid.h"
-#include "services/service_manager/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/mojom/constants.mojom.h"
namespace service_manager {
diff --git a/chromium/services/service_manager/public/cpp/identity.typemap b/chromium/services/service_manager/public/cpp/identity.typemap
index 45b931a8f1e..3d4cc7ce3ba 100644
--- a/chromium/services/service_manager/public/cpp/identity.typemap
+++ b/chromium/services/service_manager/public/cpp/identity.typemap
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom = "//services/service_manager/public/interfaces/connector.mojom"
+mojom = "//services/service_manager/public/mojom/connector.mojom"
public_headers = [ "//services/service_manager/public/cpp/identity.h" ]
traits_headers =
- [ "//services/service_manager/public/cpp/identity_struct_traits.h" ]
+ [ "//services/service_manager/public/cpp/identity_mojom_traits.h" ]
public_deps = [
"//services/service_manager/public/cpp:cpp_types",
]
diff --git a/chromium/services/service_manager/public/cpp/identity_struct_traits.h b/chromium/services/service_manager/public/cpp/identity_mojom_traits.h
index fa971352659..64c4c68a739 100644
--- a/chromium/services/service_manager/public/cpp/identity_struct_traits.h
+++ b/chromium/services/service_manager/public/cpp/identity_mojom_traits.h
@@ -6,13 +6,12 @@
#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_IDENTITY_STRUCT_TRAITS_H_
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/interfaces_export.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
namespace mojo {
template <>
-struct SERVICE_MANAGER_MOJOM_EXPORT
+struct COMPONENT_EXPORT(SERVICE_MANAGER_MOJOM)
StructTraits<service_manager::mojom::IdentityDataView,
service_manager::Identity> {
static const std::string& name(const service_manager::Identity& identity) {
diff --git a/chromium/services/service_manager/public/cpp/interface_provider.cc b/chromium/services/service_manager/public/cpp/interface_provider.cc
index 2d4e273ec81..b04f9d73dd3 100644
--- a/chromium/services/service_manager/public/cpp/interface_provider.cc
+++ b/chromium/services/service_manager/public/cpp/interface_provider.cc
@@ -53,7 +53,7 @@ base::WeakPtr<InterfaceProvider> InterfaceProvider::GetWeakPtr() {
return weak_factory_.GetWeakPtr();
}
-void InterfaceProvider::GetInterface(
+void InterfaceProvider::GetInterfaceByName(
const std::string& name,
mojo::ScopedMessagePipeHandle request_handle) {
// Local binders can be registered via TestApi.
diff --git a/chromium/services/service_manager/public/cpp/interface_provider.h b/chromium/services/service_manager/public/cpp/interface_provider.h
index a7e9996ecf3..5cc86da88d8 100644
--- a/chromium/services/service_manager/public/cpp/interface_provider.h
+++ b/chromium/services/service_manager/public/cpp/interface_provider.h
@@ -7,7 +7,7 @@
#include "base/bind.h"
#include "services/service_manager/public/cpp/export.h"
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
+#include "services/service_manager/public/mojom/interface_provider.mojom.h"
namespace service_manager {
@@ -81,22 +81,20 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT InterfaceProvider {
base::WeakPtr<InterfaceProvider> GetWeakPtr();
- // Binds |ptr| to an implementation of Interface in the remote application.
- // |ptr| can immediately be used to start sending requests to the remote
- // interface.
- template <typename Interface>
- void GetInterface(mojo::InterfacePtr<Interface>* ptr) {
- mojo::MessagePipe pipe;
- ptr->Bind(mojo::InterfacePtrInfo<Interface>(std::move(pipe.handle0), 0u));
-
- GetInterface(Interface::Name_, std::move(pipe.handle1));
+ // Binds a passed in interface pointer to an implementation of the interface
+ // in the remote application using MakeRequest. The interface pointer can
+ // immediately be used to start sending requests to the remote interface.
+ // Uses templated parameters in order to work with weak interfaces in blink.
+ template <typename... Args>
+ void GetInterface(Args&&... args) {
+ GetInterface(MakeRequest(std::forward<Args>(args)...));
}
template <typename Interface>
void GetInterface(mojo::InterfaceRequest<Interface> request) {
- GetInterface(Interface::Name_, std::move(request.PassMessagePipe()));
+ GetInterfaceByName(Interface::Name_, std::move(request.PassMessagePipe()));
}
- void GetInterface(const std::string& name,
- mojo::ScopedMessagePipeHandle request_handle);
+ void GetInterfaceByName(const std::string& name,
+ mojo::ScopedMessagePipeHandle request_handle);
// Returns a callback to GetInterface<Interface>(). This can be passed to
// BinderRegistry::AddInterface() to forward requests.
diff --git a/chromium/services/service_manager/public/cpp/interface_provider_spec.h b/chromium/services/service_manager/public/cpp/interface_provider_spec.h
index 30907018141..1db349ea44b 100644
--- a/chromium/services/service_manager/public/cpp/interface_provider_spec.h
+++ b/chromium/services/service_manager/public/cpp/interface_provider_spec.h
@@ -21,7 +21,7 @@ using InterfaceSet = std::set<std::string>;
using Name = std::string;
// See comments in
-// services/service_manager/public/interfaces/interface_provider_spec.mojom for
+// services/service_manager/public/mojom/interface_provider_spec.mojom for
// a description of InterfaceProviderSpec.
struct SERVICE_MANAGER_PUBLIC_CPP_TYPES_EXPORT InterfaceProviderSpec {
InterfaceProviderSpec();
diff --git a/chromium/services/service_manager/public/cpp/interface_provider_spec.typemap b/chromium/services/service_manager/public/cpp/interface_provider_spec.typemap
index ce418a0412d..72f0278bb34 100644
--- a/chromium/services/service_manager/public/cpp/interface_provider_spec.typemap
+++ b/chromium/services/service_manager/public/cpp/interface_provider_spec.typemap
@@ -2,11 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-mojom =
- "//services/service_manager/public/interfaces/interface_provider_spec.mojom"
+mojom = "//services/service_manager/public/mojom/interface_provider_spec.mojom"
public_headers =
[ "//services/service_manager/public/cpp/interface_provider_spec.h" ]
-traits_headers = [ "//services/service_manager/public/cpp/interface_provider_spec_struct_traits.h" ]
+traits_headers = [ "//services/service_manager/public/cpp/interface_provider_spec_mojom_traits.h" ]
public_deps = [
"//services/service_manager/public/cpp:cpp_types",
]
diff --git a/chromium/services/service_manager/public/cpp/interface_provider_spec_struct_traits.h b/chromium/services/service_manager/public/cpp/interface_provider_spec_mojom_traits.h
index 5f18346fabf..62e50e67641 100644
--- a/chromium/services/service_manager/public/cpp/interface_provider_spec_struct_traits.h
+++ b/chromium/services/service_manager/public/cpp/interface_provider_spec_mojom_traits.h
@@ -6,22 +6,21 @@
#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_INTERFACE_PROVIDER_SPEC_STRUCT_TRAITS_H_
#include "services/service_manager/public/cpp/interface_provider_spec.h"
-#include "services/service_manager/public/interfaces/interface_provider_spec.mojom.h"
-#include "services/service_manager/public/interfaces/interfaces_export.h"
+#include "services/service_manager/public/mojom/interface_provider_spec.mojom.h"
namespace mojo {
template <>
-struct SERVICE_MANAGER_MOJOM_EXPORT
+struct COMPONENT_EXPORT(SERVICE_MANAGER_MOJOM)
StructTraits<service_manager::mojom::InterfaceProviderSpec::DataView,
service_manager::InterfaceProviderSpec> {
static const std::map<service_manager::Capability,
service_manager::InterfaceSet>&
- provides(const service_manager::InterfaceProviderSpec& spec) {
+ provides(const service_manager::InterfaceProviderSpec& spec) {
return spec.provides;
}
static const std::map<service_manager::Name, service_manager::CapabilitySet>&
- requires(const service_manager::InterfaceProviderSpec& spec) {
+ requires(const service_manager::InterfaceProviderSpec& spec) {
return spec.requires;
}
static bool Read(service_manager::mojom::InterfaceProviderSpecDataView data,
@@ -32,7 +31,7 @@ struct SERVICE_MANAGER_MOJOM_EXPORT
};
template <>
-struct SERVICE_MANAGER_MOJOM_EXPORT
+struct COMPONENT_EXPORT(SERVICE_MANAGER_MOJOM)
StructTraits<service_manager::mojom::InterfaceSet::DataView,
service_manager::InterfaceSet> {
static std::vector<std::string> interfaces(
@@ -57,7 +56,7 @@ struct SERVICE_MANAGER_MOJOM_EXPORT
};
template <>
-struct SERVICE_MANAGER_MOJOM_EXPORT
+struct COMPONENT_EXPORT(SERVICE_MANAGER_MOJOM)
StructTraits<service_manager::mojom::CapabilitySet::DataView,
service_manager::CapabilitySet> {
static std::vector<std::string> capabilities(
diff --git a/chromium/services/service_manager/public/cpp/service_context.cc b/chromium/services/service_manager/public/cpp/service_context.cc
index 60758b2ff7d..87353815255 100644
--- a/chromium/services/service_manager/public/cpp/service_context.cc
+++ b/chromium/services/service_manager/public/cpp/service_context.cc
@@ -99,6 +99,11 @@ void ServiceContext::RequestQuit() {
service_control_->RequestQuit();
}
+base::RepeatingClosure ServiceContext::CreateQuitClosure() {
+ return base::BindRepeating(&ServiceContext::RequestQuit,
+ weak_factory_.GetWeakPtr());
+}
+
void ServiceContext::DisconnectFromServiceManager() {
if (binding_.is_bound())
binding_.Close();
diff --git a/chromium/services/service_manager/public/cpp/service_context.h b/chromium/services/service_manager/public/cpp/service_context.h
index 31ddd95c88a..ba76060776c 100644
--- a/chromium/services/service_manager/public/cpp/service_context.h
+++ b/chromium/services/service_manager/public/cpp/service_context.h
@@ -17,9 +17,9 @@
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/export.h"
#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
-#include "services/service_manager/public/interfaces/service_control.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
+#include "services/service_manager/public/mojom/service_control.mojom.h"
namespace service_manager {
@@ -74,8 +74,11 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT ServiceContext : public mojom::Service {
// NOTE: It is acceptable for |closure| to delete this ServiceContext.
void SetQuitClosure(const base::Closure& closure);
- // Informs the Service Manager that this instance is ready to terminate. If
- // the Service Manager has any outstanding connection requests for this
+ // Returns a closure that, when run, informs the Service Manager that this
+ // instance is ready to terminate. If it has already terminated, then the
+ // closure does nothing.
+ //
+ // If the Service Manager has any outstanding connection requests for this
// instance, the request is ignored; the instance will eventually receive
// the pending request(s) and can then appropriately decide whether or not
// it still wants to quit.
@@ -83,7 +86,7 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT ServiceContext : public mojom::Service {
// If the request is granted, the Service Manager will soon sever the
// connection to this ServiceContext, and
// Service::OnServiceManagerConnectionLost() will be invoked at that time.
- void RequestQuit();
+ base::RepeatingClosure CreateQuitClosure();
// Immediately severs the connection to the Service Manager.
//
@@ -123,6 +126,8 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT ServiceContext : public mojom::Service {
private:
friend class service_manager::Service;
+ void RequestQuit();
+
// mojom::Service:
void OnStart(const Identity& info, OnStartCallback callback) override;
void OnBindInterface(const BindSourceInfo& source_info,
diff --git a/chromium/services/service_manager/public/cpp/service_context_ref.cc b/chromium/services/service_manager/public/cpp/service_context_ref.cc
index 226ba1128cc..30cb7cd7092 100644
--- a/chromium/services/service_manager/public/cpp/service_context_ref.cc
+++ b/chromium/services/service_manager/public/cpp/service_context_ref.cc
@@ -59,8 +59,8 @@ class ServiceContextRefImpl : public ServiceContextRef {
};
ServiceContextRefFactory::ServiceContextRefFactory(
- const base::Closure& quit_closure)
- : quit_closure_(quit_closure), weak_factory_(this) {
+ base::RepeatingClosure quit_closure)
+ : quit_closure_(std::move(quit_closure)), weak_factory_(this) {
DCHECK(!quit_closure_.is_null());
}
diff --git a/chromium/services/service_manager/public/cpp/service_context_ref.h b/chromium/services/service_manager/public/cpp/service_context_ref.h
index 9175b183159..1126a0e1864 100644
--- a/chromium/services/service_manager/public/cpp/service_context_ref.h
+++ b/chromium/services/service_manager/public/cpp/service_context_ref.h
@@ -34,7 +34,7 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT ServiceContextRef {
class SERVICE_MANAGER_PUBLIC_CPP_EXPORT ServiceContextRefFactory {
public:
// |quit_closure| is called whenever the last ref is destroyed.
- explicit ServiceContextRefFactory(const base::Closure& quit_closure);
+ explicit ServiceContextRefFactory(base::RepeatingClosure quit_closure);
~ServiceContextRefFactory();
std::unique_ptr<ServiceContextRef> CreateRef();
@@ -48,7 +48,7 @@ class SERVICE_MANAGER_PUBLIC_CPP_EXPORT ServiceContextRefFactory {
void AddRef();
void Release();
- const base::Closure quit_closure_;
+ base::RepeatingClosure quit_closure_;
int ref_count_ = 0;
base::WeakPtrFactory<ServiceContextRefFactory> weak_factory_;
diff --git a/chromium/services/service_manager/public/cpp/standalone_service/BUILD.gn b/chromium/services/service_manager/public/cpp/standalone_service/BUILD.gn
index a168eec52ce..8acd6ccefc0 100644
--- a/chromium/services/service_manager/public/cpp/standalone_service/BUILD.gn
+++ b/chromium/services/service_manager/public/cpp/standalone_service/BUILD.gn
@@ -21,7 +21,7 @@ source_set("standalone_service") {
public_deps = [
"//base",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
if (is_linux && !is_android) {
diff --git a/chromium/services/service_manager/public/cpp/standalone_service/main.cc b/chromium/services/service_manager/public/cpp/standalone_service/main.cc
index 41614888db5..61c3b47d5ef 100644
--- a/chromium/services/service_manager/public/cpp/standalone_service/main.cc
+++ b/chromium/services/service_manager/public/cpp/standalone_service/main.cc
@@ -4,8 +4,10 @@
#include "services/service_manager/public/c/main.h"
#include "base/at_exit.h"
+#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/debug/stack_trace.h"
+#include "base/feature_list.h"
#include "base/i18n/icu_util.h"
#include "base/logging.h"
#include "base/macros.h"
@@ -13,7 +15,7 @@
#include "base/task_scheduler/task_scheduler.h"
#include "services/service_manager/public/cpp/standalone_service/standalone_service.h"
#include "services/service_manager/public/cpp/standalone_service/switches.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
#include "services/service_manager/runner/init.h"
#if defined(OS_MACOSX)
@@ -52,6 +54,11 @@ int main(int argc, char** argv) {
base::debug::EnableInProcessStackDumping();
#endif
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ base::FeatureList::InitializeInstance(
+ command_line->GetSwitchValueASCII(switches::kEnableFeatures),
+ command_line->GetSwitchValueASCII(switches::kDisableFeatures));
+
service_manager::WaitForDebuggerIfNecessary();
service_manager::RunStandaloneService(base::Bind(&RunServiceMain));
diff --git a/chromium/services/service_manager/public/cpp/standalone_service/standalone_service.h b/chromium/services/service_manager/public/cpp/standalone_service/standalone_service.h
index 2cccd120842..890626782fd 100644
--- a/chromium/services/service_manager/public/cpp/standalone_service/standalone_service.h
+++ b/chromium/services/service_manager/public/cpp/standalone_service/standalone_service.h
@@ -6,7 +6,7 @@
#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_STANDALONE_SERVICE_H_
#include "base/callback.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
namespace service_manager {
diff --git a/chromium/services/service_manager/public/cpp/standalone_service/switches.h b/chromium/services/service_manager/public/cpp/standalone_service/switches.h
index b6f85087447..67d573fcd0b 100644
--- a/chromium/services/service_manager/public/cpp/standalone_service/switches.h
+++ b/chromium/services/service_manager/public/cpp/standalone_service/switches.h
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_SWITCHES_H_
+#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_SWITCHES_H_
+
namespace service_manager {
namespace switches {
@@ -9,3 +12,5 @@ extern const char kIcuDataDir[];
} // namespace switches
} // namespace service_manager
+
+#endif // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_STANDALONE_SERVICE_SWITCHES_H_
diff --git a/chromium/services/service_manager/public/cpp/test/BUILD.gn b/chromium/services/service_manager/public/cpp/test/BUILD.gn
index 3d231b21e07..3473ac1a58f 100644
--- a/chromium/services/service_manager/public/cpp/test/BUILD.gn
+++ b/chromium/services/service_manager/public/cpp/test/BUILD.gn
@@ -56,7 +56,7 @@ source_set("test_support") {
public_deps = [
"//base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
deps = [
diff --git a/chromium/services/service_manager/public/java/BUILD.gn b/chromium/services/service_manager/public/java/BUILD.gn
index a1af30194ea..cdf05c65b49 100644
--- a/chromium/services/service_manager/public/java/BUILD.gn
+++ b/chromium/services/service_manager/public/java/BUILD.gn
@@ -14,6 +14,6 @@ android_library("service_manager_java") {
"//base:base_java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
- "//services/service_manager/public/interfaces:interfaces_java",
+ "//services/service_manager/public/mojom:mojom_java",
]
}
diff --git a/chromium/services/service_manager/public/interfaces/BUILD.gn b/chromium/services/service_manager/public/mojom/BUILD.gn
index a98a02dd3b7..ac7c34dae5d 100644
--- a/chromium/services/service_manager/public/interfaces/BUILD.gn
+++ b/chromium/services/service_manager/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom_component("interfaces") {
+mojom_component("mojom") {
output_prefix = "service_manager_mojom"
macro_prefix = "SERVICE_MANAGER_MOJOM"
diff --git a/chromium/services/resource_coordinator/public/interfaces/tracing/OWNERS b/chromium/services/service_manager/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/resource_coordinator/public/interfaces/tracing/OWNERS
+++ b/chromium/services/service_manager/public/mojom/OWNERS
diff --git a/chromium/services/service_manager/public/interfaces/connector.mojom b/chromium/services/service_manager/public/mojom/connector.mojom
index ab256f44820..6acdae586c9 100644
--- a/chromium/services/service_manager/public/interfaces/connector.mojom
+++ b/chromium/services/service_manager/public/mojom/connector.mojom
@@ -4,8 +4,8 @@
module service_manager.mojom;
-import "services/service_manager/public/interfaces/constants.mojom";
-import "services/service_manager/public/interfaces/interface_provider.mojom";
+import "services/service_manager/public/mojom/constants.mojom";
+import "services/service_manager/public/mojom/interface_provider.mojom";
// TODO(beng): Evalute the utility of this enum. There are some inconsistencies
// in its use with BindInterface/StartService.
diff --git a/chromium/services/service_manager/public/interfaces/constants.mojom b/chromium/services/service_manager/public/mojom/constants.mojom
index 5f540fc4143..5f540fc4143 100644
--- a/chromium/services/service_manager/public/interfaces/constants.mojom
+++ b/chromium/services/service_manager/public/mojom/constants.mojom
diff --git a/chromium/services/service_manager/public/interfaces/interface_provider.mojom b/chromium/services/service_manager/public/mojom/interface_provider.mojom
index 44b67c9505e..44b67c9505e 100644
--- a/chromium/services/service_manager/public/interfaces/interface_provider.mojom
+++ b/chromium/services/service_manager/public/mojom/interface_provider.mojom
diff --git a/chromium/services/service_manager/public/interfaces/interface_provider_spec.mojom b/chromium/services/service_manager/public/mojom/interface_provider_spec.mojom
index f17d55b3cfb..f17d55b3cfb 100644
--- a/chromium/services/service_manager/public/interfaces/interface_provider_spec.mojom
+++ b/chromium/services/service_manager/public/mojom/interface_provider_spec.mojom
diff --git a/chromium/services/service_manager/public/interfaces/service.mojom b/chromium/services/service_manager/public/mojom/service.mojom
index f4109ba4511..56f2201252f 100644
--- a/chromium/services/service_manager/public/interfaces/service.mojom
+++ b/chromium/services/service_manager/public/mojom/service.mojom
@@ -4,10 +4,10 @@
module service_manager.mojom;
-import "services/service_manager/public/interfaces/connector.mojom";
-import "services/service_manager/public/interfaces/interface_provider.mojom";
-import "services/service_manager/public/interfaces/interface_provider_spec.mojom";
-import "services/service_manager/public/interfaces/service_control.mojom";
+import "services/service_manager/public/mojom/connector.mojom";
+import "services/service_manager/public/mojom/interface_provider.mojom";
+import "services/service_manager/public/mojom/interface_provider_spec.mojom";
+import "services/service_manager/public/mojom/service_control.mojom";
// Metadata describing an instance of a service that originated a call to
// BindInterface().
diff --git a/chromium/services/service_manager/public/interfaces/service_control.mojom b/chromium/services/service_manager/public/mojom/service_control.mojom
index f80b81c17b9..f80b81c17b9 100644
--- a/chromium/services/service_manager/public/interfaces/service_control.mojom
+++ b/chromium/services/service_manager/public/mojom/service_control.mojom
diff --git a/chromium/services/service_manager/public/interfaces/service_factory.mojom b/chromium/services/service_manager/public/mojom/service_factory.mojom
index 745df7b01d6..a62e1aebe9b 100644
--- a/chromium/services/service_manager/public/interfaces/service_factory.mojom
+++ b/chromium/services/service_manager/public/mojom/service_factory.mojom
@@ -4,8 +4,8 @@
module service_manager.mojom;
-import "services/service_manager/public/interfaces/connector.mojom";
-import "services/service_manager/public/interfaces/service.mojom";
+import "services/service_manager/public/mojom/connector.mojom";
+import "services/service_manager/public/mojom/service.mojom";
// Implemented by a package containing multiple services identified by
// unique names.
diff --git a/chromium/services/service_manager/public/interfaces/service_manager.mojom b/chromium/services/service_manager/public/mojom/service_manager.mojom
index de06ed7d383..1097b69b1fc 100644
--- a/chromium/services/service_manager/public/interfaces/service_manager.mojom
+++ b/chromium/services/service_manager/public/mojom/service_manager.mojom
@@ -4,7 +4,7 @@
module service_manager.mojom;
-import "services/service_manager/public/interfaces/connector.mojom";
+import "services/service_manager/public/mojom/connector.mojom";
struct RunningServiceInfo {
uint32 id;
diff --git a/chromium/services/service_manager/public/service_manifest.gni b/chromium/services/service_manager/public/service_manifest.gni
index 96eb2899591..1a55cde7692 100644
--- a/chromium/services/service_manager/public/service_manifest.gni
+++ b/chromium/services/service_manager/public/service_manifest.gni
@@ -106,7 +106,7 @@ template("service_manifest") {
args += [ "--pretty" ]
}
- if (defined(invoker.overlays)) {
+ if (defined(invoker.overlays) && invoker.overlays != []) {
args += [ "--overlays" ]
foreach(manifest_target, invoker.overlays) {
manifest_target_dir = get_label_info(manifest_target, "target_gen_dir")
diff --git a/chromium/services/service_manager/public/tools/manifest/manifest_collator.py b/chromium/services/service_manager/public/tools/manifest/manifest_collator.py
index be305618291..42cef4905b4 100755
--- a/chromium/services/service_manager/public/tools/manifest/manifest_collator.py
+++ b/chromium/services/service_manager/public/tools/manifest/manifest_collator.py
@@ -18,6 +18,12 @@ _MANIFEST_OVERLAY_OVERRIDE_KEYS = [
"display_name",
]
+# Keys which are merged with content from manifest overlays
+_MANIFEST_OVERLAY_MERGE_KEYS = [
+ "interface_provider_specs",
+ "required_files",
+]
+
eater_relative = "../../../../../../tools/json_comment_eater"
eater_relative = os.path.join(os.path.abspath(__file__), eater_relative)
sys.path.insert(0, os.path.normpath(eater_relative))
@@ -53,8 +59,10 @@ def MergeDicts(left, right):
def MergeManifestOverlay(manifest, overlay):
- MergeDicts(manifest["interface_provider_specs"],
- overlay["interface_provider_specs"])
+
+ for key in _MANIFEST_OVERLAY_MERGE_KEYS:
+ if key in overlay:
+ MergeDicts(manifest[key], overlay[key])
if "services" in overlay:
if "services" not in manifest:
diff --git a/chromium/services/service_manager/runner/common/BUILD.gn b/chromium/services/service_manager/runner/common/BUILD.gn
index c4ba43a1551..98043a0550e 100644
--- a/chromium/services/service_manager/runner/common/BUILD.gn
+++ b/chromium/services/service_manager/runner/common/BUILD.gn
@@ -18,6 +18,6 @@ source_set("common") {
public_deps = [
"//mojo/edk/system",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
diff --git a/chromium/services/service_manager/runner/common/client_util.h b/chromium/services/service_manager/runner/common/client_util.h
index 2188dd9c0e0..dfcf4c00b96 100644
--- a/chromium/services/service_manager/runner/common/client_util.h
+++ b/chromium/services/service_manager/runner/common/client_util.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_SERVICE_MANAGER_RUNNER_COMMON_CLIENT_UTIL_H_
#define SERVICES_SERVICE_MANAGER_RUNNER_COMMON_CLIENT_UTIL_H_
-#include "services/service_manager/public/interfaces/service.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
namespace base {
class CommandLine;
diff --git a/chromium/services/service_manager/runner/host/service_process_launcher.h b/chromium/services/service_manager/runner/host/service_process_launcher.h
index 3a02b999597..cedfc2371d9 100644
--- a/chromium/services/service_manager/runner/host/service_process_launcher.h
+++ b/chromium/services/service_manager/runner/host/service_process_launcher.h
@@ -16,7 +16,7 @@
#include "base/synchronization/waitable_event.h"
#include "mojo/edk/embedder/outgoing_broker_client_invitation.h"
#include "mojo/edk/embedder/platform_channel_pair.h"
-#include "services/service_manager/public/interfaces/service_factory.mojom.h"
+#include "services/service_manager/public/mojom/service_factory.mojom.h"
#include "services/service_manager/runner/host/service_process_launcher_delegate.h"
#include "services/service_manager/sandbox/sandbox_type.h"
diff --git a/chromium/services/service_manager/sandbox/linux/bpf_broker_policy_linux.cc b/chromium/services/service_manager/sandbox/linux/bpf_broker_policy_linux.cc
index a6d8eea78d1..687ac789d77 100644
--- a/chromium/services/service_manager/sandbox/linux/bpf_broker_policy_linux.cc
+++ b/chromium/services/service_manager/sandbox/linux/bpf_broker_policy_linux.cc
@@ -117,6 +117,7 @@ ResultExpr BrokerProcessPolicy::EvaluateSyscall(int sysno) const {
allowed_command_set_.test(sandbox::syscall_broker::COMMAND_UNLINK)) {
return Allow();
}
+ break;
#endif
#if defined(__NR_unlinkat)
case __NR_unlinkat:
@@ -125,6 +126,7 @@ ResultExpr BrokerProcessPolicy::EvaluateSyscall(int sysno) const {
allowed_command_set_.test(sandbox::syscall_broker::COMMAND_UNLINK)) {
return Allow();
}
+ break;
#endif
default:
break;
diff --git a/chromium/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc b/chromium/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
index bc16952c089..d683aacc76f 100644
--- a/chromium/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
+++ b/chromium/services/service_manager/sandbox/linux/bpf_gpu_policy_linux.cc
@@ -61,7 +61,20 @@ ResultExpr GpuProcessPolicy::EvaluateSyscall(int sysno) const {
case __NR_open:
#endif // !defined(__aarch64__)
case __NR_faccessat:
- case __NR_openat: {
+ case __NR_openat:
+#if defined(__NR_stat)
+ case __NR_stat:
+#endif
+#if defined(__NR_stat64)
+ case __NR_stat64:
+#endif
+#if defined(__NR_fstatat)
+ case __NR_fstatat:
+#endif
+#if defined(__NR_newfstatat)
+ case __NR_newfstatat:
+#endif
+ {
auto* broker_process = SandboxLinux::GetInstance()->broker_process();
DCHECK(broker_process);
return Trap(BrokerProcess::SIGSYS_Handler, broker_process);
diff --git a/chromium/services/service_manager/sandbox/linux/sandbox_linux.cc b/chromium/services/service_manager/sandbox/linux/sandbox_linux.cc
index 37d11e4bcef..76476b21141 100644
--- a/chromium/services/service_manager/sandbox/linux/sandbox_linux.cc
+++ b/chromium/services/service_manager/sandbox/linux/sandbox_linux.cc
@@ -369,11 +369,16 @@ bool SandboxLinux::InitializeSandbox(SandboxType sandbox_type,
sandbox_failure_fatal = switch_value != "no";
}
- if (sandbox_failure_fatal)
- LOG(FATAL) << error_message;
-
- LOG(ERROR) << error_message;
- return false;
+ if (sandbox_failure_fatal) {
+ error_message += " Try waiting for /proc to be updated.";
+ LOG(ERROR) << error_message;
+ // This will return if /proc/self eventually reports this process is
+ // single-threaded, or crash if it does not after a number of retries.
+ sandbox::ThreadHelpers::AssertSingleThreaded();
+ } else {
+ LOG(ERROR) << error_message;
+ return false;
+ }
}
// Only one thread is running, pre-initialize if not already done.
diff --git a/chromium/services/service_manager/sandbox/linux/sandbox_linux.h b/chromium/services/service_manager/sandbox/linux/sandbox_linux.h
index 047048cb874..def5720692b 100644
--- a/chromium/services/service_manager/sandbox/linux/sandbox_linux.h
+++ b/chromium/services/service_manager/sandbox/linux/sandbox_linux.h
@@ -54,14 +54,13 @@ class SERVICE_MANAGER_SANDBOX_EXPORT SandboxLinux {
// sandbox host. See
// https://chromium.googlesource.com/chromium/src/+/master/docs/linux_sandbox_ipc.md
// This isn't the full list, values < 32 are reserved for methods called from
- // Skia.
+ // Skia, and values < 64 are reserved for libc_interceptor.cc.
enum LinuxSandboxIPCMethods {
- METHOD_GET_FALLBACK_FONT_FOR_CHAR = 32,
- METHOD_LOCALTIME = 33,
- DEPRECATED_METHOD_GET_CHILD_WITH_INODE = 34,
- METHOD_GET_STYLE_FOR_STRIKE = 35,
- METHOD_MAKE_SHARED_MEMORY_SEGMENT = 36,
- METHOD_MATCH_WITH_FALLBACK = 37,
+ METHOD_GET_FALLBACK_FONT_FOR_CHAR = 64,
+ DEPRECATED_METHOD_GET_CHILD_WITH_INODE,
+ METHOD_GET_STYLE_FOR_STRIKE,
+ METHOD_MAKE_SHARED_MEMORY_SEGMENT,
+ METHOD_MATCH_WITH_FALLBACK,
};
// These form a bitmask which describes the conditions of the Linux sandbox.
diff --git a/chromium/services/service_manager/sandbox/mac/cdm.sb b/chromium/services/service_manager/sandbox/mac/cdm.sb
index d22fe31f6b3..a7ba200db8b 100644
--- a/chromium/services/service_manager/sandbox/mac/cdm.sb
+++ b/chromium/services/service_manager/sandbox/mac/cdm.sb
@@ -10,3 +10,6 @@
; Allow to read framework and CDM resources files for CDM host verification
(define bundle-version-path "BUNDLE_VERSION_PATH")
(allow file-read* (subpath (param bundle-version-path)))
+
+; mach IPC
+(allow mach-lookup (global-name "com.apple.windowserver.active"))
diff --git a/chromium/services/service_manager/sandbox/mac/common_v2.sb b/chromium/services/service_manager/sandbox/mac/common_v2.sb
index d33adf36e7a..17ce998d670 100644
--- a/chromium/services/service_manager/sandbox/mac/common_v2.sb
+++ b/chromium/services/service_manager/sandbox/mac/common_v2.sb
@@ -110,7 +110,7 @@
(path "/dev/urandom"))
(if (= os-version 1013)
- (begin (allow file-read-data (subpath "/private/var/db/timezone"))
+ (begin (allow file-read* (subpath "/private/var/db/timezone"))
(allow file-read-data (subpath "/usr/share/zoneinfo.default"))))
(if (< os-version 1013)
diff --git a/chromium/services/service_manager/sandbox/mac/gpu_v2.sb b/chromium/services/service_manager/sandbox/mac/gpu_v2.sb
index 593b49d3547..2fa2a097597 100644
--- a/chromium/services/service_manager/sandbox/mac/gpu_v2.sb
+++ b/chromium/services/service_manager/sandbox/mac/gpu_v2.sb
@@ -6,7 +6,10 @@
; Allow communication between the GPU process and the UI server.
(allow mach-lookup
+ (global-name "com.apple.CoreServices.coreservicesd")
+ (global-name "com.apple.coreservices.launchservicesd")
(global-name "com.apple.cvmsServ")
+ (global-name "com.apple.system.notification_center")
(global-name "com.apple.tsm.uiserver")
(global-name "com.apple.windowserver.active"))
@@ -23,6 +26,9 @@
(iokit-user-client-class "IOSurfaceSendRight"))
(iokit-user-client-class "RootDomainUserClient")
+(allow ipc-posix-shm-read-data
+ (ipc-posix-name "apple.shm.notification_center"))
+
; https://crbug.com/515280
(if (>= os-version 1011)
(allow file-read* (subpath "/System/Library/Extensions")))
diff --git a/chromium/services/service_manager/sandbox/mac/ppapi_v2.sb b/chromium/services/service_manager/sandbox/mac/ppapi_v2.sb
index 4328eff8db4..8da26ef0ca9 100644
--- a/chromium/services/service_manager/sandbox/mac/ppapi_v2.sb
+++ b/chromium/services/service_manager/sandbox/mac/ppapi_v2.sb
@@ -4,6 +4,13 @@
; --- The contents of common.sb implicitly included here. ---
+; Params specific to ppapi.
+(define ppapi-plugin-0 "PPAPI_PATH_0")
+(define ppapi-plugin-1 "PPAPI_PATH_1")
+(define ppapi-plugin-2 "PPAPI_PATH_2")
+(define ppapi-plugin-3 "PPAPI_PATH_3")
+(define ppapi-plugin-4 "PPAPI_PATH_4")
+
; Needed for Fonts.
(allow-font-access)
@@ -19,3 +26,15 @@
(allow file-read-data
(subpath "/System/Library/CoreServices/SystemAppearance.bundle")
(path "/System/Library/Colors/System.clr/System.clr"))
+
+; Allow the ppapi plugin binaries to be loaded.
+(if (param-defined? ppapi-plugin-0)
+ (allow file-read-data (subpath (param ppapi-plugin-0))))
+(if (param-defined? ppapi-plugin-1)
+ (allow file-read-data (subpath (param ppapi-plugin-1))))
+(if (param-defined? ppapi-plugin-2)
+ (allow file-read-data (subpath (param ppapi-plugin-2))))
+(if (param-defined? ppapi-plugin-3)
+ (allow file-read-data (subpath (param ppapi-plugin-3))))
+(if (param-defined? ppapi-plugin-4)
+ (allow file-read-data (subpath (param ppapi-plugin-4))))
diff --git a/chromium/services/service_manager/sandbox/mac/renderer.sb b/chromium/services/service_manager/sandbox/mac/renderer.sb
index 138d245766b..09f142e19c2 100644
--- a/chromium/services/service_manager/sandbox/mac/renderer.sb
+++ b/chromium/services/service_manager/sandbox/mac/renderer.sb
@@ -37,7 +37,7 @@
; https://crbug.com/754280
(if (param-true? macos-1013)
- (begin (allow file-read-metadata (path "/private/var/db/timezone/zoneinfo"))
+ (begin (allow file-read* (subpath "/private/var/db/timezone"))
(allow file-read-data (subpath "/usr/share/zoneinfo.default")))
(allow file-read-data (subpath "/usr/share/zoneinfo")))
diff --git a/chromium/services/service_manager/sandbox/sandbox_delegate.h b/chromium/services/service_manager/sandbox/sandbox_delegate.h
index 299e4350c7c..3a15981c7c2 100644
--- a/chromium/services/service_manager/sandbox/sandbox_delegate.h
+++ b/chromium/services/service_manager/sandbox/sandbox_delegate.h
@@ -5,6 +5,8 @@
#ifndef SERVICES_SERVICE_MANAGER_SANDBOX_SANDBOX_DELEGATE_H_
#define SERVICES_SERVICE_MANAGER_SANDBOX_SANDBOX_DELEGATE_H_
+#include <string>
+
#include "base/process/process.h"
#include "build/build_config.h"
#include "services/service_manager/sandbox/sandbox_type.h"
@@ -28,6 +30,10 @@ class SandboxDelegate {
// AddPolicyForSandboxedProcess.
virtual bool DisableDefaultPolicy() = 0;
+ // Get the AppContainer ID for the sandbox. If this returns false then the
+ // AppContainer will not be enabled for the process.
+ virtual bool GetAppContainerId(std::string* appcontainer_id) = 0;
+
// Called right before spawning the process. Returns false on failure.
virtual bool PreSpawnTarget(sandbox::TargetPolicy* policy) = 0;
diff --git a/chromium/services/service_manager/sandbox/switches.cc b/chromium/services/service_manager/sandbox/switches.cc
index e63e78b0c09..2854d5025c7 100644
--- a/chromium/services/service_manager/sandbox/switches.cc
+++ b/chromium/services/service_manager/sandbox/switches.cc
@@ -67,6 +67,18 @@ const char kGpuSandboxFailuresFatal[] = "gpu-sandbox-failures-fatal";
// Allows third party modules to inject by disabling the BINARY_SIGNATURE
// mitigation policy on Win10+. Also has other effects in ELF.
const char kAllowThirdPartyModules[] = "allow-third-party-modules";
+
+// Add additional capabilities to the AppContainer sandbox on the GPU process.
+const char kAddGpuAppContainerCaps[] = "add-gpu-appcontainer-caps";
+
+// Disables AppContainer sandbox on the GPU process.
+const char kDisableGpuAppContainer[] = "disable-gpu-appcontainer";
+
+// Disables low-privilege AppContainer sandbox on the GPU process.
+const char kDisableGpuLpac[] = "disable-gpu-lpac";
+
+// Enables AppContainer sandbox on the GPU process.
+const char kEnableGpuAppContainer[] = "enable-gpu-appcontainer";
#endif
// Flags spied upon from other layers.
diff --git a/chromium/services/service_manager/sandbox/switches.h b/chromium/services/service_manager/sandbox/switches.h
index 999c2fd9790..1ee7f737f71 100644
--- a/chromium/services/service_manager/sandbox/switches.h
+++ b/chromium/services/service_manager/sandbox/switches.h
@@ -40,6 +40,10 @@ SERVICE_MANAGER_SANDBOX_EXPORT extern const char kGpuSandboxAllowSysVShm[];
SERVICE_MANAGER_SANDBOX_EXPORT extern const char kGpuSandboxFailuresFatal[];
#if defined(OS_WIN)
SERVICE_MANAGER_SANDBOX_EXPORT extern const char kAllowThirdPartyModules[];
+SERVICE_MANAGER_SANDBOX_EXPORT extern const char kAddGpuAppContainerCaps[];
+SERVICE_MANAGER_SANDBOX_EXPORT extern const char kDisableGpuAppContainer[];
+SERVICE_MANAGER_SANDBOX_EXPORT extern const char kDisableGpuLpac[];
+SERVICE_MANAGER_SANDBOX_EXPORT extern const char kEnableGpuAppContainer[];
#endif
// Flags spied upon from other layers.
diff --git a/chromium/services/service_manager/sandbox/win/sandbox_win.cc b/chromium/services/service_manager/sandbox/win/sandbox_win.cc
index 132a3e4dfd6..6c7356eacc4 100644
--- a/chromium/services/service_manager/sandbox/win/sandbox_win.cc
+++ b/chromium/services/service_manager/sandbox/win/sandbox_win.cc
@@ -8,11 +8,13 @@
#include <string>
#include <utility>
+#include <vector>
#include "base/command_line.h"
#include "base/debug/activity_tracker.h"
#include "base/debug/profiler.h"
#include "base/feature_list.h"
+#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/hash.h"
#include "base/logging.h"
@@ -23,15 +25,21 @@
#include "base/metrics/histogram_macros.h"
#include "base/path_service.h"
#include "base/process/launch.h"
+#include "base/sha1.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/trace_event/trace_event.h"
#include "base/win/iat_patch_function.h"
#include "base/win/scoped_handle.h"
#include "base/win/win_util.h"
#include "base/win/windows_version.h"
+#include "sandbox/win/src/app_container_profile.h"
#include "sandbox/win/src/process_mitigations.h"
#include "sandbox/win/src/sandbox.h"
#include "sandbox/win/src/sandbox_nt_util.h"
@@ -577,6 +585,55 @@ sandbox::ResultCode SetJobMemoryLimit(const base::CommandLine& cmd_line,
#endif
}
+// Generate a unique sandbox AC profile for the appcontainer based on the SHA1
+// hash of the appcontainer_id. This does not need to be secure so using SHA1
+// isn't a security concern.
+base::string16 GetAppContainerProfileName(
+ const std::string& appcontainer_id,
+ service_manager::SandboxType sandbox_type) {
+ DCHECK(sandbox_type == service_manager::SANDBOX_TYPE_GPU);
+ auto sha1 = base::SHA1HashString(appcontainer_id);
+ auto profile_name = base::StrCat(
+ {"chrome.sandbox.gpu", base::HexEncode(sha1.data(), sha1.size())});
+ return base::UTF8ToWide(profile_name);
+}
+
+sandbox::ResultCode SetupAppContainerProfile(
+ sandbox::AppContainerProfile* profile,
+ const base::CommandLine& command_line,
+ service_manager::SandboxType sandbox_type) {
+ if (sandbox_type != service_manager::SANDBOX_TYPE_GPU)
+ return sandbox::SBOX_ERROR_UNSUPPORTED;
+
+ if (!profile->AddImpersonationCapability(L"chromeInstallFiles")) {
+ DLOG(ERROR) << "AppContainerProfile::AddImpersonationCapability() failed";
+ return sandbox::SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_CAPABILITY;
+ }
+
+ std::vector<base::string16> base_caps = {
+ L"lpacChromeInstallFiles", L"registryRead",
+ };
+
+ auto cmdline_caps =
+ base::SplitString(command_line.GetSwitchValueNative(
+ service_manager::switches::kAddGpuAppContainerCaps),
+ L",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
+ base_caps.insert(base_caps.end(), cmdline_caps.begin(), cmdline_caps.end());
+
+ for (const auto& cap : base_caps) {
+ if (!profile->AddCapability(cap.c_str())) {
+ DLOG(ERROR) << "AppContainerProfile::AddCapability() failed";
+ return sandbox::SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_CAPABILITY;
+ }
+ }
+
+ if (!command_line.HasSwitch(service_manager::switches::kDisableGpuLpac)) {
+ profile->SetEnableLowPrivilegeAppContainer(true);
+ }
+
+ return sandbox::SBOX_ALL_OK;
+}
+
} // namespace
// static
@@ -654,6 +711,56 @@ sandbox::ResultCode SandboxWin::AddWin32kLockdownPolicy(
}
// static
+sandbox::ResultCode SandboxWin::AddAppContainerProfileToPolicy(
+ const base::CommandLine& command_line,
+ service_manager::SandboxType sandbox_type,
+ const std::string& appcontainer_id,
+ sandbox::TargetPolicy* policy) {
+ base::string16 profile_name =
+ GetAppContainerProfileName(appcontainer_id, sandbox_type);
+ sandbox::ResultCode result =
+ policy->AddAppContainerProfile(profile_name.c_str(), true);
+ if (result != sandbox::SBOX_ALL_OK)
+ return result;
+
+ scoped_refptr<sandbox::AppContainerProfile> profile =
+ policy->GetAppContainerProfile();
+ result = SetupAppContainerProfile(profile.get(), command_line, sandbox_type);
+ if (result != sandbox::SBOX_ALL_OK)
+ return result;
+
+ DWORD granted_access;
+ BOOL granted_access_status;
+ bool access_check =
+ profile->AccessCheck(command_line.GetProgram().value().c_str(),
+ SE_FILE_OBJECT, GENERIC_READ | GENERIC_EXECUTE,
+ &granted_access, &granted_access_status) &&
+ granted_access_status;
+ if (!access_check)
+ return sandbox::SBOX_ERROR_CREATE_APPCONTAINER_PROFILE_ACCESS_CHECK;
+
+ return sandbox::SBOX_ALL_OK;
+}
+
+// static
+bool SandboxWin::IsAppContainerEnabledForSandbox(
+ const base::CommandLine& command_line,
+ SandboxType sandbox_type) {
+ if (sandbox_type != SANDBOX_TYPE_GPU)
+ return false;
+ if (base::win::GetVersion() < base::win::VERSION_WIN10_RS1)
+ return false;
+ const std::string appcontainer_group_name =
+ base::FieldTrialList::FindFullName("EnableGpuAppContainer");
+ if (command_line.HasSwitch(switches::kDisableGpuAppContainer))
+ return false;
+ if (command_line.HasSwitch(switches::kEnableGpuAppContainer))
+ return true;
+ return base::StartsWith(appcontainer_group_name, "Enabled",
+ base::CompareCase::INSENSITIVE_ASCII);
+}
+
+// static
bool SandboxWin::InitBrokerServices(sandbox::BrokerServices* broker_services) {
// TODO(abarth): DCHECK(CalledOnValidThread());
// See <http://b/1287166>.
@@ -801,6 +908,16 @@ sandbox::ResultCode SandboxWin::StartSandboxedProcess(
return result;
}
+ std::string appcontainer_id;
+ if (IsAppContainerEnabledForSandbox(*cmd_line, sandbox_type) &&
+ delegate->GetAppContainerId(&appcontainer_id)) {
+ result = AddAppContainerProfileToPolicy(*cmd_line, sandbox_type,
+ appcontainer_id, policy.get());
+ DCHECK(result == sandbox::SBOX_ALL_OK);
+ if (result != sandbox::SBOX_ALL_OK)
+ return result;
+ }
+
// Allow the renderer and gpu processes to access the log file.
if (process_type == service_manager::switches::kRendererProcess ||
process_type == service_manager::switches::kGpuProcess) {
diff --git a/chromium/services/service_manager/sandbox/win/sandbox_win.h b/chromium/services/service_manager/sandbox/win/sandbox_win.h
index 1feb1de42ad..3e68741eea6 100644
--- a/chromium/services/service_manager/sandbox/win/sandbox_win.h
+++ b/chromium/services/service_manager/sandbox/win/sandbox_win.h
@@ -59,6 +59,21 @@ class SERVICE_MANAGER_SANDBOX_EXPORT SandboxWin {
sandbox::TargetPolicy* policy,
bool enable_opm);
+ // Add the AppContainer sandbox profile to the policy. |sandbox_type|
+ // determines what policy is enabled. |appcontainer_id| is used to create
+ // a unique package SID, it can be anything the caller wants.
+ static sandbox::ResultCode AddAppContainerProfileToPolicy(
+ const base::CommandLine& command_line,
+ service_manager::SandboxType sandbox_type,
+ const std::string& appcontainer_id,
+ sandbox::TargetPolicy* policy);
+
+ // Returns whether the AppContainer sandbox is enabled or not for a specific
+ // sandbox type from |command_line| and |sandbox_type|.
+ static bool IsAppContainerEnabledForSandbox(
+ const base::CommandLine& command_line,
+ service_manager::SandboxType sandbox_type);
+
static bool InitBrokerServices(sandbox::BrokerServices* broker_services);
static bool InitTargetServices(sandbox::TargetServices* target_services);
};
diff --git a/chromium/services/service_manager/service_manager.cc b/chromium/services/service_manager/service_manager.cc
index 5a3bd5c7752..c4574370b28 100644
--- a/chromium/services/service_manager/service_manager.cc
+++ b/chromium/services/service_manager/service_manager.cc
@@ -27,16 +27,16 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/catalog/entry.h"
#include "services/catalog/instance.h"
-#include "services/catalog/public/interfaces/constants.mojom.h"
+#include "services/catalog/public/mojom/constants.mojom.h"
#include "services/service_manager/connect_util.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/constants.mojom.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
-#include "services/service_manager/public/interfaces/service_control.mojom.h"
-#include "services/service_manager/public/interfaces/service_manager.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
+#include "services/service_manager/public/mojom/constants.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
+#include "services/service_manager/public/mojom/service_control.mojom.h"
+#include "services/service_manager/public/mojom/service_manager.mojom.h"
#include "services/service_manager/sandbox/sandbox_type.h"
#if !defined(OS_IOS)
diff --git a/chromium/services/service_manager/service_manager.h b/chromium/services/service_manager/service_manager.h
index 48a09cc7987..86f69fe2334 100644
--- a/chromium/services/service_manager/service_manager.h
+++ b/chromium/services/service_manager/service_manager.h
@@ -19,11 +19,11 @@
#include "services/service_manager/connect_params.h"
#include "services/service_manager/public/cpp/identity.h"
#include "services/service_manager/public/cpp/interface_provider_spec.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
-#include "services/service_manager/public/interfaces/service.mojom.h"
-#include "services/service_manager/public/interfaces/service_factory.mojom.h"
-#include "services/service_manager/public/interfaces/service_manager.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
+#include "services/service_manager/public/mojom/interface_provider.mojom.h"
+#include "services/service_manager/public/mojom/service.mojom.h"
+#include "services/service_manager/public/mojom/service_factory.mojom.h"
+#include "services/service_manager/public/mojom/service_manager.mojom.h"
#include "services/service_manager/runner/host/service_process_launcher_factory.h"
#include "services/service_manager/service_overrides.h"
diff --git a/chromium/services/service_manager/tests/BUILD.gn b/chromium/services/service_manager/tests/BUILD.gn
index df3413c72eb..1f874773927 100644
--- a/chromium/services/service_manager/tests/BUILD.gn
+++ b/chromium/services/service_manager/tests/BUILD.gn
@@ -37,7 +37,7 @@ service_test("service_manager_unittests") {
"//services/service_manager/embedder:unittests",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp/test:test_support",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/service_manager/runner/host:unittests",
"//services/service_manager/tests/connect",
"//services/service_manager/tests/lifecycle",
@@ -64,7 +64,7 @@ source_set("util") {
"//base:base_static",
"//mojo/edk/system",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/service_manager/runner/common",
]
}
diff --git a/chromium/services/service_manager/tests/connect/BUILD.gn b/chromium/services/service_manager/tests/connect/BUILD.gn
index 077419e5710..0535205e575 100644
--- a/chromium/services/service_manager/tests/connect/BUILD.gn
+++ b/chromium/services/service_manager/tests/connect/BUILD.gn
@@ -19,7 +19,7 @@ source_set("connect") {
"//base/test:test_support",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/service_manager/tests:util",
]
@@ -37,7 +37,7 @@ mojom("interfaces") {
"connect_test.mojom",
]
deps = [
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
@@ -71,7 +71,7 @@ service("connect_test_package") {
"//base",
"//mojo/common:common_base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
@@ -95,7 +95,7 @@ service("connect_test_app") {
"//base",
"//mojo/common:common_base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
@@ -114,7 +114,7 @@ service("connect_test_class_app") {
"//base",
"//mojo/common:common_base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
diff --git a/chromium/services/service_manager/tests/connect/connect_test.mojom b/chromium/services/service_manager/tests/connect/connect_test.mojom
index bedc074ee3e..f1579a69556 100644
--- a/chromium/services/service_manager/tests/connect/connect_test.mojom
+++ b/chromium/services/service_manager/tests/connect/connect_test.mojom
@@ -4,7 +4,7 @@
module service_manager.test.mojom;
-import "services/service_manager/public/interfaces/connector.mojom";
+import "services/service_manager/public/mojom/connector.mojom";
interface ConnectTestService {
GetTitle() => (string title);
diff --git a/chromium/services/service_manager/tests/lifecycle/BUILD.gn b/chromium/services/service_manager/tests/lifecycle/BUILD.gn
index e5bef8bff19..310a115d1ff 100644
--- a/chromium/services/service_manager/tests/lifecycle/BUILD.gn
+++ b/chromium/services/service_manager/tests/lifecycle/BUILD.gn
@@ -19,7 +19,7 @@ source_set("lifecycle") {
"//base/test:test_support",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/service_manager/runner/common",
"//services/service_manager/tests:util",
]
@@ -62,7 +62,7 @@ source_set("app_client") {
":interfaces",
"//base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
@@ -76,7 +76,7 @@ service("lifecycle_unittest_package") {
":interfaces",
"//base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
diff --git a/chromium/services/service_manager/tests/sandbox/BUILD.gn b/chromium/services/service_manager/tests/sandbox/BUILD.gn
index 864a7dee56d..bed95ff7373 100644
--- a/chromium/services/service_manager/tests/sandbox/BUILD.gn
+++ b/chromium/services/service_manager/tests/sandbox/BUILD.gn
@@ -12,4 +12,9 @@ source_set("sandbox") {
"//services/service_manager/sandbox",
"//testing/gtest",
]
+
+ if (is_win) {
+ sources += [ "sandbox_win_unittest.cc" ]
+ deps += [ "//sandbox/win:sandbox" ]
+ }
}
diff --git a/chromium/services/service_manager/tests/service_manager/BUILD.gn b/chromium/services/service_manager/tests/service_manager/BUILD.gn
index dc24bd6bdf6..8f01635ef5f 100644
--- a/chromium/services/service_manager/tests/service_manager/BUILD.gn
+++ b/chromium/services/service_manager/tests/service_manager/BUILD.gn
@@ -22,7 +22,7 @@ source_set("service_manager") {
"//mojo/edk/system",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/service_manager/runner/common",
]
@@ -38,7 +38,7 @@ mojom("interfaces") {
]
deps = [
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
@@ -108,7 +108,7 @@ service("service_manager_unittest_embedder") {
"//mojo/edk/system",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp/standalone_service:main",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/service_manager/runner:init",
"//services/service_manager/runner/common",
]
diff --git a/chromium/services/service_manager/tests/service_manager/service_manager_unittest.mojom b/chromium/services/service_manager/tests/service_manager/service_manager_unittest.mojom
index 31663743bfd..e62562b68f3 100644
--- a/chromium/services/service_manager/tests/service_manager/service_manager_unittest.mojom
+++ b/chromium/services/service_manager/tests/service_manager/service_manager_unittest.mojom
@@ -4,7 +4,7 @@
module service_manager.test.mojom;
-import "services/service_manager/public/interfaces/connector.mojom";
+import "services/service_manager/public/mojom/connector.mojom";
interface CreateInstanceTest {
SetTargetIdentity(service_manager.mojom.Identity identity);
diff --git a/chromium/services/service_manager/tests/shutdown/BUILD.gn b/chromium/services/service_manager/tests/shutdown/BUILD.gn
index cdb4bde4899..e75be1c7fda 100644
--- a/chromium/services/service_manager/tests/shutdown/BUILD.gn
+++ b/chromium/services/service_manager/tests/shutdown/BUILD.gn
@@ -22,7 +22,7 @@ source_set("shutdown") {
"//base/test:test_config",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
data_deps = [
@@ -56,7 +56,7 @@ service("shutdown_service") {
":interfaces",
"//base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
@@ -74,7 +74,7 @@ service("shutdown_client") {
":interfaces",
"//base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
]
}
diff --git a/chromium/services/shape_detection/BUILD.gn b/chromium/services/shape_detection/BUILD.gn
index 36043e56ffd..f36ee28938e 100644
--- a/chromium/services/shape_detection/BUILD.gn
+++ b/chromium/services/shape_detection/BUILD.gn
@@ -9,7 +9,6 @@ import("//testing/test.gni")
source_set("lib") {
sources = [
"barcode_detection_impl.h",
- "face_detection_provider_impl.h",
"shape_detection_service.cc",
"shape_detection_service.h",
"text_detection_impl.h",
@@ -23,12 +22,13 @@ source_set("lib") {
"detection_utils_mac.mm",
"face_detection_impl_mac.h",
"face_detection_impl_mac.mm",
+ "face_detection_provider_mac.h",
+ "face_detection_provider_mac.mm",
"text_detection_impl_mac.h",
"text_detection_impl_mac.mm",
]
libs = [ "QuartzCore.framework" ]
} else if (is_win) {
- sources -= [ "face_detection_provider_impl.h" ]
sources += [
"barcode_detection_impl.cc",
"detection_utils_win.cc",
@@ -44,6 +44,7 @@ source_set("lib") {
sources += [
"barcode_detection_impl.cc",
"face_detection_provider_impl.cc",
+ "face_detection_provider_impl.h",
"text_detection_impl.cc",
]
}
@@ -58,7 +59,7 @@ source_set("lib") {
"//base",
"//media/capture",
"//services/service_manager/public/cpp",
- "//services/shape_detection/public/interfaces",
+ "//services/shape_detection/public/mojom",
]
if (is_android) {
@@ -94,9 +95,9 @@ if (is_android) {
"//mojo/android:system_java",
"//mojo/public/java:bindings_java",
"//mojo/public/java:system_java",
- "//services/service_manager/public/interfaces:interfaces_java",
"//services/service_manager/public/java:service_manager_java",
- "//services/shape_detection/public/interfaces:interfaces_java",
+ "//services/service_manager/public/mojom:mojom_java",
+ "//services/shape_detection/public/mojom:mojom_java",
"//skia/public/interfaces:interfaces_java",
"//ui/gfx/geometry/mojo:mojo_java",
]
diff --git a/chromium/services/shape_detection/barcode_detection_impl.h b/chromium/services/shape_detection/barcode_detection_impl.h
index e0aa2451c3e..8c550bc0fe5 100644
--- a/chromium/services/shape_detection/barcode_detection_impl.h
+++ b/chromium/services/shape_detection/barcode_detection_impl.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_IMPL_H_
#define SERVICES_SHAPE_DETECTION_BARCODE_DETECTION_IMPL_H_
-#include "services/shape_detection/public/interfaces/barcodedetection.mojom.h"
+#include "services/shape_detection/public/mojom/barcodedetection.mojom.h"
namespace shape_detection {
diff --git a/chromium/services/shape_detection/barcode_detection_impl_mac.h b/chromium/services/shape_detection/barcode_detection_impl_mac.h
index 7a821c2d4eb..a2aeaa6d0ab 100644
--- a/chromium/services/shape_detection/barcode_detection_impl_mac.h
+++ b/chromium/services/shape_detection/barcode_detection_impl_mac.h
@@ -7,7 +7,7 @@
#include "base/mac/availability.h"
#include "base/mac/scoped_nsobject.h"
-#include "services/shape_detection/public/interfaces/barcodedetection.mojom.h"
+#include "services/shape_detection/public/mojom/barcodedetection.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
@class CIDetector;
diff --git a/chromium/services/shape_detection/detection_utils_mac.h b/chromium/services/shape_detection/detection_utils_mac.h
index 69e46426496..bb38f417573 100644
--- a/chromium/services/shape_detection/detection_utils_mac.h
+++ b/chromium/services/shape_detection/detection_utils_mac.h
@@ -8,7 +8,7 @@
#import <QuartzCore/QuartzCore.h>
#include "base/mac/scoped_nsobject.h"
-#include "services/shape_detection/public/interfaces/barcodedetection.mojom.h"
+#include "services/shape_detection/public/mojom/barcodedetection.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
namespace shape_detection {
diff --git a/chromium/services/shape_detection/detection_utils_win.h b/chromium/services/shape_detection/detection_utils_win.h
index d2653ab95d1..c64c6a8ae00 100644
--- a/chromium/services/shape_detection/detection_utils_win.h
+++ b/chromium/services/shape_detection/detection_utils_win.h
@@ -74,7 +74,8 @@ class AsyncOperation {
// outside. This is happening on an OS thread.
task_runner->PostTask(
FROM_HERE, base::BindOnce(&AsyncOperation::AsyncCallbackInternal,
- std::move(weak_ptr), async_op, status));
+ std::move(weak_ptr),
+ base::Unretained(async_op), status));
return S_OK;
});
diff --git a/chromium/services/shape_detection/face_detection_impl_mac.h b/chromium/services/shape_detection/face_detection_impl_mac.h
index 51d6ac21d8a..484a21ecdde 100644
--- a/chromium/services/shape_detection/face_detection_impl_mac.h
+++ b/chromium/services/shape_detection/face_detection_impl_mac.h
@@ -6,7 +6,7 @@
#define SERVICES_SHAPE_DETECTION_FACE_DETECTION_IMPL_MAC_H_
#include "base/mac/scoped_nsobject.h"
-#include "services/shape_detection/public/interfaces/facedetection.mojom.h"
+#include "services/shape_detection/public/mojom/facedetection.mojom.h"
#include "third_party/skia/include/core/SkBitmap.h"
@class CIDetector;
diff --git a/chromium/services/shape_detection/face_detection_impl_mac.mm b/chromium/services/shape_detection/face_detection_impl_mac.mm
index 7228152d0c6..58e5f203b2f 100644
--- a/chromium/services/shape_detection/face_detection_impl_mac.mm
+++ b/chromium/services/shape_detection/face_detection_impl_mac.mm
@@ -5,20 +5,10 @@
#include "services/shape_detection/face_detection_impl_mac.h"
#include "base/mac/scoped_cftyperef.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shape_detection/detection_utils_mac.h"
-#include "services/shape_detection/face_detection_provider_impl.h"
namespace shape_detection {
-void FaceDetectionProviderImpl::CreateFaceDetection(
- shape_detection::mojom::FaceDetectionRequest request,
- shape_detection::mojom::FaceDetectorOptionsPtr options) {
- mojo::MakeStrongBinding(
- std::make_unique<FaceDetectionImplMac>(std::move(options)),
- std::move(request));
-}
-
FaceDetectionImplMac::FaceDetectionImplMac(
shape_detection::mojom::FaceDetectorOptionsPtr options) {
NSString* const accuracy =
diff --git a/chromium/services/shape_detection/face_detection_impl_win.h b/chromium/services/shape_detection/face_detection_impl_win.h
index 966a49369b0..d99235f2d58 100644
--- a/chromium/services/shape_detection/face_detection_impl_win.h
+++ b/chromium/services/shape_detection/face_detection_impl_win.h
@@ -16,7 +16,7 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shape_detection/detection_utils_win.h"
-#include "services/shape_detection/public/interfaces/facedetection.mojom.h"
+#include "services/shape_detection/public/mojom/facedetection.mojom.h"
class SkBitmap;
diff --git a/chromium/services/shape_detection/face_detection_impl_win_unittest.cc b/chromium/services/shape_detection/face_detection_impl_win_unittest.cc
index 0716f52ae78..8b25fde5425 100644
--- a/chromium/services/shape_detection/face_detection_impl_win_unittest.cc
+++ b/chromium/services/shape_detection/face_detection_impl_win_unittest.cc
@@ -17,7 +17,7 @@
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h"
#include "services/shape_detection/face_detection_provider_win.h"
-#include "services/shape_detection/public/interfaces/facedetection_provider.mojom.h"
+#include "services/shape_detection/public/mojom/facedetection_provider.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/codec/jpeg_codec.h"
diff --git a/chromium/services/shape_detection/face_detection_provider_impl.h b/chromium/services/shape_detection/face_detection_provider_impl.h
index bd03eeac6a1..be57400990b 100644
--- a/chromium/services/shape_detection/face_detection_provider_impl.h
+++ b/chromium/services/shape_detection/face_detection_provider_impl.h
@@ -6,7 +6,7 @@
#define SERVICES_SHAPE_DETECTION_FACE_DETECTION_PROVIDER_IMPL_H_
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/shape_detection/public/interfaces/facedetection_provider.mojom.h"
+#include "services/shape_detection/public/mojom/facedetection_provider.mojom.h"
namespace shape_detection {
diff --git a/chromium/services/shape_detection/face_detection_provider_mac.h b/chromium/services/shape_detection/face_detection_provider_mac.h
new file mode 100644
index 00000000000..e84c59e6888
--- /dev/null
+++ b/chromium/services/shape_detection/face_detection_provider_mac.h
@@ -0,0 +1,34 @@
+// Copyright 2018 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 SERVICES_SHAPE_DETECTION_FACE_DETECTION_PROVIDER_MAC_H_
+#define SERVICES_SHAPE_DETECTION_FACE_DETECTION_PROVIDER_MAC_H_
+
+#include "base/macros.h"
+#include "services/shape_detection/public/mojom/facedetection_provider.mojom.h"
+
+namespace shape_detection {
+
+// The FaceDetectionProviderMac class is a provider that binds an implementation
+// of mojom::FaceDetection with Core Image or Vision Framework.
+class FaceDetectionProviderMac
+ : public shape_detection::mojom::FaceDetectionProvider {
+ public:
+ FaceDetectionProviderMac();
+ ~FaceDetectionProviderMac() override;
+
+ // Binds FaceDetection provider request to the implementation of
+ // mojom::FaceDetectionProvider.
+ static void Create(mojom::FaceDetectionProviderRequest request);
+
+ void CreateFaceDetection(mojom::FaceDetectionRequest request,
+ mojom::FaceDetectorOptionsPtr options) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FaceDetectionProviderMac);
+};
+
+} // namespace shape_detection
+
+#endif // SERVICES_SHAPE_DETECTION_FACE_DETECTION_PROVIDER_MAC_H_
diff --git a/chromium/services/shape_detection/face_detection_provider_mac.mm b/chromium/services/shape_detection/face_detection_provider_mac.mm
new file mode 100644
index 00000000000..8bd2f44cd4c
--- /dev/null
+++ b/chromium/services/shape_detection/face_detection_provider_mac.mm
@@ -0,0 +1,34 @@
+// Copyright 2018 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/shape_detection/face_detection_provider_mac.h"
+
+#include <memory>
+#include <utility>
+
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/shape_detection/face_detection_impl_mac.h"
+
+namespace shape_detection {
+
+FaceDetectionProviderMac::FaceDetectionProviderMac() = default;
+
+FaceDetectionProviderMac::~FaceDetectionProviderMac() = default;
+
+// static
+void FaceDetectionProviderMac::Create(
+ mojom::FaceDetectionProviderRequest request) {
+ mojo::MakeStrongBinding(std::make_unique<FaceDetectionProviderMac>(),
+ std::move(request));
+}
+
+void FaceDetectionProviderMac::CreateFaceDetection(
+ mojom::FaceDetectionRequest request,
+ mojom::FaceDetectorOptionsPtr options) {
+ mojo::MakeStrongBinding(
+ std::make_unique<FaceDetectionImplMac>(std::move(options)),
+ std::move(request));
+}
+
+} // namespace shape_detection
diff --git a/chromium/services/shape_detection/face_detection_provider_win.h b/chromium/services/shape_detection/face_detection_provider_win.h
index e98c1e8e54f..c73032d23a5 100644
--- a/chromium/services/shape_detection/face_detection_provider_win.h
+++ b/chromium/services/shape_detection/face_detection_provider_win.h
@@ -14,7 +14,7 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shape_detection/detection_utils_win.h"
#include "services/shape_detection/face_detection_impl_win.h"
-#include "services/shape_detection/public/interfaces/facedetection_provider.mojom.h"
+#include "services/shape_detection/public/mojom/facedetection_provider.mojom.h"
namespace shape_detection {
diff --git a/chromium/services/shape_detection/public/interfaces/BUILD.gn b/chromium/services/shape_detection/public/mojom/BUILD.gn
index 44522415a7e..52292ab6b05 100644
--- a/chromium/services/shape_detection/public/interfaces/BUILD.gn
+++ b/chromium/services/shape_detection/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"barcodedetection.mojom",
"constants.mojom",
diff --git a/chromium/services/service_manager/public/interfaces/OWNERS b/chromium/services/shape_detection/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/service_manager/public/interfaces/OWNERS
+++ b/chromium/services/shape_detection/public/mojom/OWNERS
diff --git a/chromium/services/shape_detection/public/interfaces/barcodedetection.mojom b/chromium/services/shape_detection/public/mojom/barcodedetection.mojom
index 5ae9aef56d7..5ae9aef56d7 100644
--- a/chromium/services/shape_detection/public/interfaces/barcodedetection.mojom
+++ b/chromium/services/shape_detection/public/mojom/barcodedetection.mojom
diff --git a/chromium/services/shape_detection/public/interfaces/constants.mojom b/chromium/services/shape_detection/public/mojom/constants.mojom
index 85f919b4923..85f919b4923 100644
--- a/chromium/services/shape_detection/public/interfaces/constants.mojom
+++ b/chromium/services/shape_detection/public/mojom/constants.mojom
diff --git a/chromium/services/shape_detection/public/interfaces/facedetection.mojom b/chromium/services/shape_detection/public/mojom/facedetection.mojom
index eb90fa99731..eb90fa99731 100644
--- a/chromium/services/shape_detection/public/interfaces/facedetection.mojom
+++ b/chromium/services/shape_detection/public/mojom/facedetection.mojom
diff --git a/chromium/services/shape_detection/public/interfaces/facedetection_provider.mojom b/chromium/services/shape_detection/public/mojom/facedetection_provider.mojom
index 33346d4568f..33346d4568f 100644
--- a/chromium/services/shape_detection/public/interfaces/facedetection_provider.mojom
+++ b/chromium/services/shape_detection/public/mojom/facedetection_provider.mojom
diff --git a/chromium/services/shape_detection/public/interfaces/textdetection.mojom b/chromium/services/shape_detection/public/mojom/textdetection.mojom
index b3bb5a76247..b3bb5a76247 100644
--- a/chromium/services/shape_detection/public/interfaces/textdetection.mojom
+++ b/chromium/services/shape_detection/public/mojom/textdetection.mojom
diff --git a/chromium/services/shape_detection/shape_detection_service.cc b/chromium/services/shape_detection/shape_detection_service.cc
index 492ad069093..27809edaed3 100644
--- a/chromium/services/shape_detection/shape_detection_service.cc
+++ b/chromium/services/shape_detection/shape_detection_service.cc
@@ -4,12 +4,18 @@
#include "services/shape_detection/shape_detection_service.h"
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
#include "base/macros.h"
#include "build/build_config.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/shape_detection/barcode_detection_impl.h"
#if defined(OS_WIN)
#include "services/shape_detection/face_detection_provider_win.h"
+#elif defined(OS_MACOSX)
+#include "services/shape_detection/face_detection_provider_mac.h"
#else
#include "services/shape_detection/face_detection_provider_impl.h"
#endif
@@ -32,8 +38,7 @@ ShapeDetectionService::~ShapeDetectionService() = default;
void ShapeDetectionService::OnStart() {
ref_factory_.reset(new service_manager::ServiceContextRefFactory(
- base::Bind(&service_manager::ServiceContext::RequestQuit,
- base::Unretained(context()))));
+ context()->CreateQuitClosure()));
#if defined(OS_ANDROID)
registry_.AddInterface(
@@ -47,6 +52,10 @@ void ShapeDetectionService::OnStart() {
registry_.AddInterface(base::Bind(&BarcodeDetectionImpl::Create));
registry_.AddInterface(base::Bind(&TextDetectionImpl::Create));
registry_.AddInterface(base::Bind(&FaceDetectionProviderWin::Create));
+#elif defined(OS_MACOSX)
+ registry_.AddInterface(base::Bind(&BarcodeDetectionImpl::Create));
+ registry_.AddInterface(base::Bind(&TextDetectionImpl::Create));
+ registry_.AddInterface(base::Bind(&FaceDetectionProviderMac::Create));
#else
registry_.AddInterface(base::Bind(&BarcodeDetectionImpl::Create));
registry_.AddInterface(base::Bind(&TextDetectionImpl::Create));
diff --git a/chromium/services/shape_detection/text_detection_impl.h b/chromium/services/shape_detection/text_detection_impl.h
index 30e8400a10e..24a999fc200 100644
--- a/chromium/services/shape_detection/text_detection_impl.h
+++ b/chromium/services/shape_detection/text_detection_impl.h
@@ -5,7 +5,7 @@
#ifndef SERVICES_SHAPE_DETECTION_TEXT_DETECTION_IMPL_H_
#define SERVICES_SHAPE_DETECTION_TEXT_DETECTION_IMPL_H_
-#include "services/shape_detection/public/interfaces/textdetection.mojom.h"
+#include "services/shape_detection/public/mojom/textdetection.mojom.h"
namespace shape_detection {
diff --git a/chromium/services/shape_detection/text_detection_impl_mac.h b/chromium/services/shape_detection/text_detection_impl_mac.h
index 95c8d65ca62..5015dd29572 100644
--- a/chromium/services/shape_detection/text_detection_impl_mac.h
+++ b/chromium/services/shape_detection/text_detection_impl_mac.h
@@ -7,7 +7,7 @@
#include "base/mac/availability.h"
#include "base/mac/scoped_nsobject.h"
-#include "services/shape_detection/public/interfaces/textdetection.mojom.h"
+#include "services/shape_detection/public/mojom/textdetection.mojom.h"
@class CIDetector;
diff --git a/chromium/services/shape_detection/text_detection_impl_win.h b/chromium/services/shape_detection/text_detection_impl_win.h
index 844be8622cb..79ffe9d1ec5 100644
--- a/chromium/services/shape_detection/text_detection_impl_win.h
+++ b/chromium/services/shape_detection/text_detection_impl_win.h
@@ -15,7 +15,7 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/shape_detection/detection_utils_win.h"
-#include "services/shape_detection/public/interfaces/textdetection.mojom.h"
+#include "services/shape_detection/public/mojom/textdetection.mojom.h"
class SkBitmap;
diff --git a/chromium/services/shape_detection/text_detection_impl_win_unittest.cc b/chromium/services/shape_detection/text_detection_impl_win_unittest.cc
index 34c6dc258c9..7e1cc54488e 100644
--- a/chromium/services/shape_detection/text_detection_impl_win_unittest.cc
+++ b/chromium/services/shape_detection/text_detection_impl_win_unittest.cc
@@ -16,7 +16,7 @@
#include "base/win/scoped_com_initializer.h"
#include "base/win/windows_version.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/shape_detection/public/interfaces/textdetection.mojom.h"
+#include "services/shape_detection/public/mojom/textdetection.mojom.h"
#include "services/shape_detection/text_detection_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/codec/png_codec.h"
diff --git a/chromium/services/test/BUILD.gn b/chromium/services/test/BUILD.gn
index df1f2194505..7bd581fc541 100644
--- a/chromium/services/test/BUILD.gn
+++ b/chromium/services/test/BUILD.gn
@@ -22,6 +22,14 @@ source_set("run_all_service_tests") {
"//ui/base",
]
+ if (is_ios) {
+ deps += [ ":tests_bundle_data" ]
+ } else {
+ data = [
+ "data/",
+ ]
+ }
+
data_deps = [
"//ui/resources:ui_test_pak_data",
]
@@ -34,3 +42,33 @@ source_set("run_all_service_tests") {
deps += [ "//ui/ozone" ]
}
}
+
+bundle_data("tests_bundle_data") {
+ visibility = [ ":run_all_service_tests" ]
+ testonly = true
+ sources = [
+ "//services/test/data/content-sniffer-test0.html",
+ "//services/test/data/content-sniffer-test0.html.mock-http-headers",
+ "//services/test/data/content-sniffer-test1.html",
+ "//services/test/data/content-sniffer-test1.html.mock-http-headers",
+ "//services/test/data/content-sniffer-test2.html",
+ "//services/test/data/content-sniffer-test2.html.mock-http-headers",
+ "//services/test/data/content-sniffer-test4.html",
+ "//services/test/data/content-sniffer-test4.html.mock-http-headers",
+ "//services/test/data/empty.html",
+ "//services/test/data/hello.html",
+ "//services/test/data/hello.html.mock-http-headers",
+ "//services/test/data/nocache.html",
+ "//services/test/data/nocache.html.mock-http-headers",
+ "//services/test/data/nosniff-test.html",
+ "//services/test/data/nosniff-test.html.mock-http-headers",
+ "//services/test/data/redirect307-to-echo",
+ "//services/test/data/redirect307-to-echo.mock-http-headers",
+ "//services/test/data/simple_page.html",
+ "//services/test/data/title1.html",
+ ]
+ outputs = [
+ "{{bundle_resources_dir}}/" +
+ "{{source_root_relative_dir}}/{{source_file_part}}",
+ ]
+}
diff --git a/chromium/services/test/echo/BUILD.gn b/chromium/services/test/echo/BUILD.gn
index 8aa585f4c86..86705cffbd6 100644
--- a/chromium/services/test/echo/BUILD.gn
+++ b/chromium/services/test/echo/BUILD.gn
@@ -15,8 +15,8 @@ source_set("lib") {
deps = [
"//base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
- "//services/test/echo/public/interfaces",
+ "//services/service_manager/public/mojom",
+ "//services/test/echo/public/mojom",
]
}
diff --git a/chromium/services/test/echo/public/interfaces/BUILD.gn b/chromium/services/test/echo/public/mojom/BUILD.gn
index d50f842bb0d..4027a8abe24 100644
--- a/chromium/services/test/echo/public/interfaces/BUILD.gn
+++ b/chromium/services/test/echo/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"echo.mojom",
]
diff --git a/chromium/services/test/echo/public/interfaces/echo.mojom b/chromium/services/test/echo/public/mojom/echo.mojom
index 412364e7d55..412364e7d55 100644
--- a/chromium/services/test/echo/public/interfaces/echo.mojom
+++ b/chromium/services/test/echo/public/mojom/echo.mojom
diff --git a/chromium/services/test/user_id/BUILD.gn b/chromium/services/test/user_id/BUILD.gn
index b8853ec8708..f93b129c4b8 100644
--- a/chromium/services/test/user_id/BUILD.gn
+++ b/chromium/services/test/user_id/BUILD.gn
@@ -15,8 +15,8 @@ source_set("lib") {
deps = [
"//base",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
- "//services/test/user_id/public/interfaces",
+ "//services/service_manager/public/mojom",
+ "//services/test/user_id/public/mojom",
]
}
diff --git a/chromium/services/test/user_id/public/interfaces/BUILD.gn b/chromium/services/test/user_id/public/mojom/BUILD.gn
index a87f2fca799..7208bd715f6 100644
--- a/chromium/services/test/user_id/public/interfaces/BUILD.gn
+++ b/chromium/services/test/user_id/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"user_id.mojom",
]
diff --git a/chromium/services/test/user_id/public/interfaces/user_id.mojom b/chromium/services/test/user_id/public/mojom/user_id.mojom
index a22579f2174..a22579f2174 100644
--- a/chromium/services/test/user_id/public/interfaces/user_id.mojom
+++ b/chromium/services/test/user_id/public/mojom/user_id.mojom
diff --git a/chromium/services/tracing/BUILD.gn b/chromium/services/tracing/BUILD.gn
new file mode 100644
index 00000000000..157a1a7bb8e
--- /dev/null
+++ b/chromium/services/tracing/BUILD.gn
@@ -0,0 +1,92 @@
+# Copyright 2018 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.
+
+# There should be only one tracing service. It is currently
+# in the browser process. So, only //content/browser should link to this target.
+# Others modules should only need the public targets.
+import("//services/catalog/public/tools/catalog.gni")
+import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+import("//services/service_manager/public/tools/test/service_test.gni")
+
+source_set("lib") {
+ sources = [
+ "agent_registry.cc",
+ "agent_registry.h",
+ "coordinator.cc",
+ "coordinator.h",
+ "recorder.cc",
+ "recorder.h",
+ "tracing_service.cc",
+ "tracing_service.h",
+ ]
+
+ public_deps = [
+ "//base",
+ "//mojo/common",
+ "//mojo/public/cpp/bindings",
+ "//services/tracing/public/cpp",
+ ]
+}
+
+service_manifest("manifest") {
+ name = "tracing"
+ source = "manifest.json"
+}
+
+service("tracing") {
+ sources = [
+ "service_main.cc",
+ ]
+
+ deps = [
+ ":lib",
+ "//mojo/public/cpp/system",
+ ]
+}
+
+source_set("tests") {
+ testonly = true
+
+ sources = [
+ "agent_registry_unittest.cc",
+ "coordinator_unittest.cc",
+ "public/cpp/chrome_trace_event_agent_unittest.cc",
+ "recorder_unittest.cc",
+ "test_util.cc",
+ "test_util.h",
+ ]
+
+ if (!is_android) {
+ sources += [ "tracing_service_unittest.cc" ]
+ }
+
+ deps = [
+ ":lib",
+ "//base",
+ "//base/test:test_support",
+ "//mojo/public/cpp/bindings",
+ "//services/service_manager/public/cpp",
+ "//services/service_manager/public/cpp:service_test_support",
+ "//services/service_manager/public/mojom",
+ "//services/tracing:lib",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+
+ data_deps = [
+ ":tracing",
+ ]
+}
+
+service_manifest("unittest_manifest") {
+ name = "tracing_unittests"
+ source = "unittest_manifest.json"
+}
+
+catalog("tests_catalog") {
+ testonly = true
+ embedded_services = [ ":unittest_manifest" ]
+ standalone_services = [ ":manifest" ]
+}
diff --git a/chromium/services/tracing/DEPS b/chromium/services/tracing/DEPS
new file mode 100644
index 00000000000..5f9afdbbf6f
--- /dev/null
+++ b/chromium/services/tracing/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+services/service_manager/public"
+]
diff --git a/chromium/services/tracing/OWNERS b/chromium/services/tracing/OWNERS
new file mode 100644
index 00000000000..041b283cbdc
--- /dev/null
+++ b/chromium/services/tracing/OWNERS
@@ -0,0 +1,8 @@
+file://base/trace_event/OWNERS
+chiniforooshan@chromium.org
+
+per-file manifest.json=set noparent
+per-file manifest.json=file://ipc/SECURITY_OWNERS
+
+per-file unittest_manifest.json=set noparent
+per-file unittest_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/resource_coordinator/tracing/agent_registry.cc b/chromium/services/tracing/agent_registry.cc
index f80029178db..5dceb1513a8 100644
--- a/chromium/services/resource_coordinator/tracing/agent_registry.cc
+++ b/chromium/services/tracing/agent_registry.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/tracing/agent_registry.h"
+#include "services/tracing/agent_registry.h"
#include <string>
#include <utility>
@@ -11,6 +11,7 @@
#include "base/logging.h"
#include "base/threading/thread_checker.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
namespace {
tracing::AgentRegistry* g_agent_registry;
@@ -18,19 +19,22 @@ tracing::AgentRegistry* g_agent_registry;
namespace tracing {
-AgentRegistry::AgentEntry::AgentEntry(size_t id,
- AgentRegistry* agent_registry,
- mojom::AgentPtr agent,
- const std::string& label,
- mojom::TraceDataType type,
- bool supports_explicit_clock_sync)
+AgentRegistry::AgentEntry::AgentEntry(
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref,
+ size_t id,
+ AgentRegistry* agent_registry,
+ mojom::AgentPtr agent,
+ const std::string& label,
+ mojom::TraceDataType type,
+ bool supports_explicit_clock_sync)
: id_(id),
agent_registry_(agent_registry),
agent_(std::move(agent)),
label_(label),
type_(type),
supports_explicit_clock_sync_(supports_explicit_clock_sync),
- is_tracing_(false) {
+ is_tracing_(false),
+ service_ref_(std::move(service_ref)) {
DCHECK(!label.empty());
agent_.set_connection_error_handler(base::BindRepeating(
&AgentRegistry::AgentEntry::OnConnectionError, AsWeakPtr()));
@@ -75,7 +79,9 @@ AgentRegistry* AgentRegistry::GetInstance() {
return g_agent_registry;
}
-AgentRegistry::AgentRegistry() {
+AgentRegistry::AgentRegistry(
+ service_manager::ServiceContextRefFactory* service_ref_factory)
+ : service_ref_factory_(service_ref_factory) {
DCHECK(!g_agent_registry);
g_agent_registry = this;
}
@@ -120,7 +126,8 @@ void AgentRegistry::RegisterAgent(mojom::AgentPtr agent,
mojom::TraceDataType type,
bool supports_explicit_clock_sync) {
auto id = next_agent_id_++;
- auto entry = std::make_unique<AgentEntry>(id, this, std::move(agent), label,
+ auto entry = std::make_unique<AgentEntry>(service_ref_factory_->CreateRef(),
+ id, this, std::move(agent), label,
type, supports_explicit_clock_sync);
if (!agent_initialization_callback_.is_null())
agent_initialization_callback_.Run(entry.get());
diff --git a/chromium/services/resource_coordinator/tracing/agent_registry.h b/chromium/services/tracing/agent_registry.h
index 202d6b8aa75..91cb7b60363 100644
--- a/chromium/services/resource_coordinator/tracing/agent_registry.h
+++ b/chromium/services/tracing/agent_registry.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_RESOURCE_COORDINATOR_TRACING_AGENT_REGISTRY_H_
-#define SERVICES_RESOURCE_COORDINATOR_TRACING_AGENT_REGISTRY_H_
+#ifndef SERVICES_TRACING_AGENT_REGISTRY_H_
+#define SERVICES_TRACING_AGENT_REGISTRY_H_
#include <map>
#include <memory>
@@ -14,11 +14,13 @@
#include "base/memory/weak_ptr.h"
#include "base/threading/thread_checker.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
#include "services/service_manager/public/cpp/identity.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
namespace service_manager {
struct BindSourceInfo;
+class ServiceContextRef;
+class ServiceContextRefFactory;
} // namespace service_manager
namespace tracing {
@@ -27,7 +29,8 @@ class AgentRegistry : public mojom::AgentRegistry {
public:
class AgentEntry : public base::SupportsWeakPtr<AgentEntry> {
public:
- AgentEntry(size_t id,
+ AgentEntry(std::unique_ptr<service_manager::ServiceContextRef> service_ref,
+ size_t id,
AgentRegistry* agent_registry,
mojom::AgentPtr agent,
const std::string& label,
@@ -63,6 +66,7 @@ class AgentRegistry : public mojom::AgentRegistry {
const bool supports_explicit_clock_sync_;
std::map<const void*, base::OnceClosure> closures_;
bool is_tracing_;
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
DISALLOW_COPY_AND_ASSIGN(AgentEntry);
};
@@ -73,7 +77,8 @@ class AgentRegistry : public mojom::AgentRegistry {
static AgentRegistry* GetInstance();
- AgentRegistry();
+ explicit AgentRegistry(
+ service_manager::ServiceContextRefFactory* service_ref_factory);
void BindAgentRegistryRequest(
mojom::AgentRegistryRequest request,
@@ -110,6 +115,7 @@ class AgentRegistry : public mojom::AgentRegistry {
size_t next_agent_id_ = 0;
std::map<size_t, std::unique_ptr<AgentEntry>> agents_;
AgentInitializationCallback agent_initialization_callback_;
+ service_manager::ServiceContextRefFactory* service_ref_factory_;
THREAD_CHECKER(thread_checker_);
@@ -118,4 +124,4 @@ class AgentRegistry : public mojom::AgentRegistry {
} // namespace tracing
-#endif // SERVICES_RESOURCE_COORDINATOR_TRACING_AGENT_REGISTRY_H_
+#endif // SERVICES_TRACING_AGENT_REGISTRY_H_
diff --git a/chromium/services/resource_coordinator/tracing/agent_registry_unittest.cc b/chromium/services/tracing/agent_registry_unittest.cc
index 3493ee2f3c9..7a75d0049a9 100644
--- a/chromium/services/resource_coordinator/tracing/agent_registry_unittest.cc
+++ b/chromium/services/tracing/agent_registry_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/tracing/agent_registry.h"
+#include "services/tracing/agent_registry.h"
#include <memory>
#include <string>
@@ -10,17 +10,20 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
-#include "services/resource_coordinator/tracing/test_util.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
+#include "services/tracing/test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace tracing {
class AgentRegistryTest : public testing::Test {
public:
+ AgentRegistryTest() : service_ref_factory_(base::DoNothing()) {}
+
void SetUp() override {
message_loop_.reset(new base::MessageLoop());
- registry_.reset(new AgentRegistry());
+ registry_.reset(new AgentRegistry(&service_ref_factory_));
}
void TearDown() override {
@@ -42,6 +45,7 @@ class AgentRegistryTest : public testing::Test {
}
std::unique_ptr<AgentRegistry> registry_;
+ service_manager::ServiceContextRefFactory service_ref_factory_;
private:
std::unique_ptr<base::MessageLoop> message_loop_;
diff --git a/chromium/services/resource_coordinator/tracing/coordinator.cc b/chromium/services/tracing/coordinator.cc
index cd2a394f090..795abd0f371 100644
--- a/chromium/services/resource_coordinator/tracing/coordinator.cc
+++ b/chromium/services/tracing/coordinator.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/tracing/coordinator.h"
+#include "services/tracing/coordinator.h"
#include <algorithm>
#include <string>
@@ -26,11 +26,12 @@
#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_event.h"
#include "mojo/common/data_pipe_utils.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing_constants.mojom.h"
-#include "services/resource_coordinator/tracing/agent_registry.h"
-#include "services/resource_coordinator/tracing/recorder.h"
#include "services/service_manager/public/cpp/bind_source_info.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+#include "services/tracing/agent_registry.h"
+#include "services/tracing/public/mojom/constants.mojom.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
+#include "services/tracing/recorder.h"
namespace {
@@ -270,10 +271,12 @@ Coordinator* Coordinator::GetInstance() {
return g_coordinator;
}
-Coordinator::Coordinator()
+Coordinator::Coordinator(
+ service_manager::ServiceContextRefFactory* service_ref_factory)
: binding_(this),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
agent_registry_(AgentRegistry::GetInstance()),
+ service_ref_(service_ref_factory->CreateRef()),
weak_ptr_factory_(this) {
DCHECK(!g_coordinator);
DCHECK(agent_registry_);
diff --git a/chromium/services/resource_coordinator/tracing/coordinator.h b/chromium/services/tracing/coordinator.h
index 5ce696762e0..17e6867b04b 100644
--- a/chromium/services/resource_coordinator/tracing/coordinator.h
+++ b/chromium/services/tracing/coordinator.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_RESOURCE_COORDINATOR_TRACING_COORDINATOR_H_
-#define SERVICES_RESOURCE_COORDINATOR_TRACING_COORDINATOR_H_
+#ifndef SERVICES_TRACING_COORDINATOR_H_
+#define SERVICES_TRACING_COORDINATOR_H_
#include <map>
#include <memory>
@@ -16,9 +16,9 @@
#include "base/single_thread_task_runner.h"
#include "base/values.h"
#include "mojo/public/cpp/system/data_pipe.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
-#include "services/resource_coordinator/tracing/agent_registry.h"
-#include "services/resource_coordinator/tracing/recorder.h"
+#include "services/tracing/agent_registry.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
+#include "services/tracing/recorder.h"
namespace base {
class TimeTicks;
@@ -42,7 +42,8 @@ class Coordinator : public mojom::Coordinator {
public:
static Coordinator* GetInstance();
- Coordinator();
+ explicit Coordinator(
+ service_manager::ServiceContextRefFactory* service_ref_factory);
void BindCoordinatorRequest(
mojom::CoordinatorRequest request,
@@ -107,6 +108,7 @@ class Coordinator : public mojom::Coordinator {
// For getting categories.
std::set<std::string> category_set_;
GetCategoriesCallback get_categories_callback_;
+ std::unique_ptr<service_manager::ServiceContextRef> service_ref_;
base::WeakPtrFactory<Coordinator> weak_ptr_factory_;
@@ -114,4 +116,4 @@ class Coordinator : public mojom::Coordinator {
};
} // namespace tracing
-#endif // SERVICES_RESOURCE_COORDINATOR_TRACING_COORDINATOR_H_
+#endif // SERVICES_TRACING_COORDINATOR_H_
diff --git a/chromium/services/resource_coordinator/tracing/coordinator_unittest.cc b/chromium/services/tracing/coordinator_unittest.cc
index 80cc1097dfb..28f6d31c9f1 100644
--- a/chromium/services/resource_coordinator/tracing/coordinator_unittest.cc
+++ b/chromium/services/tracing/coordinator_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/tracing/coordinator.h"
+#include "services/tracing/coordinator.h"
#include <algorithm>
#include <memory>
@@ -16,8 +16,9 @@
#include "base/test/scoped_task_environment.h"
#include "mojo/common/data_pipe_drainer.h"
#include "mojo/public/cpp/system/data_pipe.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
-#include "services/resource_coordinator/tracing/test_util.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
+#include "services/tracing/test_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace tracing {
@@ -25,10 +26,12 @@ namespace tracing {
class CoordinatorTest : public testing::Test,
public mojo::common::DataPipeDrainer::Client {
public:
+ CoordinatorTest() : service_ref_factory_(base::DoNothing()) {}
+
// testing::Test
void SetUp() override {
- agent_registry_.reset(new AgentRegistry());
- coordinator_.reset(new Coordinator());
+ agent_registry_.reset(new AgentRegistry(&service_ref_factory_));
+ coordinator_.reset(new Coordinator(&service_ref_factory_));
output_ = "";
}
@@ -160,6 +163,7 @@ class CoordinatorTest : public testing::Test,
std::unique_ptr<mojo::common::DataPipeDrainer> drainer_;
base::RepeatingClosure quit_closure_;
std::string output_;
+ service_manager::ServiceContextRefFactory service_ref_factory_;
};
TEST_F(CoordinatorTest, StartTracingSimple) {
diff --git a/chromium/services/tracing/manifest.json b/chromium/services/tracing/manifest.json
new file mode 100644
index 00000000000..7f5e1128fc2
--- /dev/null
+++ b/chromium/services/tracing/manifest.json
@@ -0,0 +1,21 @@
+{
+ "name": "tracing",
+ "display_name": "Tracing",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "app": [
+ "tracing::mojom::AgentRegistry"
+ ],
+ "tracing": [ "tracing::mojom::Coordinator" ],
+ "tests": [ "*" ]
+ },
+ "requires": {
+ "service_manager": [
+ "service_manager:singleton",
+ "service_manager:service_manager"
+ ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/tracing/public/cpp/BUILD.gn b/chromium/services/tracing/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..d46b333bf70
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2018 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.
+
+component("cpp") {
+ sources = [
+ "base_agent.cc",
+ "base_agent.h",
+ "chrome_trace_event_agent.cc",
+ "chrome_trace_event_agent.h",
+ ]
+
+ defines = [ "IS_TRACING_CPP_IMPL" ]
+ output_name = "tracing_cpp"
+
+ public_deps = [
+ "//base",
+ "//mojo/public/cpp/bindings",
+ "//services/service_manager/public/cpp",
+ "//services/tracing/public/mojom",
+ ]
+}
diff --git a/chromium/services/tracing/public/cpp/base_agent.cc b/chromium/services/tracing/public/cpp/base_agent.cc
new file mode 100644
index 00000000000..3df867d4e99
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/base_agent.cc
@@ -0,0 +1,57 @@
+// Copyright 2018 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/tracing/public/cpp/base_agent.h"
+
+#include <utility>
+
+#include "services/service_manager/public/cpp/connector.h"
+#include "services/tracing/public/mojom/constants.mojom.h"
+
+namespace tracing {
+
+BaseAgent::BaseAgent(service_manager::Connector* connector,
+ const std::string& label,
+ mojom::TraceDataType type,
+ bool supports_explicit_clock_sync)
+ : binding_(this) {
+ // |connector| can be null in tests.
+ if (!connector)
+ return;
+ tracing::mojom::AgentRegistryPtr agent_registry;
+ connector->BindInterface(tracing::mojom::kServiceName, &agent_registry);
+
+ tracing::mojom::AgentPtr agent;
+ binding_.Bind(mojo::MakeRequest(&agent));
+ agent_registry->RegisterAgent(std::move(agent), label, type,
+ supports_explicit_clock_sync);
+}
+
+BaseAgent::~BaseAgent() = default;
+
+void BaseAgent::StartTracing(const std::string& config,
+ base::TimeTicks coordinator_time,
+ const Agent::StartTracingCallback& callback) {
+ callback.Run(true /* success */);
+}
+
+void BaseAgent::StopAndFlush(tracing::mojom::RecorderPtr recorder) {}
+
+void BaseAgent::RequestClockSyncMarker(
+ const std::string& sync_id,
+ const Agent::RequestClockSyncMarkerCallback& callback) {
+ NOTREACHED() << "The agent claims to support explicit clock sync but does "
+ << "not override BaseAgent::RequestClockSyncMarker()";
+}
+
+void BaseAgent::GetCategories(const Agent::GetCategoriesCallback& callback) {
+ callback.Run("" /* categories */);
+}
+
+void BaseAgent::RequestBufferStatus(
+ const Agent::RequestBufferStatusCallback& callback) {
+ callback.Run(0 /* capacity */, 0 /* count */);
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/public/cpp/base_agent.h b/chromium/services/tracing/public/cpp/base_agent.h
new file mode 100644
index 00000000000..ae6caf129d9
--- /dev/null
+++ b/chromium/services/tracing/public/cpp/base_agent.h
@@ -0,0 +1,51 @@
+// Copyright 2018 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 SERVICES_TRACING_PUBLIC_CPP_BASE_AGENT_H_
+#define SERVICES_TRACING_PUBLIC_CPP_BASE_AGENT_H_
+
+#include <string>
+
+#include "base/component_export.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
+
+namespace service_manager {
+class Connector;
+} // namespace service_manager
+
+// This class is a minimal implementation of mojom::Agent to reduce boilerplate
+// code in tracing agents. A tracing agent can inherit from this class and only
+// override methods that actually do something, in most cases only StartTracing
+// and StopAndFlush.
+namespace tracing {
+class COMPONENT_EXPORT(TRACING_CPP) BaseAgent : public mojom::Agent {
+ protected:
+ BaseAgent(service_manager::Connector* connector,
+ const std::string& label,
+ mojom::TraceDataType type,
+ bool supports_explicit_clock_sync);
+ ~BaseAgent() override;
+
+ private:
+ // tracing::mojom::Agent:
+ void StartTracing(const std::string& config,
+ base::TimeTicks coordinator_time,
+ const Agent::StartTracingCallback& callback) override;
+ void StopAndFlush(tracing::mojom::RecorderPtr recorder) override;
+ void RequestClockSyncMarker(
+ const std::string& sync_id,
+ const Agent::RequestClockSyncMarkerCallback& callback) override;
+ void GetCategories(const Agent::GetCategoriesCallback& callback) override;
+ void RequestBufferStatus(
+ const Agent::RequestBufferStatusCallback& callback) override;
+
+ mojo::Binding<tracing::mojom::Agent> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(BaseAgent);
+};
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_PUBLIC_CPP_BASE_AGENT_H_
diff --git a/chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent.cc b/chromium/services/tracing/public/cpp/chrome_trace_event_agent.cc
index 23025160a91..0def62c7a34 100644
--- a/chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent.cc
+++ b/chromium/services/tracing/public/cpp/chrome_trace_event_agent.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent.h"
+#include "services/tracing/public/cpp/chrome_trace_event_agent.h"
#include <string>
#include <utility>
@@ -16,8 +16,8 @@
#include "base/time/time.h"
#include "base/trace_event/trace_log.h"
#include "base/values.h"
-#include "services/resource_coordinator/public/interfaces/service_constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
+#include "services/tracing/public/mojom/constants.mojom.h"
namespace {
@@ -36,24 +36,14 @@ ChromeTraceEventAgent* ChromeTraceEventAgent::GetInstance() {
ChromeTraceEventAgent::ChromeTraceEventAgent(
service_manager::Connector* connector)
- : binding_(this), enabled_tracing_modes_(0) {
+ : BaseAgent(connector,
+ kChromeTraceEventLabel,
+ mojom::TraceDataType::ARRAY,
+ false /* supports_explicit_clock_sync */),
+ enabled_tracing_modes_(0) {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
DCHECK(!g_chrome_trace_event_agent);
g_chrome_trace_event_agent = this;
- // |connector| can be null in tests.
- if (!connector)
- return;
-
- // Connecto to the agent registry interface.
- tracing::mojom::AgentRegistryPtr agent_registry;
- connector->BindInterface(resource_coordinator::mojom::kServiceName,
- &agent_registry);
-
- mojom::AgentPtr agent;
- binding_.Bind(mojo::MakeRequest(&agent));
- agent_registry->RegisterAgent(std::move(agent), kChromeTraceEventLabel,
- mojom::TraceDataType::ARRAY,
- false /* supports_explicit_clock_sync */);
}
ChromeTraceEventAgent::~ChromeTraceEventAgent() {
@@ -103,12 +93,6 @@ void ChromeTraceEventAgent::StopAndFlush(mojom::RecorderPtr recorder) {
&ChromeTraceEventAgent::OnTraceLogFlush, base::Unretained(this)));
}
-void ChromeTraceEventAgent::RequestClockSyncMarker(
- const std::string& sync_id,
- const RequestClockSyncMarkerCallback& callback) {
- NOTREACHED() << "This agent does not support explicit clock sync";
-}
-
void ChromeTraceEventAgent::RequestBufferStatus(
const RequestBufferStatusCallback& callback) {
base::trace_event::TraceLogStatus status =
diff --git a/chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent.h b/chromium/services/tracing/public/cpp/chrome_trace_event_agent.h
index 25b33f5ebcb..f2f0c57b812 100644
--- a/chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent.h
+++ b/chromium/services/tracing/public/cpp/chrome_trace_event_agent.h
@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_TRACING_CHROME_TRACE_EVENT_AGENT_H_
-#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_TRACING_CHROME_TRACE_EVENT_AGENT_H_
+#ifndef SERVICES_TRACING_PUBLIC_CPP_CHROME_TRACE_EVENT_AGENT_H_
+#define SERVICES_TRACING_PUBLIC_CPP_CHROME_TRACE_EVENT_AGENT_H_
#include <memory>
#include <string>
#include <vector>
+#include "base/component_export.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "base/threading/thread_checker.h"
#include "base/values.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/resource_coordinator/public/cpp/resource_coordinator_export.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
+#include "services/tracing/public/cpp/base_agent.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
namespace base {
class TimeTicks;
@@ -27,8 +27,7 @@ class Connector;
namespace tracing {
-class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ChromeTraceEventAgent
- : public mojom::Agent {
+class COMPONENT_EXPORT(TRACING_CPP) ChromeTraceEventAgent : public BaseAgent {
public:
using MetadataGeneratorFunction =
base::RepeatingCallback<std::unique_ptr<base::DictionaryValue>()>;
@@ -50,9 +49,6 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ChromeTraceEventAgent
base::TimeTicks coordinator_time,
const StartTracingCallback& callback) override;
void StopAndFlush(mojom::RecorderPtr recorder) override;
- void RequestClockSyncMarker(
- const std::string& sync_id,
- const RequestClockSyncMarkerCallback& callback) override;
void RequestBufferStatus(
const RequestBufferStatusCallback& callback) override;
void GetCategories(const GetCategoriesCallback& callback) override;
@@ -60,7 +56,6 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ChromeTraceEventAgent
void OnTraceLogFlush(const scoped_refptr<base::RefCountedString>& events_str,
bool has_more_events);
- mojo::Binding<mojom::Agent> binding_;
uint8_t enabled_tracing_modes_;
mojom::RecorderPtr recorder_;
std::vector<MetadataGeneratorFunction> metadata_generator_functions_;
@@ -72,4 +67,4 @@ class SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_EXPORT ChromeTraceEventAgent
};
} // namespace tracing
-#endif // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_TRACING_CHROME_TRACE_EVENT_AGENT_H_
+#endif // SERVICES_TRACING_PUBLIC_CPP_CHROME_TRACE_EVENT_AGENT_H_
diff --git a/chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent_unittest.cc b/chromium/services/tracing/public/cpp/chrome_trace_event_agent_unittest.cc
index 2541f90be66..ab829416ce7 100644
--- a/chromium/services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent_unittest.cc
+++ b/chromium/services/tracing/public/cpp/chrome_trace_event_agent_unittest.cc
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/public/cpp/tracing/chrome_trace_event_agent.h"
+#include "services/tracing/public/cpp/chrome_trace_event_agent.h"
+
+#include <utility>
#include "base/bind.h"
#include "base/callback_forward.h"
@@ -14,7 +16,7 @@
#include "base/trace_event/trace_event.h"
#include "base/trace_event/trace_log.h"
#include "base/values.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace tracing {
@@ -26,7 +28,7 @@ const char kTestMetadataKey[] = "ChromeTraceEventAgentTestMetadata";
class MockRecorder : public mojom::Recorder {
public:
- MockRecorder(mojom::RecorderRequest request)
+ explicit MockRecorder(mojom::RecorderRequest request)
: binding_(this, std::move(request)) {
binding_.set_connection_error_handler(base::BindRepeating(
&MockRecorder::OnConnectionError, base::Unretained(this)));
diff --git a/chromium/services/tracing/public/mojom/BUILD.gn b/chromium/services/tracing/public/mojom/BUILD.gn
new file mode 100644
index 00000000000..ebfa6b95a02
--- /dev/null
+++ b/chromium/services/tracing/public/mojom/BUILD.gn
@@ -0,0 +1,22 @@
+# Copyright 2018 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("//mojo/public/tools/bindings/mojom.gni")
+
+mojom_component("mojom") {
+ output_prefix = "tracing_mojom"
+ macro_prefix = "TRACING_MOJOM"
+
+ sources = [
+ "constants.mojom",
+ "tracing.mojom",
+ ]
+
+ public_deps = [
+ "//mojo/common:common_custom_types",
+ ]
+
+ # TODO(crbug.com/714018): Convert the implementation to use OnceCallback.
+ use_once_callback = false
+}
diff --git a/chromium/services/shape_detection/public/interfaces/OWNERS b/chromium/services/tracing/public/mojom/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/shape_detection/public/interfaces/OWNERS
+++ b/chromium/services/tracing/public/mojom/OWNERS
diff --git a/chromium/services/resource_coordinator/public/interfaces/tracing/tracing_constants.mojom b/chromium/services/tracing/public/mojom/constants.mojom
index a0ca06dfb79..abf03fa664b 100644
--- a/chromium/services/resource_coordinator/public/interfaces/tracing/tracing_constants.mojom
+++ b/chromium/services/tracing/public/mojom/constants.mojom
@@ -6,6 +6,8 @@ module tracing.mojom;
const uint32 kStopTracingRetryTimeMilliseconds = 100;
+const string kServiceName = "tracing";
+
// The label of agents that provide trace data of the format explained in
// https://goo.gl/Dw8qPY.
const string kChromeTraceEventLabel = "traceEvents";
diff --git a/chromium/services/resource_coordinator/public/interfaces/tracing/tracing.mojom b/chromium/services/tracing/public/mojom/tracing.mojom
index 39a74c1a9f2..39a74c1a9f2 100644
--- a/chromium/services/resource_coordinator/public/interfaces/tracing/tracing.mojom
+++ b/chromium/services/tracing/public/mojom/tracing.mojom
diff --git a/chromium/services/resource_coordinator/tracing/recorder.cc b/chromium/services/tracing/recorder.cc
index 33b117d6beb..4c25d9cf549 100644
--- a/chromium/services/resource_coordinator/tracing/recorder.cc
+++ b/chromium/services/tracing/recorder.cc
@@ -2,11 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/tracing/recorder.h"
+#include "services/tracing/recorder.h"
+
+#include <utility>
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
namespace tracing {
diff --git a/chromium/services/resource_coordinator/tracing/recorder.h b/chromium/services/tracing/recorder.h
index 3c8baa2e42a..1178004ff50 100644
--- a/chromium/services/resource_coordinator/tracing/recorder.h
+++ b/chromium/services/tracing/recorder.h
@@ -2,8 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_RESOURCE_COORDINATOR_TRACING_RECORDER_H_
-#define SERVICES_RESOURCE_COORDINATOR_TRACING_RECORDER_H_
+#ifndef SERVICES_TRACING_RECORDER_H_
+#define SERVICES_TRACING_RECORDER_H_
+
+#include <memory>
+#include <string>
#include "base/callback_forward.h"
#include "base/logging.h"
@@ -12,7 +15,7 @@
#include "base/memory/weak_ptr.h"
#include "base/values.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
namespace tracing {
@@ -34,13 +37,9 @@ class Recorder : public mojom::Recorder {
const base::RepeatingClosure& on_data_change_callback);
~Recorder() override;
- const std::string& data() const {
- return data_;
- }
+ const std::string& data() const { return data_; }
- void clear_data() {
- data_.clear();
- }
+ void clear_data() { data_.clear(); }
const base::DictionaryValue& metadata() const { return metadata_; }
bool is_recording() const { return is_recording_; }
@@ -68,4 +67,4 @@ class Recorder : public mojom::Recorder {
};
} // namespace tracing
-#endif // SERVICES_RESOURCE_COORDINATOR_TRACING_RECORDER_H_
+#endif // SERVICES_TRACING_RECORDER_H_
diff --git a/chromium/services/resource_coordinator/tracing/recorder_unittest.cc b/chromium/services/tracing/recorder_unittest.cc
index e316153dcb4..9462477e3e2 100644
--- a/chromium/services/resource_coordinator/tracing/recorder_unittest.cc
+++ b/chromium/services/tracing/recorder_unittest.cc
@@ -2,7 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/tracing/recorder.h"
+#include "services/tracing/recorder.h"
+
+#include <utility>
#include "base/bind.h"
#include "base/callback_forward.h"
diff --git a/chromium/services/tracing/service_main.cc b/chromium/services/tracing/service_main.cc
new file mode 100644
index 00000000000..98adace3336
--- /dev/null
+++ b/chromium/services/tracing/service_main.cc
@@ -0,0 +1,12 @@
+// Copyright 2018 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/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/service_runner.h"
+#include "services/tracing/tracing_service.h"
+
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+ return service_manager::ServiceRunner(new tracing::TracingService())
+ .Run(service_request_handle);
+}
diff --git a/chromium/services/resource_coordinator/tracing/test_util.cc b/chromium/services/tracing/test_util.cc
index 5d7a8756336..e60d7cab14a 100644
--- a/chromium/services/resource_coordinator/tracing/test_util.cc
+++ b/chromium/services/tracing/test_util.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/resource_coordinator/tracing/test_util.h"
+#include "services/tracing/test_util.h"
#include <string>
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
namespace tracing {
diff --git a/chromium/services/resource_coordinator/tracing/test_util.h b/chromium/services/tracing/test_util.h
index 0e2a94baed1..082b4de47a0 100644
--- a/chromium/services/resource_coordinator/tracing/test_util.h
+++ b/chromium/services/tracing/test_util.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_RESOURCE_COORDINATOR_TRACING_TEST_UTIL_H_
-#define SERVICES_RESOURCE_COORDINATOR_TRACING_TEST_UTIL_H_
+#ifndef SERVICES_TRACING_TEST_UTIL_H_
+#define SERVICES_TRACING_TEST_UTIL_H_
#include <string>
#include <vector>
@@ -11,7 +11,7 @@
#include "base/trace_event/trace_log.h"
#include "base/values.h"
#include "mojo/public/cpp/bindings/binding.h"
-#include "services/resource_coordinator/public/interfaces/tracing/tracing.mojom.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
namespace base {
class TimeTicks;
@@ -52,4 +52,4 @@ class MockAgent : public mojom::Agent {
} // namespace tracing
-#endif // SERVICES_RESOURCE_COORDINATOR_TRACING_TEST_UTIL_H_
+#endif // SERVICES_TRACING_TEST_UTIL_H_
diff --git a/chromium/services/tracing/tracing_service.cc b/chromium/services/tracing/tracing_service.cc
new file mode 100644
index 00000000000..701ea444cda
--- /dev/null
+++ b/chromium/services/tracing/tracing_service.cc
@@ -0,0 +1,47 @@
+// Copyright 2018 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/tracing/tracing_service.h"
+
+#include <utility>
+
+#include "base/timer/timer.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/tracing/agent_registry.h"
+#include "services/tracing/coordinator.h"
+
+namespace tracing {
+
+std::unique_ptr<service_manager::Service> TracingService::Create() {
+ return std::make_unique<TracingService>();
+}
+
+TracingService::TracingService() : weak_factory_(this) {}
+
+TracingService::~TracingService() = default;
+
+void TracingService::OnStart() {
+ ref_factory_.reset(new service_manager::ServiceContextRefFactory(
+ context()->CreateQuitClosure()));
+
+ tracing_agent_registry_ = std::make_unique<AgentRegistry>(ref_factory_.get());
+ registry_.AddInterface(
+ base::BindRepeating(&AgentRegistry::BindAgentRegistryRequest,
+ base::Unretained(tracing_agent_registry_.get())));
+
+ tracing_coordinator_ = std::make_unique<Coordinator>(ref_factory_.get());
+ registry_.AddInterface(
+ base::BindRepeating(&Coordinator::BindCoordinatorRequest,
+ base::Unretained(tracing_coordinator_.get())));
+}
+
+void TracingService::OnBindInterface(
+ const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(interface_name, std::move(interface_pipe),
+ source_info);
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/tracing_service.h b/chromium/services/tracing/tracing_service.h
new file mode 100644
index 00000000000..e70a29027fa
--- /dev/null
+++ b/chromium/services/tracing/tracing_service.h
@@ -0,0 +1,58 @@
+// Copyright 2018 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 SERVICES_TRACING_TRACING_SERVICE_H_
+#define SERVICES_TRACING_TRACING_SERVICE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_context_ref.h"
+#include "services/tracing/agent_registry.h"
+#include "services/tracing/coordinator.h"
+
+namespace tracing {
+
+class TracingService : public service_manager::Service {
+ public:
+ TracingService();
+ ~TracingService() override;
+
+ // service_manager::Service:
+ // Factory function for use as an embedded service.
+ static std::unique_ptr<service_manager::Service> Create();
+
+ // service_manager::Service:
+ void OnStart() override;
+ void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
+
+ service_manager::ServiceContextRefFactory* ref_factory() {
+ return ref_factory_.get();
+ }
+
+ private:
+ service_manager::BinderRegistryWithArgs<
+ const service_manager::BindSourceInfo&>
+ registry_;
+ std::unique_ptr<tracing::AgentRegistry> tracing_agent_registry_;
+ std::unique_ptr<tracing::Coordinator> tracing_coordinator_;
+ std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
+
+ // WeakPtrFactory members should always come last so WeakPtrs are destructed
+ // before other members.
+ base::WeakPtrFactory<TracingService> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(TracingService);
+};
+
+} // namespace tracing
+
+#endif // SERVICES_TRACING_TRACING_SERVICE_H_
diff --git a/chromium/services/tracing/tracing_service_unittest.cc b/chromium/services/tracing/tracing_service_unittest.cc
new file mode 100644
index 00000000000..b71fc43ad46
--- /dev/null
+++ b/chromium/services/tracing/tracing_service_unittest.cc
@@ -0,0 +1,52 @@
+// Copyright 2018 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 <memory>
+
+#include "base/macros.h"
+#include "base/run_loop.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/service.h"
+#include "services/service_manager/public/cpp/service_test.h"
+#include "services/tracing/public/mojom/constants.mojom.h"
+#include "services/tracing/public/mojom/tracing.mojom.h"
+
+namespace tracing {
+
+class TracingServiceTest : public service_manager::test::ServiceTest {
+ public:
+ TracingServiceTest()
+ : service_manager::test::ServiceTest("tracing_unittests") {}
+ ~TracingServiceTest() override {}
+
+ protected:
+ void SetUp() override {
+ service_manager::test::ServiceTest::SetUp();
+ connector()->StartService(mojom::kServiceName);
+ }
+
+ void SetRunLoopToQuit(base::RunLoop* loop) { loop_ = loop; }
+
+ private:
+ base::RunLoop* loop_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(TracingServiceTest);
+};
+
+TEST_F(TracingServiceTest, TracingServiceInstantiate) {
+ mojom::AgentRegistryPtr agent_registry;
+ connector()->BindInterface(mojom::kServiceName,
+ mojo::MakeRequest(&agent_registry));
+
+ tracing::mojom::AgentPtr agent;
+ agent_registry->RegisterAgent(std::move(agent), "FOO",
+ mojom::TraceDataType::STRING,
+ false /*supports_explicit_clock_sync*/);
+
+ base::RunLoop loop;
+ SetRunLoopToQuit(&loop);
+ loop.Run();
+}
+
+} // namespace tracing
diff --git a/chromium/services/tracing/unittest_manifest.json b/chromium/services/tracing/unittest_manifest.json
new file mode 100644
index 00000000000..311385fd3ec
--- /dev/null
+++ b/chromium/services/tracing/unittest_manifest.json
@@ -0,0 +1,11 @@
+{
+ "name": "tracing_unittests",
+ "display_name": "Tracing Unittests",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "requires": {
+ "tracing": [ "tests" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/ui/BUILD.gn b/chromium/services/ui/BUILD.gn
index 1fc2205fc9d..db48a91a58d 100644
--- a/chromium/services/ui/BUILD.gn
+++ b/chromium/services/ui/BUILD.gn
@@ -58,7 +58,7 @@ source_set("lib") {
"//components/viz/service",
"//mojo/common:common_base",
"//services/catalog/public/cpp",
- "//services/catalog/public/interfaces:constants",
+ "//services/catalog/public/mojom:constants",
"//services/service_manager/public/cpp",
"//services/ui/clipboard:lib",
"//services/ui/ime:lib",
diff --git a/chromium/services/ui/common/BUILD.gn b/chromium/services/ui/common/BUILD.gn
index 7d179495c8f..403d4053fde 100644
--- a/chromium/services/ui/common/BUILD.gn
+++ b/chromium/services/ui/common/BUILD.gn
@@ -3,9 +3,9 @@
# found in the LICENSE file.
import("//build/config/ui.gni")
-import("//services/service_manager/public/service_manifest.gni")
import("//testing/test.gni")
+# TODO(sky): move everything but switches to services/ui/public/cpp
source_set("mus_common") {
sources = [
"accelerator_util.cc",
@@ -19,19 +19,11 @@ source_set("mus_common") {
]
deps = [
- "//gpu/command_buffer/client",
- "//gpu/config",
- "//gpu/ipc/client",
- "//gpu/ipc/common:command_buffer_traits",
- "//ipc:ipc",
- "//services/service_manager/public/cpp",
- "//ui/events:events",
+ "//ui/events",
"//ui/gfx/ipc/geometry",
]
public_deps = [
- "//mojo/public/cpp/bindings",
- "//mojo/public/cpp/system",
"//services/ui/public/interfaces",
"//ui/base",
]
diff --git a/chromium/services/ui/common/switches.cc b/chromium/services/ui/common/switches.cc
index e4e81f52c3d..35cdb6140da 100644
--- a/chromium/services/ui/common/switches.cc
+++ b/chromium/services/ui/common/switches.cc
@@ -17,9 +17,5 @@ const char kUseAsyncEventTargeting[] = "enable-async-event-targeting";
// "//services/ui/ime/test_ime_driver".
const char kUseTestConfig[] = "use-test-config";
-// WindowServer uses the viz hit-test logic (HitTestAggregator and
-// HitTestQuery).
-const char kUseVizHitTest[] = "use-viz-hit-test";
-
} // namespace switches
} // namespace ui
diff --git a/chromium/services/ui/common/switches.h b/chromium/services/ui/common/switches.h
index 2565eb76aec..85709f0e6a7 100644
--- a/chromium/services/ui/common/switches.h
+++ b/chromium/services/ui/common/switches.h
@@ -13,7 +13,6 @@ namespace switches {
// alongside the definition of their values in the .cc file.
extern const char kUseAsyncEventTargeting[];
extern const char kUseTestConfig[];
-extern const char kUseVizHitTest[];
} // namespace switches
} // namespace ui
diff --git a/chromium/services/ui/common/types.h b/chromium/services/ui/common/types.h
index dd59cb86f85..882025c24b9 100644
--- a/chromium/services/ui/common/types.h
+++ b/chromium/services/ui/common/types.h
@@ -13,12 +13,12 @@
namespace ui {
// Used to identify windows and change ids.
-typedef uint32_t Id;
+using Id = uint64_t;
// Used to identify a client as well as a client-specific window id. For
// example, the Id for a window consists of the ClientSpecificId of the client
// and the ClientSpecificId of the window.
-typedef uint16_t ClientSpecificId;
+using ClientSpecificId = uint32_t;
} // namespace ui
diff --git a/chromium/services/ui/common/util.h b/chromium/services/ui/common/util.h
index 11b4f785d38..ef03325a508 100644
--- a/chromium/services/ui/common/util.h
+++ b/chromium/services/ui/common/util.h
@@ -9,22 +9,14 @@
#include "services/ui/common/types.h"
-// TODO(beng): #$*&@#(@ MacOSX SDK!
-#if defined(HiWord)
-#undef HiWord
-#endif
-#if defined(LoWord)
-#undef LoWord
-#endif
-
namespace ui {
-inline uint16_t HiWord(uint32_t id) {
- return static_cast<uint16_t>((id >> 16) & 0xFFFF);
+inline ClientSpecificId ClientIdFromTransportId(Id id) {
+ return static_cast<ClientSpecificId>((id >> 32) & 0xFFFFFFFF);
}
-inline uint16_t LoWord(uint32_t id) {
- return static_cast<uint16_t>(id & 0xFFFF);
+inline ClientSpecificId ClientWindowIdFromTransportId(Id id) {
+ return static_cast<ClientSpecificId>(id & 0xFFFFFFFF);
}
} // namespace ui
diff --git a/chromium/services/ui/demo/BUILD.gn b/chromium/services/ui/demo/BUILD.gn
index 6b8b00412cc..0ccd4405842 100644
--- a/chromium/services/ui/demo/BUILD.gn
+++ b/chromium/services/ui/demo/BUILD.gn
@@ -89,6 +89,7 @@ source_set("tests") {
deps = [
":demo",
"//base",
+ "//base/test:test_support",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
"//services/ui/public/interfaces",
diff --git a/chromium/services/ui/demo/mus_demo_unittests.cc b/chromium/services/ui/demo/mus_demo_unittests.cc
index b2cfc99f979..d7fe8039ab0 100644
--- a/chromium/services/ui/demo/mus_demo_unittests.cc
+++ b/chromium/services/ui/demo/mus_demo_unittests.cc
@@ -2,14 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/base_switches.h"
#include "base/bind.h"
#include "base/command_line.h"
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
#include "services/service_manager/public/cpp/service_test.h"
#include "services/ui/public/interfaces/constants.mojom.h"
#include "services/ui/public/interfaces/window_server_test.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
namespace ui {
@@ -30,14 +33,16 @@ class MusDemoTest : public service_manager::test::ServiceTest {
~MusDemoTest() override {}
void SetUp() override {
+ feature_list_.InitAndEnableFeature(features::kMash);
base::CommandLine::ForCurrentProcess()->AppendSwitch("use-test-config");
- base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kMus);
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kMusHostingViz);
+ base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kEnableFeatures, features::kMash.name);
ServiceTest::SetUp();
}
private:
+ base::test::ScopedFeatureList feature_list_;
+
DISALLOW_COPY_AND_ASSIGN(MusDemoTest);
};
diff --git a/chromium/services/ui/ime/ime_unittest.cc b/chromium/services/ui/ime/ime_unittest.cc
index 062b817fc4a..ba4034146e3 100644
--- a/chromium/services/ui/ime/ime_unittest.cc
+++ b/chromium/services/ui/ime/ime_unittest.cc
@@ -33,7 +33,7 @@ class TestTextInputClient : public ui::mojom::TextInputClient {
void SetCompositionText(const ui::CompositionText& composition) override {}
void ConfirmCompositionText() override {}
void ClearCompositionText() override {}
- void InsertText(const std::string& text) override {}
+ void InsertText(const base::string16& text) override {}
void InsertChar(std::unique_ptr<ui::Event> event) override {
receieved_event_ = std::move(event);
if (run_loop_)
diff --git a/chromium/services/ui/manifest.json b/chromium/services/ui/manifest.json
index dfd2c55d476..d67213ba37a 100644
--- a/chromium/services/ui/manifest.json
+++ b/chromium/services/ui/manifest.json
@@ -54,9 +54,6 @@
"input_device_controller": [
"ui::mojom::InputDeviceController"
],
- "user_access_manager": [
- "ui::mojom::UserAccessManager"
- ],
"window_manager": [
"discardable_memory::mojom::DiscardableSharedMemoryManager",
"display::mojom::DisplayController",
diff --git a/chromium/services/ui/public/cpp/BUILD.gn b/chromium/services/ui/public/cpp/BUILD.gn
index b8903341a6a..9fee226a164 100644
--- a/chromium/services/ui/public/cpp/BUILD.gn
+++ b/chromium/services/ui/public/cpp/BUILD.gn
@@ -17,7 +17,7 @@ source_set("cpp") {
"//cc",
"//components/viz/common",
"//mojo/public/cpp/bindings",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/ui/common:mus_common",
"//services/ui/public/cpp/gpu",
"//services/ui/public/interfaces",
@@ -34,10 +34,6 @@ source_set("cpp") {
"//ui/gfx/geometry",
]
- data_deps = [
- "//services/ui",
- ]
-
defines = [ "GL_GLEXT_PROTOTYPES" ]
allow_circular_includes_from = [ ":internal" ]
@@ -62,7 +58,7 @@ source_set("internal") {
"//components/viz/common",
"//mojo/public/cpp/bindings",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/ui/common:mus_common",
"//services/ui/public/cpp/gpu",
"//services/ui/public/interfaces",
@@ -72,10 +68,6 @@ source_set("internal") {
"//ui/gfx/geometry",
]
- data_deps = [
- "//services/ui",
- ]
-
defines = [ "GL_GLEXT_PROTOTYPES" ]
if (use_ozone) {
diff --git a/chromium/services/ui/public/cpp/gpu/BUILD.gn b/chromium/services/ui/public/cpp/gpu/BUILD.gn
index d761ff6d2c1..07ecf33a01f 100644
--- a/chromium/services/ui/public/cpp/gpu/BUILD.gn
+++ b/chromium/services/ui/public/cpp/gpu/BUILD.gn
@@ -45,6 +45,7 @@ source_set("internal") {
"//gpu/command_buffer/client",
"//gpu/command_buffer/client:gles2_cmd_helper",
"//gpu/command_buffer/client:gles2_implementation",
+ "//gpu/command_buffer/client:raster",
"//gpu/skia_bindings",
"//mojo/public/cpp/system",
"//services/service_manager/public/cpp",
diff --git a/chromium/services/ui/public/cpp/gpu/command_buffer_metrics.cc b/chromium/services/ui/public/cpp/gpu/command_buffer_metrics.cc
index abf8de92921..c2934721eff 100644
--- a/chromium/services/ui/public/cpp/gpu/command_buffer_metrics.cc
+++ b/chromium/services/ui/public/cpp/gpu/command_buffer_metrics.cc
@@ -124,6 +124,7 @@ void RecordContextLost(ContextType type,
case UI_COMPOSITOR_CONTEXT:
UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.UICompositor", reason,
CONTEXT_LOST_REASON_MAX_ENUM);
+ break;
case CONTEXT_TYPE_UNKNOWN:
UMA_HISTOGRAM_ENUMERATION("GPU.ContextLost.Unknown", reason,
CONTEXT_LOST_REASON_MAX_ENUM);
diff --git a/chromium/services/ui/public/cpp/gpu/context_provider_command_buffer.cc b/chromium/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
index b3f82d16e42..6cbc49ae6db 100644
--- a/chromium/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
+++ b/chromium/services/ui/public/cpp/gpu/context_provider_command_buffer.cc
@@ -462,7 +462,8 @@ void ContextProviderCommandBuffer::SetDefaultTaskRunner(
}
base::Lock* ContextProviderCommandBuffer::GetLock() {
- DCHECK(support_locking_);
+ if (!support_locking_)
+ return nullptr;
return &context_lock_;
}
diff --git a/chromium/services/ui/public/cpp/gpu/gpu.cc b/chromium/services/ui/public/cpp/gpu/gpu.cc
index 9370d3fa80c..3b7e40e089e 100644
--- a/chromium/services/ui/public/cpp/gpu/gpu.cc
+++ b/chromium/services/ui/public/cpp/gpu/gpu.cc
@@ -12,7 +12,6 @@
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
#include "gpu/command_buffer/common/scheduling_priority.h"
-#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/ui/public/cpp/gpu/client_gpu_memory_buffer_manager.h"
#include "services/ui/public/cpp/gpu/context_provider_command_buffer.h"
diff --git a/chromium/services/ui/public/cpp/input_devices/input_device_controller.cc b/chromium/services/ui/public/cpp/input_devices/input_device_controller.cc
index 88ea54745a5..0f2075df610 100644
--- a/chromium/services/ui/public/cpp/input_devices/input_device_controller.cc
+++ b/chromium/services/ui/public/cpp/input_devices/input_device_controller.cc
@@ -21,12 +21,14 @@ InputDeviceController::InputDeviceController() = default;
InputDeviceController::~InputDeviceController() = default;
void InputDeviceController::AddInterface(
- service_manager::BinderRegistry* registry) {
+ service_manager::BinderRegistry* registry,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
// base::Unretained() is safe here as this class is tied to the life of
// Service, so that no requests should come in after this class is deleted.
registry->AddInterface<mojom::InputDeviceController>(
base::Bind(&InputDeviceController::BindInputDeviceControllerRequest,
- base::Unretained(this)));
+ base::Unretained(this)),
+ task_runner);
}
void InputDeviceController::AddKeyboardDeviceObserver(
diff --git a/chromium/services/ui/public/cpp/input_devices/input_device_controller.h b/chromium/services/ui/public/cpp/input_devices/input_device_controller.h
index bbeeaabf96e..554d944e959 100644
--- a/chromium/services/ui/public/cpp/input_devices/input_device_controller.h
+++ b/chromium/services/ui/public/cpp/input_devices/input_device_controller.h
@@ -23,7 +23,9 @@ class InputDeviceController : public mojom::InputDeviceController {
~InputDeviceController() override;
// Registers the interface provided by this class with |registry|.
- void AddInterface(service_manager::BinderRegistry* registry);
+ void AddInterface(
+ service_manager::BinderRegistry* registry,
+ const scoped_refptr<base::SequencedTaskRunner>& task_runner = nullptr);
// mojom::InputDeviceController::
void AddKeyboardDeviceObserver(
diff --git a/chromium/services/ui/public/interfaces/BUILD.gn b/chromium/services/ui/public/interfaces/BUILD.gn
index 74659883ddb..8ba4f04672d 100644
--- a/chromium/services/ui/public/interfaces/BUILD.gn
+++ b/chromium/services/ui/public/interfaces/BUILD.gn
@@ -6,8 +6,8 @@ import("//mojo/public/tools/bindings/mojom.gni")
import("//testing/test.gni")
mojom("interfaces") {
- # The window service runs in the browser process for --mus and in the
- # ash_and_ui process for --mash. Allow IPC serialization to be skipped for
+ # The window service runs in the browser process for mus and in the
+ # ash_and_ui process for mash. Allow IPC serialization to be skipped for
# the common case of in-process mojo calls. This causes a ~130KB size
# increase on 64-bit Intel builds.
if (is_chromeos) {
@@ -22,7 +22,6 @@ mojom("interfaces") {
"gpu.mojom",
"mus_constants.mojom",
"remote_event_dispatcher.mojom",
- "user_access_manager.mojom",
"user_activity_monitor.mojom",
"video_detector.mojom",
"window_manager.mojom",
diff --git a/chromium/services/ui/public/interfaces/ime/ime.mojom b/chromium/services/ui/public/interfaces/ime/ime.mojom
index 0f59599984a..582d0837d24 100644
--- a/chromium/services/ui/public/interfaces/ime/ime.mojom
+++ b/chromium/services/ui/public/interfaces/ime/ime.mojom
@@ -5,6 +5,7 @@
module ui.mojom;
import "mojo/common/text_direction.mojom";
+import "mojo/public/mojom/base/string16.mojom";
import "ui/events/mojo/event.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/range/mojo/range.mojom";
@@ -43,18 +44,18 @@ struct CandidateWindowProperties {
// Represents a candidate window entry.
struct CandidateWindowEntry {
// Value of the candidate.
- string value;
+ mojo_base.mojom.String16 value;
// Short string displayed next to the candidate, often the shortcut key or
// index.
- string label;
+ mojo_base.mojom.String16 label;
// Additional text describing the candidate.
- string annotation;
+ mojo_base.mojom.String16 annotation;
// The usage or detailed description of the candidate.
- string description_title;
- string description_body;
+ mojo_base.mojom.String16 description_title;
+ mojo_base.mojom.String16 description_body;
};
// See comments for ui::ImeTextSpan::Type for more details.
@@ -80,7 +81,7 @@ struct ImeTextSpan {
// Represents a text currently being composed by IME. Corresponds to
// ui::CompositionText.
struct CompositionText {
- string text;
+ mojo_base.mojom.String16 text;
array<ImeTextSpan> ime_text_spans;
gfx.mojom.Range selection;
};
@@ -163,7 +164,7 @@ interface TextInputClient {
// Inserts a given text at the insertion point. Current composition text or
// selection will be removed. This method should never be called when the
// current text input type is TEXT_INPUT_TYPE_NONE.
- InsertText(string text);
+ InsertText(mojo_base.mojom.String16 text);
// Inserts a single character at the insertion point. Unlike InsertText(),
// the character is not processed. See ui::TextInputClient::InsertChar()
diff --git a/chromium/services/ui/public/interfaces/ime/ime_struct_traits.cc b/chromium/services/ui/public/interfaces/ime/ime_struct_traits.cc
index 0a44597183d..de4d4b43caa 100644
--- a/chromium/services/ui/public/interfaces/ime/ime_struct_traits.cc
+++ b/chromium/services/ui/public/interfaces/ime/ime_struct_traits.cc
@@ -4,6 +4,7 @@
#include "services/ui/public/interfaces/ime/ime_struct_traits.h"
+#include "mojo/public/cpp/base/string16_mojom_traits.h"
#include "ui/gfx/range/mojo/range_struct_traits.h"
namespace mojo {
diff --git a/chromium/services/ui/public/interfaces/ime/ime_struct_traits.h b/chromium/services/ui/public/interfaces/ime/ime_struct_traits.h
index 42214de8702..1d942afa2b2 100644
--- a/chromium/services/ui/public/interfaces/ime/ime_struct_traits.h
+++ b/chromium/services/ui/public/interfaces/ime/ime_struct_traits.h
@@ -5,7 +5,6 @@
#ifndef SERVICES_UI_PUBLIC_INTERFACES_IME_IME_STRUCT_TRAITS_H_
#define SERVICES_UI_PUBLIC_INTERFACES_IME_IME_STRUCT_TRAITS_H_
-#include "base/strings/utf_string_conversions.h"
#include "services/ui/public/interfaces/ime/ime.mojom-shared.h"
#include "ui/base/ime/candidate_window.h"
#include "ui/base/ime/composition_text.h"
@@ -54,20 +53,20 @@ struct StructTraits<ui::mojom::CandidateWindowPropertiesDataView,
template <>
struct StructTraits<ui::mojom::CandidateWindowEntryDataView,
ui::CandidateWindow::Entry> {
- static std::string value(const ui::CandidateWindow::Entry& e) {
- return base::UTF16ToUTF8(e.value);
+ static base::string16 value(const ui::CandidateWindow::Entry& e) {
+ return e.value;
}
- static std::string label(const ui::CandidateWindow::Entry& e) {
- return base::UTF16ToUTF8(e.label);
+ static base::string16 label(const ui::CandidateWindow::Entry& e) {
+ return e.label;
}
- static std::string annotation(const ui::CandidateWindow::Entry& e) {
- return base::UTF16ToUTF8(e.annotation);
+ static base::string16 annotation(const ui::CandidateWindow::Entry& e) {
+ return e.annotation;
}
- static std::string description_title(const ui::CandidateWindow::Entry& e) {
- return base::UTF16ToUTF8(e.description_title);
+ static base::string16 description_title(const ui::CandidateWindow::Entry& e) {
+ return e.description_title;
}
- static std::string description_body(const ui::CandidateWindow::Entry& e) {
- return base::UTF16ToUTF8(e.description_body);
+ static base::string16 description_body(const ui::CandidateWindow::Entry& e) {
+ return e.description_body;
}
static bool Read(ui::mojom::CandidateWindowEntryDataView data,
ui::CandidateWindow::Entry* out);
@@ -75,9 +74,7 @@ struct StructTraits<ui::mojom::CandidateWindowEntryDataView,
template <>
struct StructTraits<ui::mojom::CompositionTextDataView, ui::CompositionText> {
- static std::string text(const ui::CompositionText& c) {
- return base::UTF16ToUTF8(c.text);
- }
+ static base::string16 text(const ui::CompositionText& c) { return c.text; }
static ui::ImeTextSpans ime_text_spans(const ui::CompositionText& c) {
return c.ime_text_spans;
}
diff --git a/chromium/services/ui/public/interfaces/ime/ime_struct_traits_unittest.cc b/chromium/services/ui/public/interfaces/ime/ime_struct_traits_unittest.cc
index 812ed1a6e9f..06846e29bb5 100644
--- a/chromium/services/ui/public/interfaces/ime/ime_struct_traits_unittest.cc
+++ b/chromium/services/ui/public/interfaces/ime/ime_struct_traits_unittest.cc
@@ -8,6 +8,7 @@
#include "base/message_loop/message_loop.h"
#include "base/strings/utf_string_conversions.h"
+#include "mojo/public/cpp/base/string16_mojom_traits.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/ui/public/interfaces/ime/ime_struct_traits_test.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/services/ui/public/interfaces/user_access_manager.mojom b/chromium/services/ui/public/interfaces/user_access_manager.mojom
deleted file mode 100644
index 94ec5bb5f86..00000000000
--- a/chromium/services/ui/public/interfaces/user_access_manager.mojom
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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.
-
-module ui.mojom;
-
-// Used to change the active user.
-interface UserAccessManager {
- // Sets the active user. By default the root user is the active user.
- SetActiveUser(string user_id);
-};
diff --git a/chromium/services/ui/public/interfaces/window_manager.mojom b/chromium/services/ui/public/interfaces/window_manager.mojom
index 4b0c4b6a7ca..cba2ae56ef9 100644
--- a/chromium/services/ui/public/interfaces/window_manager.mojom
+++ b/chromium/services/ui/public/interfaces/window_manager.mojom
@@ -139,7 +139,7 @@ interface WindowManager {
// Type: gfx::Rect.
const string kRestoreBounds_Property = "prop:restore-bounds";
- // See ShadowElevation for details. Type: wm::ShadowElevation.
+ // See ShadowController for details. Type: int32_t.
const string kShadowElevation_Property = "prop:shadow-elevation";
// The serialized shelf id. Maps to ash::kShelfIDKey. Type: mojom::String.
@@ -153,6 +153,10 @@ interface WindowManager {
// Type: ShowState.
const string kShowState_Property = "prop:show-state";
+ // The window corner radius in DIPs. Maps to
+ // aura::client::kWindowCornerRadiusKey. Type: int.
+ const string kWindowCornerRadius_Property = "prop:window-corner-radius";
+
// The window icon; typically 16x16 for titlebars. Type: SkBitmap
const string kWindowIcon_Property = "prop:window-icon";
@@ -189,14 +193,14 @@ interface WindowManager {
// When the WindowManager completes a request it must call back to
// WindowManagerClient::WmResponse().
- WmSetBounds(uint32 change_id, uint32 window_id, gfx.mojom.Rect bounds);
+ WmSetBounds(uint32 change_id, uint64 window_id, gfx.mojom.Rect bounds);
WmSetProperty(uint32 change_id,
- uint32 window_id,
+ uint64 window_id,
string name,
array<uint8>? value);
- WmSetModalType(uint32 window_id, ModalType type);
- WmSetCanFocus(uint32 window_id, bool can_focus);
+ WmSetModalType(uint64 window_id, ModalType type);
+ WmSetCanFocus(uint64 window_id, bool can_focus);
// Asks the WindowManager to create a new window.
// |frame_sink_id| is the FrameSinkId for the new window. Window manager
@@ -209,7 +213,7 @@ interface WindowManager {
// events within a reasonable timeframe. When a client enters or exits this
// state, Mus will tell the window manager about it so that the window manager
// can update the UI for the janky windows.
- WmClientJankinessChanged(uint16 client_id, bool janky);
+ WmClientJankinessChanged(uint32 client_id, bool janky);
// Asks the WindowManager to create a drag representation window: a window
// which contains a single image representation.
@@ -231,7 +235,7 @@ interface WindowManager {
// Asks the WindowManager to interactively move the window. This will return
// whether this completed successfully or not through the client's
// OnWmMoveLoopCompleted().
- WmPerformMoveLoop(uint32 change_id, uint32 window_id,
+ WmPerformMoveLoop(uint32 change_id, uint64 window_id,
MoveLoopSource source,
gfx.mojom.Point cursor_location);
@@ -240,17 +244,17 @@ interface WindowManager {
// Asks the WindowManager to change the activation from the current window
// to the next. The window manager may completely ignore this message.
- WmDeactivateWindow(uint32 window_id);
+ WmDeactivateWindow(uint64 window_id);
// Asks the WindowMangaer to stack |above_id| in front of |below_id|.
- WmStackAbove(uint32 change_id, uint32 above_id, uint32 below_id);
+ WmStackAbove(uint32 change_id, uint64 above_id, uint64 below_id);
// Asks the WindowManager to stack |window_id| as the first child of its
// window manager owned parent.
- WmStackAtTop(uint32 change_id, uint32 window_id);
+ WmStackAtTop(uint32 change_id, uint64 window_id);
// Asks the WindowManager to perform |action| on |window_id|.
- WmPerformWmAction(uint32 window_id, string action);
+ WmPerformWmAction(uint64 window_id, string action);
// An accelerator registered via AddAccelerator() has been triggered. If
// |ack_id| is non-zero the accelerator matches a PRE_TARGET and must be
@@ -263,7 +267,7 @@ interface WindowManager {
// Called when a pointer down event occurs on a window and the event is
// blocked by a modal window.
- OnEventBlockedByModalWindow(uint32 window_id);
+ OnEventBlockedByModalWindow(uint64 window_id);
};
struct WmAccelerator {
@@ -275,14 +279,14 @@ struct WmAccelerator {
// with WindowTree.
interface WindowManagerClient {
// Enables (or disables) child windows of |window_id| to be activated.
- AddActivationParent(uint32 window_id);
- RemoveActivationParent(uint32 window_id);
+ AddActivationParent(uint64 window_id);
+ RemoveActivationParent(uint64 window_id);
// Extends the hit area for children of |window_id| by the specified amount.
// |mouse_insets| is used for mouse events, and |touch_insets| for touch
// events. NOTE: the insets are expected to be negative (or zero). If one
// of the sizes of an inset is a positive value the call is ignored.
- SetExtendedHitRegionForChildren(uint32 window_id,
+ SetExtendedHitRegionForChildren(uint64 window_id,
gfx.mojom.Insets mouse_insets,
gfx.mojom.Insets touch_insets);
@@ -315,7 +319,7 @@ interface WindowManagerClient {
SetDisplayRoot(display.mojom.Display display,
WmViewportMetrics viewport_metrics,
bool is_primary_display,
- uint32 window_id,
+ uint64 window_id,
array<display.mojom.Display> mirrors) => (bool success);
// Configures metrics for the displays and notifies observers. This is only
@@ -350,14 +354,14 @@ interface WindowManagerClient {
// Calls WindowTreeClient::RequestClose() on the embedded app at the
// specified window.
- WmRequestClose(uint32 window_id);
+ WmRequestClose(uint64 window_id);
// Sets the frame decoration constants of the display the window manager is
// associated with.
WmSetFrameDecorationValues(FrameDecorationValues values);
// Sets the cursor that the non-client areas of the window should use.
- WmSetNonClientCursor(uint32 window_id, CursorData cursor);
+ WmSetNonClientCursor(uint64 window_id, CursorData cursor);
// Locks and unlocks the cursor globally. Used during window management tasks
// where the cursor shouldn't change.
@@ -388,7 +392,7 @@ interface WindowManagerClient {
// Response from WmCreateTopLevelWindow() informing the client of the id for
// the new window.
- OnWmCreatedTopLevelWindow(uint32 change_id, uint32 window_id);
+ OnWmCreatedTopLevelWindow(uint32 change_id, uint64 window_id);
// See description in WindowManager::OnAccelerator(). |ack_id| is the value
// that was passed to OnAccelerator(). If the accelerator is a pre-target
diff --git a/chromium/services/ui/public/interfaces/window_manager_constants.mojom b/chromium/services/ui/public/interfaces/window_manager_constants.mojom
index fd5a8a80a25..1e301db4cca 100644
--- a/chromium/services/ui/public/interfaces/window_manager_constants.mojom
+++ b/chromium/services/ui/public/interfaces/window_manager_constants.mojom
@@ -84,10 +84,10 @@ struct BlockingContainers {
// system modal window in this container, then only events targetted at the
// system modal window or one if its descendants (including transient windows)
// are delivered. All others are eaten.
- uint32 system_modal_container_id;
+ uint64 system_modal_container_id;
// If there is no system modal window in |system_modal_container_id|, and
// this identifies a valid window, then events that fall behind
// |min_container_id| are ignored.
- uint32 min_container_id;
+ uint64 min_container_id;
};
diff --git a/chromium/services/ui/public/interfaces/window_tree.mojom b/chromium/services/ui/public/interfaces/window_tree.mojom
index f4652318b11..69e161ff9f0 100644
--- a/chromium/services/ui/public/interfaces/window_tree.mojom
+++ b/chromium/services/ui/public/interfaces/window_tree.mojom
@@ -23,11 +23,11 @@ import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/gfx/mojo/transform.mojom";
import "ui/platform_window/mojo/text_input_state.mojom";
-// Windows are identified by a uint32. The upper 16 bits are the connection id,
-// and the lower 16 the id assigned by the client. If it's a window created by
-// the client this WindowTree is associated with, the upper 16 bits are 0;
-// otherwise the upper 16 bits are the id of the WindowTree associated with the
-// other client that created this window.
+// Windows are identified by a uint64. The upper 32 bits are the id assigned to
+// the client by the Window Service, and the lower 32 an id assigned by the
+// client. Windows created by the client supply a client id of 0, which the
+// Window Service maps appropriately. For clients that see Windows created by
+// another client, the upper 32 bits are set to identify the other client.
//
// The root window is identified with a connection id of 0, and value of 1.
//
@@ -62,7 +62,7 @@ interface WindowTree {
// ERROR_CODE_ILLEGAL_ARGUMENT: The connection part of |window_id| does not
// match the connection id of the client.
NewWindow(uint32 change_id,
- uint32 window_id,
+ uint64 window_id,
map<string, array<uint8>>? properties);
// Requests the WindowManager to create a new top level window. On success
@@ -70,7 +70,7 @@ interface WindowTree {
// failure OnChangeCompleted() is called.
// TODO(sky): this likely needs context, maybe in |properties|.
NewTopLevelWindow(uint32 change_id,
- uint32 window_id,
+ uint64 window_id,
map<string, array<uint8>> properties);
// Deletes a window. This does not recurse. No hierarchy change notifications
@@ -79,7 +79,7 @@ interface WindowTree {
// embed root from the client. When DeleteWindow() is used to remove an embed
// root, the client no longer has access to the embed root. The embedder of
// the root is notified of the change via OnEmbeddedAppDisconnected().
- DeleteWindow(uint32 change_id, uint32 window_id);
+ DeleteWindow(uint32 change_id, uint64 window_id);
// Requests input event capture for the given |window_id|. Capture is only
// allowed if the window is processing an event. When a window gains capture,
@@ -88,11 +88,11 @@ interface WindowTree {
// ReleaseCapture is called for |window_id|. OnCaptureChanged() is called to
// notify of capture changing (as long as the client did not initiate the
// change).
- SetCapture(uint32 change_id, uint32 window_id);
+ SetCapture(uint32 change_id, uint64 window_id);
// Releases input event capture for the given |window_id|. This does nothing
// if |window_id| does not currently have capture.
- ReleaseCapture(uint32 change_id, uint32 window_id);
+ ReleaseCapture(uint32 change_id, uint64 window_id);
// Starts the pointer watcher that monitors pointer events (up/down events if
// |wants_moves| is false, up/down and move if |wants_moves| is true), even if
@@ -112,49 +112,51 @@ interface WindowTree {
// Sets the specified bounds of the specified window. The window will paint
// the frame in the provided |local_frame_id|, if any.
- SetWindowBounds(uint32 change_id, uint32 window_id, gfx.mojom.Rect bounds,
+ SetWindowBounds(uint32 change_id,
+ uint64 window_id,
+ gfx.mojom.Rect bounds,
viz.mojom.LocalSurfaceId? local_surface_id);
SetWindowTransform(uint32 change_id,
- uint32 window_id,
+ uint64 window_id,
gfx.mojom.Transform transform);
// Sets the client area of the specified window. The client area is specified
// by way of insets. Everything outside of the insets, and not in
// |additional_client_areas| is considered non-client area.
// TODO(sky): convert additional_client_areas to a path.
- SetClientArea(uint32 window_id,
+ SetClientArea(uint64 window_id,
gfx.mojom.Insets insets,
array<gfx.mojom.Rect>? additional_client_areas);
// Mouse events outside a hit test mask do not hit the window. The |mask| is
// in window local coordinates. Pass null to clear the mask.
// TODO(jamescook): Convert |mask| to a path. http://crbug.com/613210
- SetHitTestMask(uint32 window_id, gfx.mojom.Rect? mask);
+ SetHitTestMask(uint64 window_id, gfx.mojom.Rect? mask);
// Called by clients that want to accept drag and drops. Windows default to
// this being disabled; a window must actively opt-in to receiving OnDrag*()
// calls.
- SetCanAcceptDrops(uint32 window_id, bool accepts_drops);
+ SetCanAcceptDrops(uint64 window_id, bool accepts_drops);
// Sets the visibility of the specified window to |visible|. Connections are
// allowed to change the visibility of any window they have created, as well
// as any of their roots.
- SetWindowVisibility(uint32 change_id, uint32 window_id, bool visible);
+ SetWindowVisibility(uint32 change_id, uint64 window_id, bool visible);
// Sets an individual named property. Setting an individual property to null
// deletes the property.
SetWindowProperty(uint32 change_id,
- uint32 window_id,
+ uint64 window_id,
string name,
array<uint8>? value);
// Sets the opacity of the specified window to |opacity|.
- SetWindowOpacity(uint32 change_id, uint32 window_id, float opacity);
+ SetWindowOpacity(uint32 change_id, uint64 window_id, float opacity);
// Attaches a CompositorFrameSink to a particular window.
AttachCompositorFrameSink(
- uint32 window_id,
+ uint64 window_id,
viz.mojom.CompositorFrameSink& compositor_frame_sink,
viz.mojom.CompositorFrameSinkClient client);
@@ -166,7 +168,7 @@ interface WindowTree {
//
// This may result in a connection getting OnWindowDeleted(). See
// RemoveWindowFromParent for details.
- AddWindow(uint32 change_id, uint32 parent, uint32 child);
+ AddWindow(uint32 change_id, uint64 parent, uint64 child);
// Removes a window from its current parent. This fails if the window is not
// valid or the window already has no parent.
@@ -176,7 +178,7 @@ interface WindowTree {
// a child of 1. Connection B has a root 1. If 2 is removed from 1 then B gets
// OnWindowDeleted(). This is done as window 2 is effectively no longer
// visible to connection B.
- RemoveWindowFromParent(uint32 change_id, uint32 window_id);
+ RemoveWindowFromParent(uint32 change_id, uint64 window_id);
// Ties the lifetime of |transient_window_id| to the lifetime of |window_id|.
// This also places |transient_window_id| on top of |window_id|.
@@ -185,38 +187,38 @@ interface WindowTree {
// . |transient_window_id| is an ancestor of |window_id|.
// . |transient_window_id| is modal to system.
AddTransientWindow(uint32 change_id,
- uint32 window_id,
- uint32 transient_window_id);
+ uint64 window_id,
+ uint64 transient_window_id);
// Decouples the lifetime of |transient_window_id| from its transient parent.
// This does not change transient window's position in the window hierarchy.
- RemoveTransientWindowFromParent(uint32 change_id, uint32 transient_window_id);
+ RemoveTransientWindowFromParent(uint32 change_id, uint64 transient_window_id);
// Changes modality type of |window_id|. This releases capture if necessary.
// This fails for any of the following reasons:
// . |window_id| does not identify a valid window.
// . Client does not have a valid user id (i.e., it is an embedded app).
- SetModalType(uint32 change_id, uint32 window_id, ModalType type);
+ SetModalType(uint32 change_id, uint64 window_id, ModalType type);
// Sets the modal parent of a CHILD_MODAL window. This is the modal parent of
// the window, which is not necessarily the same as the parent of the window.
SetChildModalParent(uint32 change_id,
- uint32 window_id,
- uint32 parent_window_id);
+ uint64 window_id,
+ uint64 parent_window_id);
// Reorders a window in its parent, relative to |relative_window_id| according
// to |direction|. Only the connection that created the window's parent can
// reorder its children.
ReorderWindow(uint32 change_id,
- uint32 window_id,
- uint32 relative_window_id,
+ uint64 window_id,
+ uint64 relative_window_id,
OrderDirection direction);
// Returns the windows comprising the tree starting at |window_id|.
// |window_id| is the first result in the return value, unless |window_id| is
// invalid, in which case an empty vector is returned. The windows are visited
// using a depth first search (pre-order).
- GetWindowTree(uint32 window_id) => (array<WindowData> windows);
+ GetWindowTree(uint64 window_id) => (array<WindowData> windows);
// A connection may grant access to another connection by way of Embed().
// Embed() results in the supplied WindowTreeClient being configured with a
@@ -245,7 +247,7 @@ interface WindowTree {
// OnEmbeddedAppDisconnected().
//
// The callback returns whether the embedding was successful.
- Embed(uint32 window_id, WindowTreeClient client, uint32 embed_flags)
+ Embed(uint64 window_id, WindowTreeClient client, uint32 embed_flags)
=> (bool success);
// Schedules a future call to Embed() using the returned token. This is used
@@ -261,7 +263,7 @@ interface WindowTree {
// that client B may call EmbedUsingToken().
ScheduleEmbed(WindowTreeClient client)
=> (mojo.common.mojom.UnguessableToken token);
- EmbedUsingToken(uint32 window_id,
+ EmbedUsingToken(uint64 window_id,
mojo.common.mojom.UnguessableToken token,
uint32 embed_flags)
=> (bool success);
@@ -271,43 +273,43 @@ interface WindowTree {
// been marked as focusable (see SetCanFocus()) and the window is in a
// container the WindowManager has identified as allowing activation
// (see WindowManagerClient::AddActivationParent()).
- SetFocus(uint32 change_id, uint32 window_id);
+ SetFocus(uint32 change_id, uint64 window_id);
// Marks the specified window as being able to receive focus.
- SetCanFocus(uint32 window_id, bool can_focus);
+ SetCanFocus(uint64 window_id, bool can_focus);
// Sets the cursor when the pointer is inside |window_id|.
- SetCursor(uint32 change_id, uint32 window_id, CursorData cursor);
+ SetCursor(uint32 change_id, uint64 window_id, CursorData cursor);
// TODO(erg): Additional cursor methods. Visibility, and cursor locking.
// Set text input state for the given window.
- SetWindowTextInputState(uint32 window_id, TextInputState state);
+ SetWindowTextInputState(uint64 window_id, TextInputState state);
// Set the input method editor UI (software keyboard, etc) visibility.
// If state is non-null, the specified window's text input state is updated.
// Otherwise the existing state is used.
- SetImeVisibility(uint32 window_id, bool visible, TextInputState? state);
+ SetImeVisibility(uint64 window_id, bool visible, TextInputState? state);
// Sets the EventTargetingPolicy. See EventTargetingPolicy for details.
- SetEventTargetingPolicy(uint32 window_id, EventTargetingPolicy policy);
+ SetEventTargetingPolicy(uint64 window_id, EventTargetingPolicy policy);
// See documentation for WindowTreeClient::OnWindowInputEvent().
OnWindowInputEventAck(uint32 event_id, EventResult result);
// If the current focus is (or is a child of) |window_id|, requests that the
// window manager change the focus to the next activatable window.
- DeactivateWindow(uint32 window_id);
+ DeactivateWindow(uint64 window_id);
// Stacks the window |above_id| above |below_id|. These two windows must
// share the same parent.
- StackAbove(uint32 change_id, uint32 above_id, uint32 below_id);
+ StackAbove(uint32 change_id, uint64 above_id, uint64 below_id);
// Stacks the window above all sibling windows.
- StackAtTop(uint32 change_id, uint32 window_id);
+ StackAtTop(uint32 change_id, uint64 window_id);
// Tells the window manager to perform |string_action| for |window_id|.
- PerformWmAction(uint32 window_id, string action);
+ PerformWmAction(uint64 window_id, string action);
// See description of WindowManager for details.
GetWindowManagerClient(associated WindowManagerClient& internal);
@@ -321,12 +323,12 @@ interface WindowTree {
// called on whether the move was canceled. Because there's a delay between
// when a client sends this message and when the window manager starts acting
// on it, pass the cursor location at the start of the move.
- PerformWindowMove(uint32 change_id, uint32 window_id, MoveLoopSource source,
+ PerformWindowMove(uint32 change_id, uint64 window_id, MoveLoopSource source,
gfx.mojom.Point cursor);
// Tells the window manager to cancel any in progress window move started with
// StartWindowMove() and to revert the window bounds to how they were.
- CancelWindowMove(uint32 window_id);
+ CancelWindowMove(uint64 window_id);
// Called by the client to start a drag operation. |source_window_id| is the
// source window, |screen_location| is what the source thinks their location
@@ -339,7 +341,7 @@ interface WindowTree {
// TODO(erg): SkBitmap is the wrong data type for the drag image; we should
// be passing ImageSkias once http://crbug.com/655874 is implemented.
PerformDragDrop(uint32 change_id,
- uint32 source_window_id,
+ uint64 source_window_id,
gfx.mojom.Point screen_location,
map<string, array<uint8>> drag_data,
skia.mojom.Bitmap? drag_image,
@@ -349,7 +351,7 @@ interface WindowTree {
// Called by the client to cancel any in progress drag drop operation. This
// will result in a change completed for the underlying change.
- CancelDragDrop(uint32 window_id);
+ CancelDragDrop(uint64 window_id);
};
// Changes to windows are not sent to the connection that originated the
@@ -367,7 +369,7 @@ interface WindowTreeClient {
OnEmbed(WindowData root,
WindowTree? tree,
int64 display_id,
- uint32 focused_window,
+ uint64 focused_window,
bool parent_drawn,
viz.mojom.LocalSurfaceId? local_surface_id);
@@ -375,20 +377,20 @@ interface WindowTreeClient {
// words the embedded app closes the connection to the server. This is called
// on the connection that created |window| as well as any ancestors that have
// the embed root policy.
- OnEmbeddedAppDisconnected(uint32 window);
+ OnEmbeddedAppDisconnected(uint64 window);
// Sent when another connection is embedded in the Window this connection was
// previously embedded in. See Embed() for more information.
- OnUnembed(uint32 window);
+ OnUnembed(uint64 window);
// Sent when capture changes. This is not sent if the client initiated the
// change.
- OnCaptureChanged(uint32 new_capture, uint32 old_capture);
+ OnCaptureChanged(uint64 new_capture, uint64 old_capture);
// This is called on the owner of a window when it embeds a client in it,
// which includes the window manager creating a new window at the request of
// another client.
- OnFrameSinkIdAllocated(uint32 window, viz.mojom.FrameSinkId frame_sink_id);
+ OnFrameSinkIdAllocated(uint64 window, viz.mojom.FrameSinkId frame_sink_id);
// Called in response to NewTopLevelWindow() successfully completing.
// |parent_drawn| is true if the parent of the window is drawn, see
@@ -403,24 +405,24 @@ interface WindowTreeClient {
// Invoked when a window's bounds have changed. Only the client embedded in
// |window| gets a non_empty |local_surface_id|.
- OnWindowBoundsChanged(uint32 window,
+ OnWindowBoundsChanged(uint64 window,
gfx.mojom.Rect old_bounds,
gfx.mojom.Rect new_bounds,
viz.mojom.LocalSurfaceId? local_surface_id);
- OnWindowTransformChanged(uint32 window,
+ OnWindowTransformChanged(uint64 window,
gfx.mojom.Transform old_transform,
gfx.mojom.Transform new_transform);
- OnClientAreaChanged(uint32 window_id,
+ OnClientAreaChanged(uint64 window_id,
gfx.mojom.Insets new_client_area,
array<gfx.mojom.Rect> new_additional_client_areas);
- OnTransientWindowAdded(uint32 window_id,
- uint32 transient_window_id);
+ OnTransientWindowAdded(uint64 window_id,
+ uint64 transient_window_id);
- OnTransientWindowRemoved(uint32 window_id,
- uint32 transient_window_id);
+ OnTransientWindowRemoved(uint64 window_id,
+ uint64 transient_window_id);
// Invoked when a change is done to the hierarchy. A value of 0 is used to
// identify a null window. For example, if the old_parent is NULL, 0 is
@@ -432,24 +434,24 @@ interface WindowTreeClient {
// the parent was previously not visible to this client.
// This is not sent for hierarchy changes of windows not known to this client
// or not attached to the tree.
- OnWindowHierarchyChanged(uint32 window,
- uint32 old_parent,
- uint32 new_parent,
+ OnWindowHierarchyChanged(uint64 window,
+ uint64 old_parent,
+ uint64 new_parent,
array<WindowData> windows);
// Invoked when the order of windows within a parent changes.
- OnWindowReordered(uint32 window_id,
- uint32 relative_window_id,
+ OnWindowReordered(uint64 window_id,
+ uint64 relative_window_id,
OrderDirection direction);
// Invoked when a window is deleted.
- OnWindowDeleted(uint32 window);
+ OnWindowDeleted(uint64 window);
// Invoked when the visibility of the specified window changes.
- OnWindowVisibilityChanged(uint32 window, bool visible);
+ OnWindowVisibilityChanged(uint64 window, bool visible);
// Invoked when the opacity of the specified window has changed.
- OnWindowOpacityChanged(uint32 window, float old_opacity, float new_opacity);
+ OnWindowOpacityChanged(uint64 window, float old_opacity, float new_opacity);
// Invoked when the drawn state of |window|'s parent changes. The drawn state
// is determined by the visibility of a Window and the Windows ancestors. A
@@ -461,11 +463,11 @@ interface WindowTreeClient {
//
// This function is only called for root Windows as the drawn state of all
// other windows can be determined from their parent.
- OnWindowParentDrawnStateChanged(uint32 window, bool drawn);
+ OnWindowParentDrawnStateChanged(uint64 window, bool drawn);
// Invoked when a window property is changed. If this change is a removal,
// |new_data| is null.
- OnWindowSharedPropertyChanged(uint32 window,
+ OnWindowSharedPropertyChanged(uint64 window,
string name,
array<uint8>? new_data);
@@ -480,9 +482,9 @@ interface WindowTreeClient {
// TODO(sky): remove |event_location_in_screen_pixel_layout| temporary until
// http://crbug.com/747465 is fixed.
OnWindowInputEvent(uint32 event_id,
- uint32 window,
+ uint64 window,
int64 display_id,
- uint32 display_root_window,
+ uint64 display_root_window,
gfx.mojom.PointF event_location_in_screen_pixel_layout,
ui.mojom.Event event,
bool matches_pointer_watcher);
@@ -493,7 +495,7 @@ interface WindowTreeClient {
// event target, or 0 if the window is not known to this client. The
// client should not acknowledge these events.
OnPointerEventObserved(ui.mojom.Event event,
- uint32 window_id,
+ uint64 window_id,
int64 display_id);
// Called in two distinct cases: when a window known to the connection gains
@@ -501,9 +503,9 @@ interface WindowTreeClient {
// window not known to the connection. In the later case |focused_window_id|
// is 0. As with other functions this is only called if the client did not
// initiate the change.
- OnWindowFocused(uint32 focused_window_id);
+ OnWindowFocused(uint64 focused_window_id);
- OnWindowCursorChanged(uint32 window_id, CursorData cursor);
+ OnWindowCursorChanged(uint64 window_id, CursorData cursor);
// Invoked when a client window submits a new surface ID. The surface ID and
// associated information is propagated to the parent connection. The parent
@@ -511,7 +513,7 @@ interface WindowTreeClient {
// frame_size and device_scale_factor in a layer.
// TODO(fsamuel): Surface IDs should be passed to parents directly instead of
// going through the window server. http://crbug.com/655231
- OnWindowSurfaceChanged(uint32 window_id,
+ OnWindowSurfaceChanged(uint64 window_id,
viz.mojom.SurfaceInfo surface_info);
// Called when the mouse cursor enters a window on this connection for the
@@ -524,7 +526,7 @@ interface WindowTreeClient {
// accepting drags through SetAcceptsDrags(), providing a list
// of available mime types. Returns a bitmask of the supported
// operations. |screen_position| is in screen coordinates.
- OnDragEnter(uint32 window,
+ OnDragEnter(uint64 window,
uint32 key_state,
gfx.mojom.Point screen_position,
uint32 effect_bitmask) => (uint32 supported_op_bitmask);
@@ -532,25 +534,27 @@ interface WindowTreeClient {
// Called when the pointer moves over the window after the initial
// DragEnter. Returns a bitmask of the supported operations at this
// location. |screen_position| is in screen coordinates.
- OnDragOver(uint32 window,
+ OnDragOver(uint64 window,
uint32 key_state,
gfx.mojom.Point screen_position,
uint32 effect_bitmask) => (uint32 supported_op_bitmask);
// Called when the pointer leaves a window or if the drop is
// canceled.
- OnDragLeave(uint32 window);
+ OnDragLeave(uint64 window);
// Called when the drop occurs on a window. Returns the action
// taken. |screen_position| is in screen coordinates.
- OnCompleteDrop(uint32 window,
+ OnCompleteDrop(uint64 window,
uint32 key_state,
gfx.mojom.Point screen_position,
uint32 effect_bitmask) => (uint32 action_taken);
// Called on the client that requested PerformDragDrop() to return which drag
// action was completed. This is called instead of OnChangeCompleted().
- OnPerformDragDropCompleted(uint32 window, bool success, uint32 action_taken);
+ OnPerformDragDropCompleted(uint32 change_id,
+ bool success,
+ uint32 action_taken);
// Called after OnCompleteDrop completes for every connection which received
// an OnDragDropStart() message. This signals that a client can forget the
@@ -563,7 +567,7 @@ interface WindowTreeClient {
// The WindowManager is requesting the specified window to close. If the
// client allows the change it should delete the window.
- RequestClose(uint32 window_id);
+ RequestClose(uint64 window_id);
// See description of WindowManager for details.
GetWindowManager(associated WindowManager& internal);
diff --git a/chromium/services/ui/public/interfaces/window_tree_constants.mojom b/chromium/services/ui/public/interfaces/window_tree_constants.mojom
index 2aec5c9e686..4070a257ae0 100644
--- a/chromium/services/ui/public/interfaces/window_tree_constants.mojom
+++ b/chromium/services/ui/public/interfaces/window_tree_constants.mojom
@@ -10,13 +10,13 @@ import "ui/gfx/geometry/mojo/geometry.mojom";
struct WindowData {
// Unique identifier of the parent. If the client can not see the parent an
// id of 0 is supplied.
- uint32 parent_id;
+ uint64 parent_id;
// Unique identifier of the window.
- uint32 window_id;
+ uint64 window_id;
// Id of the transient parent, 0 if there isn't one.
- uint32 transient_parent_id;
+ uint64 transient_parent_id;
gfx.mojom.Rect bounds;
diff --git a/chromium/services/ui/service.cc b/chromium/services/ui/service.cc
index 270c58c3246..c428ef26ddd 100644
--- a/chromium/services/ui/service.cc
+++ b/chromium/services/ui/service.cc
@@ -16,7 +16,7 @@
#include "components/discardable_memory/service/discardable_shared_memory_manager.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/catalog/public/cpp/resource_loader.h"
-#include "services/catalog/public/interfaces/constants.mojom.h"
+#include "services/catalog/public/mojom/constants.mojom.h"
#include "services/service_manager/public/c/main.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service_context.h"
@@ -59,7 +59,10 @@
#include "services/ui/display/screen_manager_forwarding.h"
#include "ui/events/ozone/layout/keyboard_layout_engine.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
+#include "ui/gfx/client_native_pixmap_factory.h"
+#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/ozone_switches.h"
#endif
#if defined(OS_CHROMEOS)
@@ -124,12 +127,6 @@ struct Service::PendingRequest {
std::unique_ptr<mojom::DisplayManagerRequest> dm_request;
};
-struct Service::UserState {
- std::unique_ptr<clipboard::ClipboardImpl> clipboard;
- std::unique_ptr<ws::AccessibilityManager> accessibility;
- std::unique_ptr<ws::WindowTreeHostFactory> window_tree_host_factory;
-};
-
Service::InitParams::InitParams() = default;
Service::InitParams::~InitParams() = default;
@@ -198,21 +195,6 @@ bool Service::InitializeResources(service_manager::Connector* connector) {
return true;
}
-Service::UserState* Service::GetUserState(
- const service_manager::Identity& remote_identity) {
- const ws::UserId& user_id = remote_identity.user_id();
- auto it = user_id_to_user_state_.find(user_id);
- if (it != user_id_to_user_state_.end())
- return it->second.get();
- user_id_to_user_state_[user_id] = base::WrapUnique(new UserState);
- return user_id_to_user_state_[user_id].get();
-}
-
-void Service::AddUserIfNecessary(
- const service_manager::Identity& remote_identity) {
- window_server_->user_id_tracker()->AddUserId(remote_identity.user_id());
-}
-
void Service::OnStart() {
base::PlatformThread::SetName("mus");
TRACE_EVENT0("mus", "Service::Initialize started");
@@ -242,9 +224,13 @@ void Service::OnStart() {
if (should_host_viz_) {
// If mus is hosting viz, then it needs to set up ozone so that it can
// connect to the gpu service through the connector.
+ // Currently mus hosting viz (i.e. mash mode) only runs single-process.
params.connector = context()->connector();
- // TODO(crbug.com/620927): This should be false once ozone-mojo is done.
params.single_process = true;
+ params.using_mojo = true;
+ } else {
+ params.using_mojo = base::CommandLine::ForCurrentProcess()->HasSwitch(
+ ::switches::kEnableDrmMojo);
}
ui::OzonePlatform::InitializeForUI(params);
@@ -252,12 +238,7 @@ void Service::OnStart() {
ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()
->SetCurrentLayoutByName("us");
- if (running_standalone_) {
- client_native_pixmap_factory_ = ui::CreateClientNativePixmapFactoryOzone();
- gfx::ClientNativePixmapFactory::SetInstance(
- client_native_pixmap_factory_.get());
- }
-
+ ui::CreateClientNativePixmapFactoryOzone();
DCHECK(gfx::ClientNativePixmapFactory::GetInstance());
#endif
@@ -275,11 +256,19 @@ void Service::OnStart() {
// so keep this line below both of those.
input_device_server_.RegisterAsObserver();
- window_server_ = base::MakeUnique<ws::WindowServer>(this, should_host_viz_);
+ if (!discardable_shared_memory_manager_) {
+ owned_discardable_shared_memory_manager_ =
+ std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
+ discardable_shared_memory_manager_ =
+ owned_discardable_shared_memory_manager_.get();
+ }
+
+ window_server_ = std::make_unique<ws::WindowServer>(this, should_host_viz_);
if (should_host_viz_) {
std::unique_ptr<ws::GpuHost> gpu_host =
- base::MakeUnique<ws::DefaultGpuHost>(window_server_.get(),
- context()->connector());
+ std::make_unique<ws::DefaultGpuHost>(
+ window_server_.get(), context()->connector(),
+ discardable_shared_memory_manager_);
window_server_->SetGpuHost(std::move(gpu_host));
registry_.AddInterface<mojom::Gpu>(
@@ -294,12 +283,6 @@ void Service::OnStart() {
ime_driver_.Init(context()->connector(), test_config_);
- if (!discardable_shared_memory_manager_) {
- owned_discardable_shared_memory_manager_ =
- std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
- discardable_shared_memory_manager_ =
- owned_discardable_shared_memory_manager_.get();
- }
registry_with_source_info_.AddInterface<mojom::AccessibilityManager>(
base::Bind(&Service::BindAccessibilityManagerRequest,
base::Unretained(this)));
@@ -311,8 +294,6 @@ void Service::OnStart() {
base::Bind(&Service::BindIMERegistrarRequest, base::Unretained(this)));
registry_.AddInterface<mojom::IMEDriver>(
base::Bind(&Service::BindIMEDriverRequest, base::Unretained(this)));
- registry_.AddInterface<mojom::UserAccessManager>(base::Bind(
- &Service::BindUserAccessManagerRequest, base::Unretained(this)));
registry_with_source_info_.AddInterface<mojom::UserActivityMonitor>(
base::Bind(&Service::BindUserActivityMonitorRequest,
base::Unretained(this)));
@@ -383,7 +364,7 @@ void Service::OnNoMoreDisplays() {
return;
DCHECK(context());
- context()->RequestQuit();
+ context()->CreateQuitClosure().Run();
}
bool Service::IsTestConfig() const {
@@ -429,22 +410,19 @@ ws::ThreadedImageCursorsFactory* Service::GetThreadedImageCursorsFactory() {
void Service::BindAccessibilityManagerRequest(
mojom::AccessibilityManagerRequest request,
const service_manager::BindSourceInfo& source_info) {
- UserState* user_state = GetUserState(source_info.identity);
- if (!user_state->accessibility) {
- const ws::UserId& user_id = source_info.identity.user_id();
- user_state->accessibility.reset(
- new ws::AccessibilityManager(window_server_.get(), user_id));
+ if (!accessibility_) {
+ accessibility_ =
+ std::make_unique<ws::AccessibilityManager>(window_server_.get());
}
- user_state->accessibility->Bind(std::move(request));
+ accessibility_->Bind(std::move(request));
}
void Service::BindClipboardRequest(
mojom::ClipboardRequest request,
const service_manager::BindSourceInfo& source_info) {
- UserState* user_state = GetUserState(source_info.identity);
- if (!user_state->clipboard)
- user_state->clipboard.reset(new clipboard::ClipboardImpl);
- user_state->clipboard->AddBinding(std::move(request));
+ if (!clipboard_)
+ clipboard_ = std::make_unique<clipboard::ClipboardImpl>();
+ clipboard_->AddBinding(std::move(request));
}
void Service::BindDisplayManagerRequest(
@@ -461,7 +439,7 @@ void Service::BindDisplayManagerRequest(
return;
}
window_server_->display_manager()
- ->GetUserDisplayManager(source_info.identity.user_id())
+ ->GetUserDisplayManager()
->AddDisplayManagerBinding(std::move(request));
}
@@ -477,32 +455,21 @@ void Service::BindIMEDriverRequest(mojom::IMEDriverRequest request) {
ime_driver_.AddBinding(std::move(request));
}
-void Service::BindUserAccessManagerRequest(
- mojom::UserAccessManagerRequest request) {
- window_server_->user_id_tracker()->Bind(std::move(request));
-}
-
void Service::BindUserActivityMonitorRequest(
mojom::UserActivityMonitorRequest request,
const service_manager::BindSourceInfo& source_info) {
- AddUserIfNecessary(source_info.identity);
- const ws::UserId& user_id = source_info.identity.user_id();
- window_server_->GetUserActivityMonitorForUser(user_id)->Add(
- std::move(request));
+ window_server_->user_activity_monitor()->Add(std::move(request));
}
void Service::BindWindowManagerWindowTreeFactoryRequest(
mojom::WindowManagerWindowTreeFactoryRequest request,
const service_manager::BindSourceInfo& source_info) {
- AddUserIfNecessary(source_info.identity);
- window_server_->window_manager_window_tree_factory_set()->Add(
- source_info.identity.user_id(), std::move(request));
+ window_server_->BindWindowManagerWindowTreeFactory(std::move(request));
}
void Service::BindWindowTreeFactoryRequest(
mojom::WindowTreeFactoryRequest request,
const service_manager::BindSourceInfo& source_info) {
- AddUserIfNecessary(source_info.identity);
if (!window_server_->display_manager()->IsReady()) {
std::unique_ptr<PendingRequest> pending_request(new PendingRequest);
pending_request->source_info = source_info;
@@ -511,10 +478,8 @@ void Service::BindWindowTreeFactoryRequest(
pending_requests_.push_back(std::move(pending_request));
return;
}
- AddUserIfNecessary(source_info.identity);
mojo::MakeStrongBinding(
std::make_unique<ws::WindowTreeFactory>(window_server_.get(),
- source_info.identity.user_id(),
source_info.identity.name()),
std::move(request));
}
@@ -522,12 +487,11 @@ void Service::BindWindowTreeFactoryRequest(
void Service::BindWindowTreeHostFactoryRequest(
mojom::WindowTreeHostFactoryRequest request,
const service_manager::BindSourceInfo& source_info) {
- UserState* user_state = GetUserState(source_info.identity);
- if (!user_state->window_tree_host_factory) {
- user_state->window_tree_host_factory.reset(new ws::WindowTreeHostFactory(
- window_server_.get(), source_info.identity.user_id()));
+ if (!window_tree_host_factory_) {
+ window_tree_host_factory_ =
+ std::make_unique<ws::WindowTreeHostFactory>(window_server_.get());
}
- user_state->window_tree_host_factory->AddBinding(std::move(request));
+ window_tree_host_factory_->AddBinding(std::move(request));
}
void Service::BindDiscardableSharedMemoryManagerRequest(
diff --git a/chromium/services/ui/service.h b/chromium/services/ui/service.h
index 4544987b6eb..b772807ac13 100644
--- a/chromium/services/ui/service.h
+++ b/chromium/services/ui/service.h
@@ -29,20 +29,14 @@
#include "services/ui/public/interfaces/gpu.mojom.h"
#include "services/ui/public/interfaces/ime/ime.mojom.h"
#include "services/ui/public/interfaces/remote_event_dispatcher.mojom.h"
-#include "services/ui/public/interfaces/user_access_manager.mojom.h"
#include "services/ui/public/interfaces/user_activity_monitor.mojom.h"
#include "services/ui/public/interfaces/video_detector.mojom.h"
#include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom.h"
#include "services/ui/public/interfaces/window_server_test.mojom.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "services/ui/public/interfaces/window_tree_host_factory.mojom.h"
-#include "services/ui/ws/user_id.h"
#include "services/ui/ws/window_server_delegate.h"
-#if defined(USE_OZONE)
-#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
-#endif
-
#if defined(OS_CHROMEOS)
#include "services/ui/public/interfaces/arc.mojom.h"
#endif // defined(OS_CHROMEOS)
@@ -66,9 +60,15 @@ class ImageCursorsSet;
class InputDeviceController;
class PlatformEventSource;
+namespace clipboard {
+class ClipboardImpl;
+}
+
namespace ws {
+class AccessibilityManager;
class ThreadedImageCursorsFactory;
class WindowServer;
+class WindowTreeHostFactory;
}
class Service : public service_manager::Service,
@@ -106,20 +106,11 @@ class Service : public service_manager::Service,
// Holds InterfaceRequests received before the first WindowTreeHost Display
// has been established.
struct PendingRequest;
- struct UserState;
-
- using UserIdToUserState = std::map<ws::UserId, std::unique_ptr<UserState>>;
// Attempts to initialize the resource bundle. Returns true if successful,
// otherwise false if resources cannot be loaded.
bool InitializeResources(service_manager::Connector* connector);
- // Returns the user specific state for the user id of |remote_identity|.
- // Service owns the return value.
- // TODO(sky): if we allow removal of user ids then we need to close anything
- // associated with the user (all incoming pipes...) on removal.
- UserState* GetUserState(const service_manager::Identity& remote_identity);
-
void AddUserIfNecessary(const service_manager::Identity& remote_identity);
// service_manager::Service:
@@ -154,8 +145,6 @@ class Service : public service_manager::Service,
void BindIMEDriverRequest(mojom::IMEDriverRequest request);
- void BindUserAccessManagerRequest(mojom::UserAccessManagerRequest request);
-
void BindUserActivityMonitorRequest(
mojom::UserActivityMonitorRequest request,
const service_manager::BindSourceInfo& source_info);
@@ -192,8 +181,6 @@ class Service : public service_manager::Service,
using PendingRequests = std::vector<std::unique_ptr<PendingRequest>>;
PendingRequests pending_requests_;
- UserIdToUserState user_id_to_user_state_;
-
// Provides input-device information via Mojo IPC. Registers Mojo interfaces
// and must outlive |registry_|.
InputDeviceServer input_device_server_;
@@ -207,10 +194,6 @@ class Service : public service_manager::Service,
bool test_config_;
-#if defined(USE_OZONE)
- std::unique_ptr<gfx::ClientNativePixmapFactory> client_native_pixmap_factory_;
-#endif
-
#if defined(OS_CHROMEOS)
std::unique_ptr<InputDeviceController> input_device_controller_;
#endif
@@ -242,6 +225,10 @@ class Service : public service_manager::Service,
bool in_destructor_ = false;
+ std::unique_ptr<clipboard::ClipboardImpl> clipboard_;
+ std::unique_ptr<ws::AccessibilityManager> accessibility_;
+ std::unique_ptr<ws::WindowTreeHostFactory> window_tree_host_factory_;
+
DISALLOW_COPY_AND_ASSIGN(Service);
};
diff --git a/chromium/services/ui/ws/BUILD.gn b/chromium/services/ui/ws/BUILD.gn
index 7b5ffbc8620..b4897ad2137 100644
--- a/chromium/services/ui/ws/BUILD.gn
+++ b/chromium/services/ui/ws/BUILD.gn
@@ -91,10 +91,6 @@ static_library("lib") {
"user_display_manager.cc",
"user_display_manager.h",
"user_display_manager_delegate.h",
- "user_id.h",
- "user_id_tracker.cc",
- "user_id_tracker.h",
- "user_id_tracker_observer.h",
"video_detector_impl.cc",
"video_detector_impl.h",
"window_coordinate_conversions.cc",
@@ -109,9 +105,7 @@ static_library("lib") {
"window_manager_state.h",
"window_manager_window_tree_factory.cc",
"window_manager_window_tree_factory.h",
- "window_manager_window_tree_factory_set.cc",
- "window_manager_window_tree_factory_set.h",
- "window_manager_window_tree_factory_set_observer.h",
+ "window_manager_window_tree_factory_observer.h",
"window_server.cc",
"window_server.h",
"window_server_delegate.cc",
@@ -127,6 +121,7 @@ static_library("lib") {
]
deps = [
+ "//components/discardable_memory/service",
"//components/viz/service/main", # TODO(sad): Temporary until GPU process split.
"//gpu/command_buffer/client",
"//gpu/command_buffer/client:gles2_interface",
@@ -144,7 +139,7 @@ static_library("lib") {
"//mojo/common:common_base",
"//mojo/public/cpp/bindings",
"//services/service_manager/public/cpp",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/ui/common:mus_common",
"//services/ui/display",
"//services/ui/public/interfaces",
@@ -224,6 +219,7 @@ static_library("test_support") {
deps = [
"//base",
"//base/test:test_config",
+ "//base/test:test_support",
"//components/viz/test:test_support",
"//mojo/common",
"//mojo/public/cpp/bindings:bindings",
@@ -297,13 +293,14 @@ source_set("tests") {
"//base/test:test_support",
"//cc:cc",
"//cc:test_support",
+ "//components/discardable_memory/service",
"//components/viz/service/main",
"//components/viz/test:test_support",
"//gpu/ipc/client",
"//mojo/public/cpp/bindings:bindings",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
- "//services/service_manager/public/interfaces",
+ "//services/service_manager/public/mojom",
"//services/ui/common:mus_common",
"//services/ui/common:task_runner_test_base",
"//services/ui/public/cpp",
@@ -320,6 +317,10 @@ source_set("tests") {
"//ui/gl",
"//ui/gl/init",
]
+
+ data_deps = [
+ "//services/ui",
+ ]
}
service_manifest("unittests_manifest") {
diff --git a/chromium/services/ui/ws/access_policy_delegate.h b/chromium/services/ui/ws/access_policy_delegate.h
index 42056ef588e..378995dc4a0 100644
--- a/chromium/services/ui/ws/access_policy_delegate.h
+++ b/chromium/services/ui/ws/access_policy_delegate.h
@@ -5,13 +5,7 @@
#ifndef SERVICES_UI_WS_ACCESS_POLICY_DELEGATE_H_
#define SERVICES_UI_WS_ACCESS_POLICY_DELEGATE_H_
-#include <vector>
-
-#include "base/containers/hash_tables.h"
-#include "services/ui/ws/ids.h"
-
namespace ui {
-
namespace ws {
class ServerWindow;
@@ -43,7 +37,6 @@ class AccessPolicyDelegate {
};
} // namespace ws
-
} // namespace ui
#endif // SERVICES_UI_WS_ACCESS_POLICY_DELEGATE_H_
diff --git a/chromium/services/ui/ws/accessibility_manager.cc b/chromium/services/ui/ws/accessibility_manager.cc
index 3b934bb4a89..02d8781f275 100644
--- a/chromium/services/ui/ws/accessibility_manager.cc
+++ b/chromium/services/ui/ws/accessibility_manager.cc
@@ -9,9 +9,8 @@
namespace ui {
namespace ws {
-AccessibilityManager::AccessibilityManager(WindowServer* window_server,
- const UserId& user)
- : window_server_(window_server), user_(user), binding_(this) {
+AccessibilityManager::AccessibilityManager(WindowServer* window_server)
+ : window_server_(window_server), binding_(this) {
DCHECK(window_server_);
}
@@ -23,7 +22,7 @@ void AccessibilityManager::Bind(mojom::AccessibilityManagerRequest request) {
}
void AccessibilityManager::SetHighContrastMode(bool enabled) {
- window_server_->SetHighContrastMode(user_, enabled);
+ window_server_->SetHighContrastMode(enabled);
}
} // namespace ws
diff --git a/chromium/services/ui/ws/accessibility_manager.h b/chromium/services/ui/ws/accessibility_manager.h
index aaf8992f2f7..a4d65b3f310 100644
--- a/chromium/services/ui/ws/accessibility_manager.h
+++ b/chromium/services/ui/ws/accessibility_manager.h
@@ -7,7 +7,6 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/ui/public/interfaces/accessibility_manager.mojom.h"
-#include "services/ui/ws/user_id.h"
namespace ui {
namespace ws {
@@ -16,7 +15,7 @@ class WindowServer;
class AccessibilityManager : public mojom::AccessibilityManager {
public:
- AccessibilityManager(WindowServer* window_server, const UserId& user);
+ explicit AccessibilityManager(WindowServer* window_server);
~AccessibilityManager() override;
void Bind(mojom::AccessibilityManagerRequest request);
@@ -26,7 +25,6 @@ class AccessibilityManager : public mojom::AccessibilityManager {
void SetHighContrastMode(bool enabled) override;
WindowServer* window_server_;
- const UserId user_;
mojo::Binding<mojom::AccessibilityManager> binding_;
DISALLOW_COPY_AND_ASSIGN(AccessibilityManager);
diff --git a/chromium/services/ui/ws/compositor_frame_sink_client_binding.cc b/chromium/services/ui/ws/compositor_frame_sink_client_binding.cc
index 79441f9e324..0c29658c9a7 100644
--- a/chromium/services/ui/ws/compositor_frame_sink_client_binding.cc
+++ b/chromium/services/ui/ws/compositor_frame_sink_client_binding.cc
@@ -42,5 +42,16 @@ void CompositorFrameSinkClientBinding::DidNotProduceFrame(
compositor_frame_sink_->DidNotProduceFrame(ack);
}
+void CompositorFrameSinkClientBinding::DidAllocateSharedBitmap(
+ mojo::ScopedSharedBufferHandle buffer,
+ const viz::SharedBitmapId& id) {
+ compositor_frame_sink_->DidAllocateSharedBitmap(std::move(buffer), id);
+}
+
+void CompositorFrameSinkClientBinding::DidDeleteSharedBitmap(
+ const viz::SharedBitmapId& id) {
+ compositor_frame_sink_->DidDeleteSharedBitmap(id);
+}
+
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/compositor_frame_sink_client_binding.h b/chromium/services/ui/ws/compositor_frame_sink_client_binding.h
index 0719d33d454..348fe011246 100644
--- a/chromium/services/ui/ws/compositor_frame_sink_client_binding.h
+++ b/chromium/services/ui/ws/compositor_frame_sink_client_binding.h
@@ -37,6 +37,9 @@ class CompositorFrameSinkClientBinding
void SetNeedsBeginFrame(bool needs_begin_frame) override;
void SetWantsAnimateOnlyBeginFrames() override;
void DidNotProduceFrame(const viz::BeginFrameAck& ack) override;
+ void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
+ const viz::SharedBitmapId& id) override;
+ void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override;
mojo::Binding<viz::mojom::CompositorFrameSinkClient> binding_;
viz::mojom::DisplayPrivateAssociatedPtr display_private_;
diff --git a/chromium/services/ui/ws/cursor_state_unittest.cc b/chromium/services/ui/ws/cursor_state_unittest.cc
index 7fcffeb5b8b..3f8f076468a 100644
--- a/chromium/services/ui/ws/cursor_state_unittest.cc
+++ b/chromium/services/ui/ws/cursor_state_unittest.cc
@@ -14,11 +14,6 @@
namespace ui {
namespace ws {
namespace test {
-namespace {
-
-const UserId kTestId1 = "2";
-
-} // namespace
class CursorStateTest : public testing::Test, public CursorStateDelegate {
public:
@@ -40,10 +35,9 @@ class CursorStateTest : public testing::Test, public CursorStateDelegate {
// testing::Test:
void SetUp() override {
screen_manager_.Init(window_server()->display_manager());
- window_server()->user_id_tracker()->AddUserId(kTestId1);
cursor_state_ = std::make_unique<CursorState>(display_manager(), this);
- AddWindowManager(window_server(), kTestId1);
+ AddWindowManager(window_server());
screen_manager().AddDisplay(MakeDisplay(0, 0, 1024, 768, 1.0f));
ASSERT_EQ(1u, display_manager()->displays().size());
}
diff --git a/chromium/services/ui/ws/cursor_unittest.cc b/chromium/services/ui/ws/cursor_unittest.cc
index 5b8c34ed42a..ad52a6f1ccb 100644
--- a/chromium/services/ui/ws/cursor_unittest.cc
+++ b/chromium/services/ui/ws/cursor_unittest.cc
@@ -32,8 +32,6 @@ namespace ui {
namespace ws {
namespace test {
-const UserId kTestId1 = "20";
-
class CursorTest : public testing::Test {
public:
CursorTest() {}
@@ -52,19 +50,13 @@ class CursorTest : public testing::Test {
void SetUp() override {
screen_manager_.Init(window_server()->display_manager());
screen_manager_.AddDisplay();
-
- // As a side effect, this allocates Displays.
- AddWindowManager(window_server(), kTestId1);
- window_server()->user_id_tracker()->AddUserId(kTestId1);
- window_server()->user_id_tracker()->SetActiveUserId(kTestId1);
+ AddWindowManager(window_server());
}
ServerWindow* GetRoot() {
DisplayManager* display_manager = window_server()->display_manager();
- // ASSERT_EQ(1u, display_manager->displays().size());
Display* display = *display_manager->displays().begin();
- return display->GetWindowManagerDisplayRootForUser(kTestId1)
- ->GetClientVisibleRoot();
+ return display->window_manager_display_root()->GetClientVisibleRoot();
}
// Create a 30x30 window where the outer 10 pixels is non-client.
@@ -72,7 +64,7 @@ class CursorTest : public testing::Test {
DisplayManager* display_manager = window_server()->display_manager();
Display* display = *display_manager->displays().begin();
WindowManagerDisplayRoot* active_display_root =
- display->GetActiveWindowManagerDisplayRoot();
+ display->window_manager_display_root();
WindowTree* tree =
active_display_root->window_manager_state()->window_tree();
ClientWindowId child_window_id;
@@ -92,7 +84,7 @@ class CursorTest : public testing::Test {
ASSERT_EQ(1u, display_manager->displays().size());
Display* display = *display_manager->displays().begin();
WindowManagerDisplayRoot* active_display_root =
- display->GetActiveWindowManagerDisplayRoot();
+ display->window_manager_display_root();
ASSERT_TRUE(active_display_root);
PointerEvent event(
MouseEvent(ET_MOUSE_MOVED, p, p, base::TimeTicks(), 0, 0));
diff --git a/chromium/services/ui/ws/debug_utils.cc b/chromium/services/ui/ws/debug_utils.cc
index 351b41610cb..a617aaf653c 100644
--- a/chromium/services/ui/ws/debug_utils.cc
+++ b/chromium/services/ui/ws/debug_utils.cc
@@ -10,7 +10,7 @@ namespace ui {
namespace ws {
std::string DebugWindowId(const ServerWindow* window) {
- return window ? window->id().ToString() : "null";
+ return window ? window->frame_sink_id().ToString() : "null";
}
} // namespace ws
diff --git a/chromium/services/ui/ws/default_access_policy.cc b/chromium/services/ui/ws/default_access_policy.cc
index a8eda1153de..9d0c7a90fa5 100644
--- a/chromium/services/ui/ws/default_access_policy.cc
+++ b/chromium/services/ui/ws/default_access_policy.cc
@@ -266,7 +266,7 @@ bool DefaultAccessPolicy::CanSetWindowManager() const {
bool DefaultAccessPolicy::WasCreatedByThisClient(
const ServerWindow* window) const {
- return window->id().client_id == client_id_;
+ return window->owning_tree_id() == client_id_;
}
bool DefaultAccessPolicy::IsValidIdForNewWindow(
diff --git a/chromium/services/ui/ws/display.cc b/chromium/services/ui/ws/display.cc
index 04a0d4d4ee8..8e6cecdd713 100644
--- a/chromium/services/ui/ws/display.cc
+++ b/chromium/services/ui/ws/display.cc
@@ -10,7 +10,7 @@
#include "base/memory/ptr_util.h"
#include "base/strings/utf_string_conversions.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/ui/common/types.h"
#include "services/ui/display/viewport_metrics.h"
#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
@@ -38,30 +38,27 @@ namespace ui {
namespace ws {
Display::Display(WindowServer* window_server) : window_server_(window_server) {
- window_server_->window_manager_window_tree_factory_set()->AddObserver(this);
- window_server_->user_id_tracker()->AddObserver(this);
+ window_server_->window_manager_window_tree_factory()->AddObserver(this);
}
Display::~Display() {
- window_server_->user_id_tracker()->RemoveObserver(this);
+ window_server_->window_manager_window_tree_factory()->RemoveObserver(this);
- window_server_->window_manager_window_tree_factory_set()->RemoveObserver(
- this);
-
- if (!focus_controller_) {
+ if (focus_controller_) {
focus_controller_->RemoveObserver(this);
focus_controller_.reset();
}
if (!binding_) {
- for (auto& pair : window_manager_display_root_map_)
- pair.second->window_manager_state()->OnDisplayDestroying(this);
- } else if (!window_manager_display_root_map_.empty()) {
+ if (window_manager_display_root_) {
+ window_manager_display_root_->window_manager_state()->OnDisplayDestroying(
+ this);
+ }
+ } else if (window_manager_display_root_) {
// If there is a |binding_| then the tree was created specifically for this
// display (which corresponds to a WindowTreeHost).
- window_server_->DestroyTree(window_manager_display_root_map_.begin()
- ->second->window_manager_state()
- ->window_tree());
+ window_server_->DestroyTree(
+ window_manager_display_root_->window_manager_state()->window_tree());
}
}
@@ -82,17 +79,14 @@ void Display::InitWindowManagerDisplayRoots() {
if (binding_) {
std::unique_ptr<WindowManagerDisplayRoot> display_root_ptr(
new WindowManagerDisplayRoot(this));
+ window_manager_display_root_ = display_root_ptr.get();
WindowManagerDisplayRoot* display_root = display_root_ptr.get();
- // For this case we never create additional displays roots, so any
- // id works.
- window_manager_display_root_map_[service_manager::mojom::kRootUserID] =
- display_root_ptr.get();
WindowTree* window_tree = binding_->CreateWindowTree(display_root->root());
display_root->window_manager_state_ = window_tree->window_manager_state();
window_tree->window_manager_state()->AddWindowManagerDisplayRoot(
std::move(display_root_ptr));
} else {
- CreateWindowManagerDisplayRootsFromFactories();
+ CreateWindowManagerDisplayRootFromFactory();
}
display_manager()->OnDisplayUpdated(display_);
}
@@ -129,36 +123,12 @@ gfx::Size Display::GetSize() const {
return root_->bounds().size();
}
-ServerWindow* Display::GetRootWithId(const WindowId& id) {
- if (id == root_->id())
- return root_.get();
- for (auto& pair : window_manager_display_root_map_) {
- if (pair.second->root()->id() == id)
- return pair.second->root();
- }
- return nullptr;
-}
-
WindowManagerDisplayRoot* Display::GetWindowManagerDisplayRootWithRoot(
const ServerWindow* window) {
- for (auto& pair : window_manager_display_root_map_) {
- if (pair.second->root() == window)
- return pair.second;
- }
- return nullptr;
-}
-
-const WindowManagerDisplayRoot* Display::GetWindowManagerDisplayRootForUser(
- const UserId& user_id) const {
- auto iter = window_manager_display_root_map_.find(user_id);
- return iter == window_manager_display_root_map_.end() ? nullptr
- : iter->second;
-}
-
-const WindowManagerDisplayRoot* Display::GetActiveWindowManagerDisplayRoot()
- const {
- return GetWindowManagerDisplayRootForUser(
- window_server_->user_id_tracker()->active_id());
+ return (window_manager_display_root_ &&
+ window_manager_display_root_->root() == window)
+ ? window_manager_display_root_
+ : nullptr;
}
bool Display::SetFocusedWindow(ServerWindow* new_focused_window) {
@@ -191,27 +161,18 @@ void Display::SetImeVisibility(ServerWindow* window, bool visible) {
}
void Display::OnWillDestroyTree(WindowTree* tree) {
- for (auto it = window_manager_display_root_map_.begin();
- it != window_manager_display_root_map_.end(); ++it) {
- if (it->second->window_manager_state()->window_tree() == tree) {
- window_manager_display_root_map_.erase(it);
- break;
- }
+ if (window_manager_display_root_ &&
+ window_manager_display_root_->window_manager_state()->window_tree() ==
+ tree) {
+ window_manager_display_root_ = nullptr;
}
}
void Display::RemoveWindowManagerDisplayRoot(
WindowManagerDisplayRoot* display_root) {
- for (auto it = window_manager_display_root_map_.begin();
- it != window_manager_display_root_map_.end(); ++it) {
- if (it->second == display_root) {
- window_manager_display_root_map_.erase(it);
- if (window_manager_display_root_map_.empty())
- display_manager()->DestroyDisplay(this);
- return;
- }
- }
- NOTREACHED();
+ DCHECK_EQ(window_manager_display_root_, display_root);
+ window_manager_display_root_ = nullptr;
+ display_manager()->DestroyDisplay(this);
}
void Display::SetNativeCursor(const ui::CursorData& cursor) {
@@ -230,29 +191,21 @@ void Display::SetTitle(const std::string& title) {
platform_display_->SetTitle(base::UTF8ToUTF16(title));
}
-void Display::CreateWindowManagerDisplayRootsFromFactories() {
- std::vector<WindowManagerWindowTreeFactory*> factories =
- window_server_->window_manager_window_tree_factory_set()->GetFactories();
- for (WindowManagerWindowTreeFactory* factory : factories) {
- if (factory->window_tree())
- CreateWindowManagerDisplayRootFromFactory(factory);
- }
-}
+void Display::CreateWindowManagerDisplayRootFromFactory() {
+ WindowManagerWindowTreeFactory* factory =
+ window_server_->window_manager_window_tree_factory();
+ if (!factory->window_tree())
+ return;
-void Display::CreateWindowManagerDisplayRootFromFactory(
- WindowManagerWindowTreeFactory* factory) {
- std::unique_ptr<WindowManagerDisplayRoot> display_root_ptr(
- new WindowManagerDisplayRoot(this));
- WindowManagerDisplayRoot* display_root = display_root_ptr.get();
- window_manager_display_root_map_[factory->user_id()] = display_root_ptr.get();
+ std::unique_ptr<WindowManagerDisplayRoot> display_root_ptr =
+ std::make_unique<WindowManagerDisplayRoot>(this);
+ window_manager_display_root_ = display_root_ptr.get();
WindowManagerState* window_manager_state =
factory->window_tree()->window_manager_state();
- display_root->window_manager_state_ = window_manager_state;
- const bool is_active =
- factory->user_id() == window_server_->user_id_tracker()->active_id();
- display_root->root()->SetVisible(is_active);
+ window_manager_display_root_->window_manager_state_ = window_manager_state;
+ window_manager_display_root_->root()->SetVisible(true);
window_manager_state->window_tree()->AddRootForWindowManager(
- display_root->root());
+ window_manager_display_root_->root());
window_manager_state->AddWindowManagerDisplayRoot(
std::move(display_root_ptr));
}
@@ -260,9 +213,9 @@ void Display::CreateWindowManagerDisplayRootFromFactory(
void Display::CreateRootWindow(const gfx::Size& size) {
DCHECK(!root_);
- WindowId id = display_manager()->GetAndAdvanceNextRootId();
- ClientWindowId client_window_id(id.client_id, id.window_id);
- root_.reset(window_server_->CreateServerWindow(id, client_window_id,
+ const ClientWindowId client_window_id =
+ display_manager()->GetAndAdvanceNextRootId();
+ root_.reset(window_server_->CreateServerWindow(client_window_id,
ServerWindow::Properties()));
root_->set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
@@ -296,9 +249,10 @@ void Display::OnAcceleratedWidgetAvailable() {
}
void Display::OnNativeCaptureLost() {
- WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
- if (display_root)
- display_root->window_manager_state()->SetCapture(nullptr, kInvalidClientId);
+ if (window_manager_display_root_) {
+ window_manager_display_root_->window_manager_state()->SetCapture(
+ nullptr, kInvalidClientId);
+ }
}
OzonePlatform* Display::GetOzonePlatform() {
@@ -326,14 +280,15 @@ void Display::SetBoundsInPixels(const gfx::Rect& bounds_in_pixels) {
gfx::Rect new_bounds(bounds_in_pixels.size());
root_->SetBounds(new_bounds, allocator_.GenerateId());
- for (auto& pair : window_manager_display_root_map_)
- pair.second->root()->SetBounds(new_bounds, allocator_.GenerateId());
+ if (window_manager_display_root_) {
+ window_manager_display_root_->root()->SetBounds(new_bounds,
+ allocator_.GenerateId());
+ }
}
ServerWindow* Display::GetActiveRootWindow() {
- WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
- if (display_root)
- return display_root->root();
+ if (window_manager_display_root_)
+ return window_manager_display_root_->root();
return nullptr;
}
@@ -362,7 +317,7 @@ void Display::OnFocusChanged(FocusControllerChangeSource change_source,
if (old_focused_window) {
owning_tree_old =
- window_server_->GetTreeWithId(old_focused_window->id().client_id);
+ window_server_->GetTreeWithId(old_focused_window->owning_tree_id());
if (owning_tree_old) {
owning_tree_old->ProcessFocusChanged(old_focused_window,
new_focused_window);
@@ -378,7 +333,7 @@ void Display::OnFocusChanged(FocusControllerChangeSource change_source,
WindowTree* embedded_tree_new = nullptr;
if (new_focused_window) {
owning_tree_new =
- window_server_->GetTreeWithId(new_focused_window->id().client_id);
+ window_server_->GetTreeWithId(new_focused_window->owning_tree_id());
if (owning_tree_new && owning_tree_new != owning_tree_old &&
owning_tree_new != embedded_tree_old) {
owning_tree_new->ProcessFocusChanged(old_focused_window,
@@ -394,9 +349,9 @@ void Display::OnFocusChanged(FocusControllerChangeSource change_source,
}
// WindowManagers are always notified of focus changes.
- WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
- if (display_root) {
- WindowTree* wm_tree = display_root->window_manager_state()->window_tree();
+ if (window_manager_display_root_) {
+ WindowTree* wm_tree =
+ window_manager_display_root_->window_manager_state()->window_tree();
if (wm_tree != owning_tree_old && wm_tree != embedded_tree_old &&
wm_tree != owning_tree_new && wm_tree != embedded_tree_new) {
wm_tree->ProcessFocusChanged(old_focused_window, new_focused_window);
@@ -409,27 +364,20 @@ void Display::OnFocusChanged(FocusControllerChangeSource change_source,
}
}
-void Display::OnUserIdRemoved(const UserId& id) {
- window_manager_display_root_map_.erase(id);
-}
-
void Display::OnWindowManagerWindowTreeFactoryReady(
WindowManagerWindowTreeFactory* factory) {
if (!binding_)
- CreateWindowManagerDisplayRootFromFactory(factory);
+ CreateWindowManagerDisplayRootFromFactory();
}
EventDispatchDetails Display::OnEventFromSource(Event* event) {
- WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
- if (display_root) {
- WindowManagerState* wm_state = display_root->window_manager_state();
+ if (window_manager_display_root_) {
+ WindowManagerState* wm_state =
+ window_manager_display_root_->window_manager_state();
wm_state->ProcessEvent(event, GetId());
}
- UserActivityMonitor* activity_monitor =
- window_server_->GetUserActivityMonitorForUser(
- window_server_->user_id_tracker()->active_id());
- activity_monitor->OnUserActivity();
+ window_server_->user_activity_monitor()->OnUserActivity();
return EventDispatchDetails();
}
diff --git a/chromium/services/ui/ws/display.h b/chromium/services/ui/ws/display.h
index e4d7c68f10f..89145ffea27 100644
--- a/chromium/services/ui/ws/display.h
+++ b/chromium/services/ui/ws/display.h
@@ -7,7 +7,6 @@
#include <stdint.h>
-#include <map>
#include <memory>
#include <queue>
#include <set>
@@ -23,8 +22,7 @@
#include "services/ui/ws/platform_display_delegate.h"
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/server_window_observer.h"
-#include "services/ui/ws/user_id_tracker_observer.h"
-#include "services/ui/ws/window_manager_window_tree_factory_set_observer.h"
+#include "services/ui/ws/window_manager_window_tree_factory_observer.h"
#include "ui/display/display.h"
#include "ui/events/event_sink.h"
@@ -57,8 +55,7 @@ class DisplayTestApi;
class Display : public PlatformDisplayDelegate,
public mojom::WindowTreeHost,
public FocusControllerObserver,
- public UserIdTrackerObserver,
- public WindowManagerWindowTreeFactorySetObserver,
+ public WindowManagerWindowTreeFactoryObserver,
public EventSink {
public:
explicit Display(WindowServer* window_server);
@@ -99,30 +96,15 @@ class Display : public PlatformDisplayDelegate,
ServerWindow* root_window() { return root_.get(); }
const ServerWindow* root_window() const { return root_.get(); }
- // Returns the ServerWindow whose id is |id|. This does not do a search over
- // all windows, rather just the display and window manager root windows.
- //
- // In general you shouldn't use this, rather use WindowServer::GetWindow(),
- // which calls this as necessary.
- ServerWindow* GetRootWithId(const WindowId& id);
-
WindowManagerDisplayRoot* GetWindowManagerDisplayRootWithRoot(
const ServerWindow* window);
- WindowManagerDisplayRoot* GetWindowManagerDisplayRootForUser(
- const UserId& user_id) {
- return const_cast<WindowManagerDisplayRoot*>(
- const_cast<const Display*>(this)->GetWindowManagerDisplayRootForUser(
- user_id));
- }
- const WindowManagerDisplayRoot* GetWindowManagerDisplayRootForUser(
- const UserId& user_id) const;
- WindowManagerDisplayRoot* GetActiveWindowManagerDisplayRoot() {
- return const_cast<WindowManagerDisplayRoot*>(
- const_cast<const Display*>(this)->GetActiveWindowManagerDisplayRoot());
+
+ WindowManagerDisplayRoot* window_manager_display_root() {
+ return window_manager_display_root_;
}
- const WindowManagerDisplayRoot* GetActiveWindowManagerDisplayRoot() const;
- size_t num_window_manager_states() const {
- return window_manager_display_root_map_.size();
+
+ const WindowManagerDisplayRoot* window_manager_display_root() const {
+ return window_manager_display_root_;
}
// TODO(sky): this should only be called by WindowServer, move to interface
@@ -141,8 +123,7 @@ class Display : public PlatformDisplayDelegate,
// Called just before |tree| is destroyed.
void OnWillDestroyTree(WindowTree* tree);
- // Removes |display_root| from internal maps. This called prior to
- // |display_root| being destroyed.
+ // Called prior to |display_root| being destroyed.
void RemoveWindowManagerDisplayRoot(WindowManagerDisplayRoot* display_root);
// Sets the native cursor to |cursor|.
@@ -166,17 +147,11 @@ class Display : public PlatformDisplayDelegate,
private:
friend class test::DisplayTestApi;
- using WindowManagerDisplayRootMap =
- std::map<UserId, WindowManagerDisplayRoot*>;
-
class CursorState;
- // Creates the set of WindowManagerDisplayRoots from the
- // WindowManagerWindowTreeFactorySet.
- void CreateWindowManagerDisplayRootsFromFactories();
-
- void CreateWindowManagerDisplayRootFromFactory(
- WindowManagerWindowTreeFactory* factory);
+ // Creates a WindowManagerDisplayRoot from the
+ // WindowManagerWindowTreeFactory.
+ void CreateWindowManagerDisplayRootFromFactory();
// Creates the root ServerWindow for this display, where |size| is in physical
// pixels.
@@ -200,10 +175,7 @@ class Display : public PlatformDisplayDelegate,
ServerWindow* old_focused_window,
ServerWindow* new_focused_window) override;
- // UserIdTrackerObserver:
- void OnUserIdRemoved(const UserId& id) override;
-
- // WindowManagerWindowTreeFactorySetObserver:
+ // WindowManagerWindowTreeFactoryObserver:
void OnWindowManagerWindowTreeFactoryReady(
WindowManagerWindowTreeFactory* factory) override;
@@ -222,7 +194,8 @@ class Display : public PlatformDisplayDelegate,
viz::ParentLocalSurfaceIdAllocator allocator_;
- WindowManagerDisplayRootMap window_manager_display_root_map_;
+ // This is owned by WindowManagerState.
+ WindowManagerDisplayRoot* window_manager_display_root_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(Display);
};
diff --git a/chromium/services/ui/ws/display_binding.cc b/chromium/services/ui/ws/display_binding.cc
index 09157038fb0..476b9466bd7 100644
--- a/chromium/services/ui/ws/display_binding.cc
+++ b/chromium/services/ui/ws/display_binding.cc
@@ -5,7 +5,7 @@
#include "services/ui/ws/display_binding.h"
#include "base/memory/ptr_util.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/ui/ws/display.h"
#include "services/ui/ws/window_manager_access_policy.h"
#include "services/ui/ws/window_server.h"
@@ -16,11 +16,9 @@ namespace ws {
DisplayBindingImpl::DisplayBindingImpl(mojom::WindowTreeHostRequest request,
Display* display,
- const UserId& user_id,
mojom::WindowTreeClientPtr client,
WindowServer* window_server)
: window_server_(window_server),
- user_id_(user_id),
binding_(display, std::move(request)),
client_(std::move(client)) {}
@@ -29,7 +27,7 @@ DisplayBindingImpl::~DisplayBindingImpl() {}
WindowTree* DisplayBindingImpl::CreateWindowTree(ServerWindow* root) {
const uint32_t embed_flags = 0;
WindowTree* tree = window_server_->EmbedAtWindow(
- root, user_id_, std::move(client_), embed_flags,
+ root, std::move(client_), embed_flags,
base::WrapUnique(new WindowManagerAccessPolicy));
const bool automatically_create_display_roots = true;
tree->ConfigureWindowManager(automatically_create_display_roots);
diff --git a/chromium/services/ui/ws/display_binding.h b/chromium/services/ui/ws/display_binding.h
index 093ea48c8e1..3b88965ffb4 100644
--- a/chromium/services/ui/ws/display_binding.h
+++ b/chromium/services/ui/ws/display_binding.h
@@ -11,7 +11,6 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "services/ui/public/interfaces/window_tree_host.mojom.h"
-#include "services/ui/ws/user_id.h"
namespace ui {
namespace ws {
@@ -38,7 +37,6 @@ class DisplayBindingImpl : public DisplayBinding {
public:
DisplayBindingImpl(mojom::WindowTreeHostRequest request,
Display* display,
- const UserId& user_id,
mojom::WindowTreeClientPtr client,
WindowServer* window_server);
~DisplayBindingImpl() override;
@@ -48,7 +46,6 @@ class DisplayBindingImpl : public DisplayBinding {
WindowTree* CreateWindowTree(ServerWindow* root) override;
WindowServer* window_server_;
- const UserId user_id_;
mojo::Binding<mojom::WindowTreeHost> binding_;
mojom::WindowTreeClientPtr client_;
diff --git a/chromium/services/ui/ws/display_manager.cc b/chromium/services/ui/ws/display_manager.cc
index 3265febb9b6..3691e0ea63e 100644
--- a/chromium/services/ui/ws/display_manager.cc
+++ b/chromium/services/ui/ws/display_manager.cc
@@ -20,7 +20,6 @@
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/user_display_manager.h"
#include "services/ui/ws/user_display_manager_delegate.h"
-#include "services/ui/ws/user_id_tracker.h"
#include "services/ui/ws/window_manager_state.h"
#include "services/ui/ws/window_manager_window_tree_factory.h"
#include "services/ui/ws/window_server_delegate.h"
@@ -38,15 +37,12 @@
namespace ui {
namespace ws {
-DisplayManager::DisplayManager(WindowServer* window_server,
- UserIdTracker* user_id_tracker)
+DisplayManager::DisplayManager(WindowServer* window_server)
// |next_root_id_| is used as the lower bits, so that starting at 0 is
// fine. |next_display_id_| is used by itself, so we start at 1 to reserve
// 0 as invalid.
: window_server_(window_server),
- user_id_tracker_(user_id_tracker),
- next_root_id_(0),
- internal_display_id_(display::kInvalidDisplayId) {
+ cursor_location_manager_(std::make_unique<CursorLocationManager>()) {
#if defined(OS_CHROMEOS)
// TODO: http://crbug.com/701468 fix function key preferences and sticky keys.
ui::EventRewriterChromeOS::Delegate* delegate = nullptr;
@@ -54,19 +50,17 @@ DisplayManager::DisplayManager(WindowServer* window_server,
event_rewriter_ = std::make_unique<ui::EventRewriterChromeOS>(
delegate, sticky_keys_controller);
#endif
- user_id_tracker_->AddObserver(this);
}
DisplayManager::~DisplayManager() {
- user_id_tracker_->RemoveObserver(this);
DestroyAllDisplays();
}
void DisplayManager::OnDisplayCreationConfigSet() {
if (window_server_->display_creation_config() ==
DisplayCreationConfig::MANUAL) {
- for (const auto& pair : user_display_managers_)
- pair.second->DisableAutomaticNotification();
+ if (user_display_manager_)
+ user_display_manager_->DisableAutomaticNotification();
} else {
// In AUTOMATIC mode SetDisplayConfiguration() is never called.
got_initial_config_from_window_manager_ = true;
@@ -169,7 +163,7 @@ bool DisplayManager::SetDisplayConfiguration(
}
}
for (size_t i = 0; i < mirrors.size(); ++i) {
- NOTIMPLEMENTED() << "TODO(crbug.com/764472): Mus mirroring/unified mode.";
+ NOTIMPLEMENTED() << "TODO(crbug.com/806318): Mus+Viz mirroring/unified";
Display* ws_mirror = GetDisplayById(mirrors[i].id());
const auto& metrics = viewport_metrics[displays.size() + i];
if (!ws_mirror) {
@@ -193,8 +187,8 @@ bool DisplayManager::SetDisplayConfiguration(
for (int64_t display_id : removed_display_ids)
display_list.RemoveDisplay(display_id);
- for (auto& pair : user_display_managers_)
- pair.second->CallOnDisplaysChanged();
+ if (user_display_manager_)
+ user_display_manager_->CallOnDisplaysChanged();
if (!got_initial_config_from_window_manager_) {
got_initial_config_from_window_manager_ = true;
@@ -204,26 +198,16 @@ bool DisplayManager::SetDisplayConfiguration(
return true;
}
-UserDisplayManager* DisplayManager::GetUserDisplayManager(
- const UserId& user_id) {
- if (!user_display_managers_.count(user_id)) {
- user_display_managers_[user_id] =
- std::make_unique<UserDisplayManager>(window_server_, user_id);
+UserDisplayManager* DisplayManager::GetUserDisplayManager() {
+ if (!user_display_manager_) {
+ user_display_manager_ =
+ std::make_unique<UserDisplayManager>(window_server_);
if (window_server_->display_creation_config() ==
DisplayCreationConfig::MANUAL) {
- user_display_managers_[user_id]->DisableAutomaticNotification();
+ user_display_manager_->DisableAutomaticNotification();
}
}
- return user_display_managers_[user_id].get();
-}
-
-CursorLocationManager* DisplayManager::GetCursorLocationManager(
- const UserId& user_id) {
- if (!cursor_location_managers_.count(user_id)) {
- cursor_location_managers_[user_id] =
- std::make_unique<CursorLocationManager>();
- }
- return cursor_location_managers_[user_id].get();
+ return user_display_manager_.get();
}
void DisplayManager::AddDisplay(Display* display) {
@@ -260,12 +244,10 @@ void DisplayManager::DestroyDisplay(Display* display) {
// If we have no more roots left, let the app know so it can terminate.
// TODO(sky): move to delegate/observer.
- if (displays_.empty() && pending_displays_.empty()) {
+ if (displays_.empty() && pending_displays_.empty())
window_server_->OnNoMoreDisplays();
- } else {
- for (const auto& pair : user_display_managers_)
- pair.second->OnDisplayDestroyed(display_id);
- }
+ else if (user_display_manager_)
+ user_display_manager_->OnDisplayDestroyed(display_id);
}
void DisplayManager::DestroyAllDisplays() {
@@ -284,8 +266,8 @@ std::set<const Display*> DisplayManager::displays() const {
}
void DisplayManager::OnDisplayUpdated(const display::Display& display) {
- for (const auto& pair : user_display_managers_)
- pair.second->OnDisplayUpdated(display);
+ if (user_display_manager_)
+ user_display_manager_->OnDisplayUpdated(display);
}
Display* DisplayManager::GetDisplayContaining(const ServerWindow* window) {
@@ -304,7 +286,7 @@ const Display* DisplayManager::GetDisplayContaining(
return nullptr;
}
-Display* DisplayManager::GetDisplayById(int64_t display_id) {
+const Display* DisplayManager::GetDisplayById(int64_t display_id) const {
for (Display* display : displays_) {
if (display->GetId() == display_id)
return display;
@@ -333,11 +315,14 @@ WindowManagerDisplayRoot* DisplayManager::GetWindowManagerDisplayRoot(
window));
}
-WindowId DisplayManager::GetAndAdvanceNextRootId() {
- // TODO(sky): handle wrapping!
- const uint16_t id = next_root_id_++;
- DCHECK_LT(id, next_root_id_);
- return RootWindowId(id);
+bool DisplayManager::InUnifiedDisplayMode() const {
+ return GetDisplayById(display::kUnifiedDisplayId) != nullptr;
+}
+
+ClientWindowId DisplayManager::GetAndAdvanceNextRootId() {
+ const ClientSpecificId id = next_root_id_++;
+ CHECK_NE(0u, next_root_id_);
+ return ClientWindowId(kWindowServerClientId, id);
}
void DisplayManager::OnDisplayAcceleratedWidgetAvailable(Display* display) {
@@ -373,28 +358,6 @@ int64_t DisplayManager::GetInternalDisplayId() const {
: display::kInvalidDisplayId;
}
-void DisplayManager::OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) {
- WindowManagerState* previous_window_manager_state =
- window_server_->GetWindowManagerStateForUser(previously_active_id);
- gfx::Point mouse_location_on_display;
- int64_t mouse_display_id = 0;
- if (previous_window_manager_state) {
- mouse_location_on_display =
- gfx::ToFlooredPoint(previous_window_manager_state->event_dispatcher()
- ->mouse_pointer_last_location());
- mouse_display_id = previous_window_manager_state->event_dispatcher()
- ->mouse_pointer_display_id();
- previous_window_manager_state->Deactivate();
- }
-
- WindowManagerState* current_window_manager_state =
- window_server_->GetWindowManagerStateForUser(active_id);
- if (current_window_manager_state)
- current_window_manager_state->Activate(mouse_location_on_display,
- mouse_display_id);
-}
-
void DisplayManager::CreateDisplay(const display::Display& display,
const display::ViewportMetrics& metrics) {
ws::Display* ws_display = new ws::Display(window_server_);
@@ -427,12 +390,10 @@ void DisplayManager::OnDisplayModified(
ws_display->SetDisplay(display);
// Send IPC to WMs with new display information.
- std::vector<WindowManagerWindowTreeFactory*> factories =
- window_server_->window_manager_window_tree_factory_set()->GetFactories();
- for (WindowManagerWindowTreeFactory* factory : factories) {
- if (factory->window_tree())
- factory->window_tree()->OnWmDisplayModified(display);
- }
+ WindowManagerWindowTreeFactory* factory =
+ window_server_->window_manager_window_tree_factory();
+ if (factory->window_tree())
+ factory->window_tree()->OnWmDisplayModified(display);
// Update the PlatformWindow and ServerWindow size. This must happen after
// OnWmDisplayModified() so the WM has updated the display size.
@@ -446,8 +407,8 @@ void DisplayManager::OnPrimaryDisplayChanged(int64_t primary_display_id) {
// TODO(kylechar): Send IPCs to WM clients first.
// Send IPCs to any DisplayManagerObservers.
- for (const auto& pair : user_display_managers_)
- pair.second->OnPrimaryDisplayChanged(primary_display_id);
+ if (user_display_manager_)
+ user_display_manager_->OnPrimaryDisplayChanged(primary_display_id);
}
} // namespace ws
diff --git a/chromium/services/ui/ws/display_manager.h b/chromium/services/ui/ws/display_manager.h
index d3b7f157a7e..abb91d9fcce 100644
--- a/chromium/services/ui/ws/display_manager.h
+++ b/chromium/services/ui/ws/display_manager.h
@@ -13,8 +13,6 @@
#include "services/ui/display/screen_manager_delegate.h"
#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
#include "services/ui/ws/ids.h"
-#include "services/ui/ws/user_id.h"
-#include "services/ui/ws/user_id_tracker_observer.h"
#include "ui/display/display.h"
namespace display {
@@ -28,17 +26,15 @@ class CursorLocationManager;
class Display;
class ServerWindow;
class UserDisplayManager;
-class UserIdTracker;
class WindowManagerDisplayRoot;
class WindowServer;
// DisplayManager manages the set of Displays. DisplayManager distinguishes
// between displays that do not yet have an accelerated widget (pending), vs
// those that do.
-class DisplayManager : public UserIdTrackerObserver,
- public display::ScreenManagerDelegate {
+class DisplayManager : public display::ScreenManagerDelegate {
public:
- DisplayManager(WindowServer* window_server, UserIdTracker* user_id_tracker);
+ explicit DisplayManager(WindowServer* window_server);
~DisplayManager() override;
// Called once WindowServer::display_creation_config() has been determined.
@@ -60,12 +56,13 @@ class DisplayManager : public UserIdTrackerObserver,
int64_t internal_display_id,
const std::vector<display::Display>& mirrors);
- // Returns the UserDisplayManager for |user_id|. DisplayManager owns the
- // return value.
- UserDisplayManager* GetUserDisplayManager(const UserId& user_id);
+ // Returns the UserDisplayManager. DisplayManager owns the return value.
+ UserDisplayManager* GetUserDisplayManager();
- // Returns the CursorLocationManager for |user_id|.
- CursorLocationManager* GetCursorLocationManager(const UserId& user_id);
+ // Returns the CursorLocationManager.
+ CursorLocationManager* cursor_location_manager() {
+ return cursor_location_manager_.get();
+ }
// Adds/removes a Display. DisplayManager owns the Displays.
// TODO(sky): make add take a scoped_ptr.
@@ -89,7 +86,11 @@ class DisplayManager : public UserIdTrackerObserver,
// Returns the display with the specified display id, or null if there is no
// display with that id.
- Display* GetDisplayById(int64_t display_id);
+ const Display* GetDisplayById(int64_t display_id) const;
+ Display* GetDisplayById(int64_t display_id) {
+ return const_cast<Display*>(
+ const_cast<const DisplayManager*>(this)->GetDisplayById(display_id));
+ }
const WindowManagerDisplayRoot* GetWindowManagerDisplayRoot(
const ServerWindow* window) const;
@@ -104,9 +105,11 @@ class DisplayManager : public UserIdTrackerObserver,
return !displays_.empty() || !pending_displays_.empty();
}
+ bool InUnifiedDisplayMode() const;
+
// Returns the id for the next root window (both for the root of a Display
// as well as the root of WindowManagers).
- WindowId GetAndAdvanceNextRootId();
+ ClientWindowId GetAndAdvanceNextRootId();
// Called when the AcceleratedWidget is available for |display|.
void OnDisplayAcceleratedWidgetAvailable(Display* display);
@@ -118,10 +121,6 @@ class DisplayManager : public UserIdTrackerObserver,
int64_t GetInternalDisplayId() const;
private:
- // UserIdTrackerObserver:
- void OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) override;
-
void CreateDisplay(const display::Display& display,
const display::ViewportMetrics& metrics);
@@ -136,7 +135,6 @@ class DisplayManager : public UserIdTrackerObserver,
void OnPrimaryDisplayChanged(int64_t primary_display_id) override;
WindowServer* window_server_;
- UserIdTracker* user_id_tracker_;
// For rewriting ChromeOS function keys.
std::unique_ptr<ui::EventRewriter> event_rewriter_;
@@ -146,13 +144,13 @@ class DisplayManager : public UserIdTrackerObserver,
std::set<Display*> pending_displays_;
std::set<Display*> displays_;
- std::map<UserId, std::unique_ptr<UserDisplayManager>> user_display_managers_;
+ std::unique_ptr<UserDisplayManager> user_display_manager_;
- std::map<UserId, std::unique_ptr<CursorLocationManager>>
- cursor_location_managers_;
+ std::unique_ptr<CursorLocationManager> cursor_location_manager_;
// ID to use for next root node.
- ClientSpecificId next_root_id_;
+ // TODO(sky): figure out why this starts at 2.
+ ClientSpecificId next_root_id_ = 2;
bool got_initial_config_from_window_manager_ = false;
@@ -161,7 +159,7 @@ class DisplayManager : public UserIdTrackerObserver,
// not mirrored in Display::SetInternalId() as mus may be running in the
// same process as the window-manager, so that if this did set the value in
// Display there could be race conditions.
- int64_t internal_display_id_;
+ int64_t internal_display_id_ = display::kInvalidDisplayId;
DISALLOW_COPY_AND_ASSIGN(DisplayManager);
};
diff --git a/chromium/services/ui/ws/display_unittest.cc b/chromium/services/ui/ws/display_unittest.cc
index 01f37c86f1d..a183739ae67 100644
--- a/chromium/services/ui/ws/display_unittest.cc
+++ b/chromium/services/ui/ws/display_unittest.cc
@@ -35,22 +35,6 @@ namespace ws {
namespace test {
namespace {
-const UserId kTestId1 = "2";
-const UserId kTestId2 = "21";
-
-ClientWindowId ClientWindowIdForFirstRoot(WindowTree* tree) {
- if (tree->roots().empty())
- return ClientWindowId();
- return ClientWindowIdForWindow(tree, *tree->roots().begin());
-}
-
-WindowManagerState* GetWindowManagerStateForUser(Display* display,
- const UserId& user_id) {
- WindowManagerDisplayRoot* display_root =
- display->GetWindowManagerDisplayRootForUser(user_id);
- return display_root ? display_root->window_manager_state() : nullptr;
-}
-
// Returns the root ServerWindow for the specified Display.
ServerWindow* GetRootOnDisplay(WindowTree* tree, Display* display) {
for (const ServerWindow* root : tree->roots()) {
@@ -110,8 +94,6 @@ class DisplayTest : public testing::Test {
// testing::Test:
void SetUp() override {
screen_manager_.Init(window_server()->display_manager());
- window_server()->user_id_tracker()->AddUserId(kTestId1);
- window_server()->user_id_tracker()->AddUserId(kTestId2);
}
private:
@@ -122,7 +104,7 @@ class DisplayTest : public testing::Test {
};
TEST_F(DisplayTest, CreateDisplay) {
- AddWindowManager(window_server(), kTestId1);
+ AddWindowManager(window_server());
const int64_t display_id =
screen_manager().AddDisplay(MakeDisplay(0, 0, 1024, 768, 1.0f));
@@ -134,9 +116,7 @@ TEST_F(DisplayTest, CreateDisplay) {
EXPECT_EQ("0,0 1024x768", display->root_window()->bounds().ToString());
// Display should have a WM root window with the correct size too.
- EXPECT_EQ(1u, display->num_window_manager_states());
- WindowManagerDisplayRoot* root1 =
- display->GetWindowManagerDisplayRootForUser(kTestId1);
+ WindowManagerDisplayRoot* root1 = display->window_manager_display_root();
ASSERT_NE(nullptr, root1);
ASSERT_NE(nullptr, root1->root());
EXPECT_EQ("0,0 1024x768", root1->root()->bounds().ToString());
@@ -155,47 +135,17 @@ TEST_F(DisplayTest, CreateDisplayBeforeWM) {
EXPECT_EQ("0,0 1024x768", display->root_window()->bounds().ToString());
// There should be no WM state for display yet.
- EXPECT_EQ(0u, display->num_window_manager_states());
- EXPECT_EQ(nullptr, display->GetWindowManagerDisplayRootForUser(kTestId1));
+ EXPECT_EQ(nullptr, display->window_manager_display_root());
- AddWindowManager(window_server(), kTestId1);
+ AddWindowManager(window_server());
// After adding a WM display should have WM state and WM root for the display.
- EXPECT_EQ(1u, display->num_window_manager_states());
- WindowManagerDisplayRoot* root1 =
- display->GetWindowManagerDisplayRootForUser(kTestId1);
+ WindowManagerDisplayRoot* root1 = display->window_manager_display_root();
ASSERT_NE(nullptr, root1);
ASSERT_NE(nullptr, root1->root());
EXPECT_EQ("0,0 1024x768", root1->root()->bounds().ToString());
}
-TEST_F(DisplayTest, CreateDisplayWithTwoWindowManagers) {
- AddWindowManager(window_server(), kTestId1);
- const int64_t display_id = screen_manager().AddDisplay();
- Display* display = display_manager()->GetDisplayById(display_id);
-
- // There should be only be one WM at this point.
- ASSERT_EQ(1u, display->num_window_manager_states());
- EXPECT_NE(nullptr, display->GetWindowManagerDisplayRootForUser(kTestId1));
- EXPECT_EQ(nullptr, display->GetWindowManagerDisplayRootForUser(kTestId2));
-
- AddWindowManager(window_server(), kTestId2);
-
- // There should now be two WMs.
- ASSERT_EQ(2u, display->num_window_manager_states());
- WindowManagerDisplayRoot* root1 =
- display->GetWindowManagerDisplayRootForUser(kTestId1);
- ASSERT_NE(nullptr, root1);
- WindowManagerDisplayRoot* root2 =
- display->GetWindowManagerDisplayRootForUser(kTestId2);
- ASSERT_NE(nullptr, root2);
-
- // Verify the two WMs have different roots but with the same bounds.
- EXPECT_NE(root1, root2);
- EXPECT_NE(root1->root(), root2->root());
- EXPECT_EQ(root1->root()->bounds(), root2->root()->bounds());
-}
-
TEST_F(DisplayTest, CreateDisplayWithDeviceScaleFactor) {
// The display bounds should be the pixel_size / device_scale_factor.
display::Display display = MakeDisplay(0, 0, 1024, 768, 2.0f);
@@ -223,149 +173,29 @@ TEST_F(DisplayTest, CreateDisplayWithDeviceScaleFactor) {
}
TEST_F(DisplayTest, Destruction) {
- AddWindowManager(window_server(), kTestId1);
+ AddWindowManager(window_server());
int64_t display_id = screen_manager().AddDisplay();
- // Add a second WM.
- AddWindowManager(window_server(), kTestId2);
ASSERT_EQ(1u, display_manager()->displays().size());
- Display* display = display_manager()->GetDisplayById(display_id);
- ASSERT_EQ(2u, display->num_window_manager_states());
- // There should be two trees, one for each windowmanager.
- EXPECT_EQ(2u, window_server()->num_trees());
-
- {
- WindowManagerState* state = GetWindowManagerStateForUser(display, kTestId1);
- // Destroy the tree associated with |state|. Should result in deleting
- // |state|.
- window_server()->DestroyTree(state->window_tree());
- ASSERT_EQ(1u, display->num_window_manager_states());
- EXPECT_FALSE(GetWindowManagerStateForUser(display, kTestId1));
- EXPECT_EQ(1u, display_manager()->displays().size());
- EXPECT_EQ(1u, window_server()->num_trees());
- }
+ EXPECT_EQ(1u, window_server()->num_trees());
+ WindowManagerState* state = window_server()->GetWindowManagerState();
+ // Destroy the tree associated with |state|. Should result in deleting
+ // |state|.
+ window_server()->DestroyTree(state->window_tree());
+ EXPECT_EQ(1u, display_manager()->displays().size());
+ EXPECT_EQ(0u, window_server()->num_trees());
EXPECT_FALSE(window_server_delegate()->got_on_no_more_displays());
screen_manager().RemoveDisplay(display_id);
- // There is still one tree left.
- EXPECT_EQ(1u, window_server()->num_trees());
EXPECT_TRUE(window_server_delegate()->got_on_no_more_displays());
}
-TEST_F(DisplayTest, EventStateResetOnUserSwitch) {
- const int64_t display_id = screen_manager().AddDisplay();
-
- AddWindowManager(window_server(), kTestId1);
- AddWindowManager(window_server(), kTestId2);
-
- window_server()->user_id_tracker()->SetActiveUserId(kTestId1);
-
- ASSERT_EQ(1u, display_manager()->displays().size());
- Display* display = display_manager()->GetDisplayById(display_id);
- WindowManagerState* active_wms =
- display->GetActiveWindowManagerDisplayRoot()->window_manager_state();
- ASSERT_TRUE(active_wms);
- EXPECT_EQ(kTestId1, active_wms->user_id());
-
- ui::PointerEvent pointer_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));
- ignore_result(static_cast<PlatformDisplayDelegate*>(display)
- ->GetEventSink()
- ->OnEventFromSource(&pointer_event));
-
- EXPECT_TRUE(EventDispatcherTestApi(active_wms->event_dispatcher())
- .AreAnyPointersDown());
- EXPECT_EQ(gfx::PointF(20, 25),
- active_wms->event_dispatcher()->mouse_pointer_last_location());
-
- // Switch the user. Should trigger resetting state in old event dispatcher
- // and update state in new event dispatcher.
- window_server()->user_id_tracker()->SetActiveUserId(kTestId2);
- EXPECT_NE(
- active_wms,
- display->GetActiveWindowManagerDisplayRoot()->window_manager_state());
- EXPECT_FALSE(EventDispatcherTestApi(active_wms->event_dispatcher())
- .AreAnyPointersDown());
- active_wms =
- display->GetActiveWindowManagerDisplayRoot()->window_manager_state();
- EXPECT_EQ(kTestId2, active_wms->user_id());
- EXPECT_EQ(gfx::PointF(20, 25),
- active_wms->event_dispatcher()->mouse_pointer_last_location());
- EXPECT_FALSE(EventDispatcherTestApi(active_wms->event_dispatcher())
- .AreAnyPointersDown());
-}
-
-// Verifies capture fails when wm is inactive and succeeds when wm is active.
-TEST_F(DisplayTest, SetCaptureFromWindowManager) {
- const int64_t display_id = screen_manager().AddDisplay();
- AddWindowManager(window_server(), kTestId1);
- AddWindowManager(window_server(), kTestId2);
- window_server()->user_id_tracker()->SetActiveUserId(kTestId1);
- ASSERT_EQ(1u, display_manager()->displays().size());
- Display* display = display_manager()->GetDisplayById(display_id);
- WindowManagerState* wms_for_id2 =
- GetWindowManagerStateForUser(display, kTestId2);
- ASSERT_TRUE(wms_for_id2);
- EXPECT_FALSE(wms_for_id2->IsActive());
-
- // Create a child of the root that we can set capture on.
- WindowTree* tree = wms_for_id2->window_tree();
- ClientWindowId child_window_id;
- ASSERT_TRUE(NewWindowInTree(tree, &child_window_id));
-
- WindowTreeTestApi(tree).EnableCapture();
-
- // SetCapture() should fail for user id2 as it is inactive.
- EXPECT_FALSE(tree->SetCapture(child_window_id));
-
- // Make the second user active and verify capture works.
- window_server()->user_id_tracker()->SetActiveUserId(kTestId2);
- EXPECT_TRUE(wms_for_id2->IsActive());
- EXPECT_TRUE(tree->SetCapture(child_window_id));
-}
-
-TEST_F(DisplayTest, FocusFailsForInactiveUser) {
- const int64_t display_id = screen_manager().AddDisplay();
- AddWindowManager(window_server(), kTestId1);
- TestWindowTreeClient* window_tree_client1 =
- window_server_delegate()->last_client();
- ASSERT_TRUE(window_tree_client1);
- AddWindowManager(window_server(), kTestId2);
- window_server()->user_id_tracker()->SetActiveUserId(kTestId1);
- ASSERT_EQ(1u, display_manager()->displays().size());
- Display* display = display_manager()->GetDisplayById(display_id);
- WindowManagerState* wms_for_id2 =
- GetWindowManagerStateForUser(display, kTestId2);
- wms_for_id2->window_tree()->AddActivationParent(
- ClientWindowIdForFirstRoot(wms_for_id2->window_tree()));
- ASSERT_TRUE(wms_for_id2);
- EXPECT_FALSE(wms_for_id2->IsActive());
- ClientWindowId child2_id;
- NewWindowInTree(wms_for_id2->window_tree(), &child2_id);
-
- // Focus should fail for windows in inactive window managers.
- EXPECT_FALSE(wms_for_id2->window_tree()->SetFocus(child2_id));
-
- // Focus should succeed for the active window manager.
- WindowManagerState* wms_for_id1 =
- GetWindowManagerStateForUser(display, kTestId1);
- ASSERT_TRUE(wms_for_id1);
- wms_for_id1->window_tree()->AddActivationParent(
- ClientWindowIdForFirstRoot(wms_for_id1->window_tree()));
- ClientWindowId child1_id;
- NewWindowInTree(wms_for_id1->window_tree(), &child1_id);
- EXPECT_TRUE(wms_for_id1->IsActive());
- EXPECT_TRUE(wms_for_id1->window_tree()->SetFocus(child1_id));
-}
-
// Verifies a single tree is used for multiple displays.
TEST_F(DisplayTest, MultipleDisplays) {
screen_manager().AddDisplay();
screen_manager().AddDisplay();
- AddWindowManager(window_server(), kTestId1);
- window_server()->user_id_tracker()->SetActiveUserId(kTestId1);
+ AddWindowManager(window_server());
ASSERT_EQ(1u, window_server_delegate()->bindings()->size());
TestWindowTreeBinding* window_tree_binding =
(*window_server_delegate()->bindings())[0];
@@ -373,27 +203,24 @@ TEST_F(DisplayTest, MultipleDisplays) {
ASSERT_EQ(2u, tree->roots().size());
std::set<const ServerWindow*> roots = tree->roots();
auto it = roots.begin();
- ServerWindow* root1 = tree->GetWindow((*it)->id());
+ ServerWindow* root1 = const_cast<ServerWindow*>(*it);
++it;
- ServerWindow* root2 = tree->GetWindow((*it)->id());
+ ServerWindow* root2 = const_cast<ServerWindow*>(*it);
ASSERT_NE(root1, root2);
Display* display1 = tree->GetDisplay(root1);
WindowManagerState* display1_wms =
- display1->GetWindowManagerDisplayRootForUser(kTestId1)
- ->window_manager_state();
+ display1->window_manager_display_root()->window_manager_state();
Display* display2 = tree->GetDisplay(root2);
WindowManagerState* display2_wms =
- display2->GetWindowManagerDisplayRootForUser(kTestId1)
- ->window_manager_state();
+ display2->window_manager_display_root()->window_manager_state();
EXPECT_EQ(display1_wms->window_tree(), display2_wms->window_tree());
}
// Assertions around destroying a secondary display.
TEST_F(DisplayTest, DestroyingDisplayDoesntDelete) {
- AddWindowManager(window_server(), kTestId1);
+ AddWindowManager(window_server());
screen_manager().AddDisplay();
const int64_t secondary_display_id = screen_manager().AddDisplay();
- window_server()->user_id_tracker()->SetActiveUserId(kTestId1);
ASSERT_EQ(1u, window_server_delegate()->bindings()->size());
WindowTree* tree = (*window_server_delegate()->bindings())[0]->tree();
ASSERT_EQ(2u, tree->roots().size());
diff --git a/chromium/services/ui/ws/drag_controller.cc b/chromium/services/ui/ws/drag_controller.cc
index cc3b99925ec..4faf1b386cd 100644
--- a/chromium/services/ui/ws/drag_controller.cc
+++ b/chromium/services/ui/ws/drag_controller.cc
@@ -260,18 +260,24 @@ void DragController::DispatchOperation(ServerWindow* target,
break;
}
case OperationType::ENTER: {
+ std::unique_ptr<ServerWindowTracker> tracker =
+ std::make_unique<ServerWindowTracker>();
+ tracker->Add(target);
connection->PerformOnDragEnter(
target, op.event_flags, op.screen_position, drag_operations_,
base::Bind(&DragController::OnDragStatusCompleted,
- weak_factory_.GetWeakPtr(), target->id()));
+ weak_factory_.GetWeakPtr(), base::Passed(&tracker)));
state->waiting_on_reply = OperationType::ENTER;
break;
}
case OperationType::OVER: {
+ std::unique_ptr<ServerWindowTracker> tracker =
+ std::make_unique<ServerWindowTracker>();
+ tracker->Add(target);
connection->PerformOnDragOver(
target, op.event_flags, op.screen_position, drag_operations_,
base::Bind(&DragController::OnDragStatusCompleted,
- weak_factory_.GetWeakPtr(), target->id()));
+ weak_factory_.GetWeakPtr(), base::Passed(&tracker)));
state->waiting_on_reply = OperationType::OVER;
break;
}
@@ -281,10 +287,13 @@ void DragController::DispatchOperation(ServerWindow* target,
break;
}
case OperationType::DROP: {
+ std::unique_ptr<ServerWindowTracker> tracker =
+ std::make_unique<ServerWindowTracker>();
+ tracker->Add(target);
connection->PerformOnCompleteDrop(
target, op.event_flags, op.screen_position, drag_operations_,
base::Bind(&DragController::OnDragDropCompleted,
- weak_factory_.GetWeakPtr(), target->id()));
+ weak_factory_.GetWeakPtr(), base::Passed(&tracker)));
state->waiting_on_reply = OperationType::DROP;
break;
}
@@ -301,23 +310,23 @@ void DragController::OnRespondToOperation(ServerWindow* window) {
DispatchOperation(window, &state);
}
-void DragController::OnDragStatusCompleted(const WindowId& id,
- DropEffectBitmask bitmask) {
- ServerWindow* window = source_->GetWindowById(id);
- if (!window) {
+void DragController::OnDragStatusCompleted(
+ std::unique_ptr<ServerWindowTracker> tracker,
+ DropEffectBitmask bitmask) {
+ if (tracker->windows().empty()) {
// The window has been deleted and its queue is empty.
return;
}
// We must remove the completed item.
- OnRespondToOperation(window);
- SetWindowDropOperations(window, bitmask);
+ OnRespondToOperation(*(tracker->windows().begin()));
+ SetWindowDropOperations(*(tracker->windows().begin()), bitmask);
}
-void DragController::OnDragDropCompleted(const WindowId& id,
- DropEffect action) {
- ServerWindow* window = source_->GetWindowById(id);
- if (!window) {
+void DragController::OnDragDropCompleted(
+ std::unique_ptr<ServerWindowTracker> tracker,
+ DropEffect action) {
+ if (tracker->windows().empty()) {
// The window has been deleted after we sent the drop message. It's really
// hard to recover from this so just signal to the source that our drag
// failed.
@@ -325,7 +334,7 @@ void DragController::OnDragDropCompleted(const WindowId& id,
return;
}
- OnRespondToOperation(window);
+ OnRespondToOperation(*(tracker->windows().begin()));
MessageDragCompleted(action != 0u, action);
}
diff --git a/chromium/services/ui/ws/drag_controller.h b/chromium/services/ui/ws/drag_controller.h
index 83e6abcadc2..5a67b4b3d86 100644
--- a/chromium/services/ui/ws/drag_controller.h
+++ b/chromium/services/ui/ws/drag_controller.h
@@ -6,6 +6,7 @@
#define SERVICES_UI_WS_DRAG_CONTROLLER_H_
#include <map>
+#include <memory>
#include <set>
#include "base/memory/weak_ptr.h"
@@ -13,6 +14,7 @@
#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/ws/ids.h"
#include "services/ui/ws/server_window_observer.h"
+#include "services/ui/ws/server_window_tracker.h"
namespace gfx {
class Point;
@@ -104,9 +106,12 @@ class DragController : public ServerWindowObserver {
void DispatchOperation(ServerWindow* window, WindowState* state);
void OnRespondToOperation(ServerWindow* window);
- // Callback methods.
- void OnDragStatusCompleted(const WindowId& id, DropEffectBitmask bitmask);
- void OnDragDropCompleted(const WindowId& id, DropEffect action);
+ // Callback methods. |tracker| contains the window being queried and is null
+ // if the window was destroyed while waiting for client.
+ void OnDragStatusCompleted(std::unique_ptr<ServerWindowTracker> tracker,
+ DropEffectBitmask bitmask);
+ void OnDragDropCompleted(std::unique_ptr<ServerWindowTracker> tracker,
+ DropEffect action);
// ServerWindowObserver:
void OnWindowDestroying(ServerWindow* window) override;
diff --git a/chromium/services/ui/ws/drag_controller_unittest.cc b/chromium/services/ui/ws/drag_controller_unittest.cc
index 764e1c6386d..50c4e4370e9 100644
--- a/chromium/services/ui/ws/drag_controller_unittest.cc
+++ b/chromium/services/ui/ws/drag_controller_unittest.cc
@@ -41,7 +41,7 @@ class DragTestWindow : public DragTargetConnection {
DragTestWindow(DragControllerTest* parent,
TestServerWindowDelegate* window_delegate,
- const WindowId& id)
+ const viz::FrameSinkId& id)
: parent_(parent),
window_delegate_(window_delegate),
window_(window_delegate_, id) {
@@ -146,10 +146,9 @@ class DragControllerTest : public testing::Test,
public DragSource {
public:
std::unique_ptr<DragTestWindow> BuildWindow() {
- WindowId id(1, ++window_id_);
+ viz::FrameSinkId id(1, ++window_id_);
std::unique_ptr<DragTestWindow> p =
std::make_unique<DragTestWindow>(this, window_delegate_.get(), id);
- server_window_by_id_[id] = p->window();
connection_by_window_[p->window()] = p.get();
return p;
}
@@ -196,7 +195,6 @@ class DragControllerTest : public testing::Test,
void OnTestWindowDestroyed(DragTestWindow* test_window) {
drag_operation_->OnWillDestroyDragTargetConnection(test_window);
- server_window_by_id_.erase(test_window->window()->id());
connection_by_window_.erase(test_window->window());
}
@@ -218,8 +216,8 @@ class DragControllerTest : public testing::Test,
window_delegate_ = std::make_unique<TestServerWindowDelegate>(
ws_test_helper_.window_server()->GetVizHostProxy());
- root_window_ =
- std::make_unique<ServerWindow>(window_delegate_.get(), WindowId(1, 2));
+ root_window_ = std::make_unique<ServerWindow>(window_delegate_.get(),
+ viz::FrameSinkId(1, 2));
window_delegate_->set_root_window(root_window_.get());
root_window_->SetVisible(true);
}
@@ -229,7 +227,6 @@ class DragControllerTest : public testing::Test,
root_window_.reset();
window_delegate_.reset();
- DCHECK(server_window_by_id_.empty());
DCHECK(connection_by_window_.empty());
testing::Test::TearDown();
@@ -249,13 +246,6 @@ class DragControllerTest : public testing::Test,
drag_completed_value_ = success;
}
- ServerWindow* GetWindowById(const WindowId& id) override {
- auto it = server_window_by_id_.find(id);
- if (it == server_window_by_id_.end())
- return nullptr;
- return it->second;
- }
-
DragTargetConnection* GetDragTargetForWindow(
const ServerWindow* window) override {
auto it = connection_by_window_.find(const_cast<ServerWindow*>(window));
@@ -270,7 +260,6 @@ class DragControllerTest : public testing::Test,
ui::CursorType cursor_;
- std::map<WindowId, ServerWindow*> server_window_by_id_;
std::map<ServerWindow*, DragTargetConnection*> connection_by_window_;
std::unique_ptr<TestServerWindowDelegate> window_delegate_;
diff --git a/chromium/services/ui/ws/drag_source.h b/chromium/services/ui/ws/drag_source.h
index 050a0ced794..cb450396d5e 100644
--- a/chromium/services/ui/ws/drag_source.h
+++ b/chromium/services/ui/ws/drag_source.h
@@ -10,7 +10,6 @@ namespace ws {
class DragTargetConnection;
class ServerWindow;
-struct WindowId;
// An interface implemented by the object that caused a DragController to
// exist, and which acts as a delegate to it.
@@ -27,8 +26,6 @@ class DragSource {
// is one of the kDropEffect constants in window_tree_constants.mojom.
virtual void OnDragCompleted(bool success, uint32_t action_taken) = 0;
- virtual ServerWindow* GetWindowById(const WindowId& id) = 0;
-
// Returns the client connection that created |window|.
virtual DragTargetConnection* GetDragTargetForWindow(
const ServerWindow* window) = 0;
diff --git a/chromium/services/ui/ws/event_dispatcher.cc b/chromium/services/ui/ws/event_dispatcher.cc
index 52c2d8f8279..a3578526e1c 100644
--- a/chromium/services/ui/ws/event_dispatcher.cc
+++ b/chromium/services/ui/ws/event_dispatcher.cc
@@ -205,7 +205,7 @@ const ServerWindow* EventDispatcher::GetWindowForMouseCursor() const {
const ClientSpecificId target_client_id = delegate_->GetEventTargetClientId(
mouse_cursor_source_window_, mouse_cursor_in_non_client_area_);
const ServerWindow* window = mouse_cursor_source_window_;
- while (window && window->id().client_id == target_client_id)
+ while (window && window->owning_tree_id() == target_client_id)
window = window->parent();
return window;
}
diff --git a/chromium/services/ui/ws/event_dispatcher_unittest.cc b/chromium/services/ui/ws/event_dispatcher_unittest.cc
index ac2e3bdfa53..e68eb6c404f 100644
--- a/chromium/services/ui/ws/event_dispatcher_unittest.cc
+++ b/chromium/services/ui/ws/event_dispatcher_unittest.cc
@@ -13,7 +13,9 @@
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
+#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_task_environment.h"
+#include "components/viz/common/features.h"
#include "components/viz/host/hit_test/hit_test_query.h"
#include "services/ui/common/accelerator_util.h"
#include "services/ui/common/switches.h"
@@ -311,10 +313,10 @@ class EventDispatcherTest : public testing::TestWithParam<bool>,
// Deletes everything created during SetUp()
void ClearSetup();
std::unique_ptr<ServerWindow> CreateChildWindowWithParent(
- const WindowId& id,
+ const viz::FrameSinkId& id,
ServerWindow* parent);
// Creates a window which is a child of |root_window_|.
- std::unique_ptr<ServerWindow> CreateChildWindow(const WindowId& id);
+ std::unique_ptr<ServerWindow> CreateChildWindow(const viz::FrameSinkId& id);
bool IsMouseButtonDown() const;
bool IsWindowPointerTarget(const ServerWindow* window) const;
int NumberPointerTargetsForWindow(ServerWindow* window) const;
@@ -393,7 +395,7 @@ void EventDispatcherTest::ClearSetup() {
}
std::unique_ptr<ServerWindow> EventDispatcherTest::CreateChildWindowWithParent(
- const WindowId& id,
+ const viz::FrameSinkId& id,
ServerWindow* parent) {
std::unique_ptr<ServerWindow> child(
new ServerWindow(window_delegate_.get(), id));
@@ -403,7 +405,7 @@ std::unique_ptr<ServerWindow> EventDispatcherTest::CreateChildWindowWithParent(
}
std::unique_ptr<ServerWindow> EventDispatcherTest::CreateChildWindow(
- const WindowId& id) {
+ const viz::FrameSinkId& id) {
return CreateChildWindowWithParent(id, root_window_.get());
}
@@ -446,8 +448,8 @@ void EventDispatcherTest::SetUp() {
window_delegate_ =
std::make_unique<TestServerWindowDelegate>(viz_host_proxy());
- root_window_ =
- std::make_unique<ServerWindow>(window_delegate_.get(), WindowId(1, 2));
+ root_window_ = std::make_unique<ServerWindow>(window_delegate_.get(),
+ viz::FrameSinkId(1, 2));
root_window_->set_is_activation_parent(true);
window_delegate_->set_root_window(root_window_.get());
root_window_->SetVisible(true);
@@ -490,7 +492,7 @@ class EventDispatcherVizTargeterTest
runloop.RunUntilIdle();
}
- std::unique_ptr<ServerWindow> CreateChildWindow(const WindowId& id) {
+ std::unique_ptr<ServerWindow> CreateChildWindow(const viz::FrameSinkId& id) {
std::unique_ptr<ServerWindow> child(
new ServerWindow(window_delegate_.get(), id));
root_window_->Add(child.get());
@@ -510,6 +512,7 @@ class EventDispatcherVizTargeterTest
event_dispatcher_->SetCaptureWindow(nullptr, kInvalidClientId);
}
+ base::test::ScopedFeatureList feature_list_;
WindowServerTestHelper ws_test_helper_;
std::unique_ptr<TestServerWindowDelegate> window_delegate_;
@@ -522,8 +525,7 @@ class EventDispatcherVizTargeterTest
};
void EventDispatcherVizTargeterTest::SetUp() {
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kUseVizHitTest);
+ feature_list_.InitAndEnableFeature(features::kEnableVizHitTestDrawQuad);
if (is_event_processing_async()) {
base::CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kUseAsyncEventTargeting);
@@ -532,8 +534,8 @@ void EventDispatcherVizTargeterTest::SetUp() {
window_delegate_ =
std::make_unique<TestServerWindowDelegate>(viz_host_proxy());
- root_window_ =
- std::make_unique<ServerWindow>(window_delegate_.get(), WindowId(1, 2));
+ root_window_ = std::make_unique<ServerWindow>(window_delegate_.get(),
+ viz::FrameSinkId(1, 2));
root_window_->set_is_activation_parent(true);
window_delegate_->set_root_window(root_window_.get());
root_window_->SetVisible(true);
@@ -558,7 +560,8 @@ void EventDispatcherVizTargeterTest::SetUp() {
}
TEST_P(EventDispatcherTest, ProcessEvent) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -702,7 +705,8 @@ TEST_P(EventDispatcherTest, PostTargetAccelerator) {
EXPECT_FALSE(details);
// Set focused window for EventDispatcher dispatches key events.
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
event_dispatcher_delegate->SetFocusedWindowFromEventDispatcher(child.get());
// With a focused window the event should be dispatched.
@@ -747,7 +751,8 @@ TEST_P(EventDispatcherTest, ProcessPost) {
}
// Set focused window for EventDispatcher dispatches key events.
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
event_dispatcher_delegate->SetFocusedWindowFromEventDispatcher(child.get());
// Dispatch for ANY, which should trigger PRE and not call
@@ -771,7 +776,8 @@ TEST_P(EventDispatcherTest, ProcessPost) {
TEST_P(EventDispatcherTest, Capture) {
ServerWindow* root = root_window();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -817,7 +823,8 @@ TEST_P(EventDispatcherTest, Capture) {
}
TEST_P(EventDispatcherTest, CaptureMultipleMouseButtons) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -863,7 +870,8 @@ TEST_P(EventDispatcherTest, CaptureMultipleMouseButtons) {
}
TEST_P(EventDispatcherTest, ClientAreaGoesToOwner) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -936,7 +944,8 @@ TEST_P(EventDispatcherTest, ClientAreaGoesToOwner) {
}
TEST_P(EventDispatcherTest, AdditionalClientArea) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -963,7 +972,8 @@ TEST_P(EventDispatcherTest, AdditionalClientArea) {
}
TEST_P(EventDispatcherTest, HitTestMask) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1004,7 +1014,8 @@ TEST_P(EventDispatcherTest, HitTestMask) {
}
TEST_P(EventDispatcherTest, DontFocusOnSecondDown) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1027,8 +1038,10 @@ TEST_P(EventDispatcherTest, DontFocusOnSecondDown) {
}
TEST_P(EventDispatcherTest, TwoPointersActive) {
- std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4));
+ std::unique_ptr<ServerWindow> child1 =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> child2 =
+ CreateChildWindow(viz::FrameSinkId(1, 4));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child1->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1099,7 +1112,8 @@ TEST_P(EventDispatcherTest, TwoPointersActive) {
}
TEST_P(EventDispatcherTest, DestroyWindowWhileGettingEvents) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1133,7 +1147,8 @@ TEST_P(EventDispatcherTest, DestroyWindowWhileGettingEvents) {
TEST_P(EventDispatcherTest, MouseInExtendedHitTestRegion) {
ServerWindow* root = root_window();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1185,8 +1200,10 @@ TEST_P(EventDispatcherTest, MouseInExtendedHitTestRegion) {
}
TEST_P(EventDispatcherTest, WheelWhileDown) {
- std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4));
+ std::unique_ptr<ServerWindow> child1 =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> child2 =
+ CreateChildWindow(viz::FrameSinkId(1, 4));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child1->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1216,7 +1233,8 @@ TEST_P(EventDispatcherTest, WheelWhileDown) {
// appropriate target window.
TEST_P(EventDispatcherTest, SetExplicitCapture) {
ServerWindow* root = root_window();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1318,7 +1336,8 @@ TEST_P(EventDispatcherTest, SetExplicitCapture) {
// capture.
TEST_P(EventDispatcherTest, ExplicitCaptureOverridesImplicitCapture) {
ServerWindow* root = root_window();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1449,8 +1468,10 @@ TEST_P(EventDispatcherTest, CaptureUpdatesActivePointerTargets) {
// Tests that when explicit capture is changed, that the previous window with
// capture is no longer being observed.
TEST_P(EventDispatcherTest, UpdatingCaptureStopsObservingPreviousCapture) {
- std::unique_ptr<ServerWindow> child1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> child2 = CreateChildWindow(WindowId(1, 4));
+ std::unique_ptr<ServerWindow> child1 =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> child2 =
+ CreateChildWindow(viz::FrameSinkId(1, 4));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child1->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1472,7 +1493,8 @@ TEST_P(EventDispatcherTest, UpdatingCaptureStopsObservingPreviousCapture) {
// Tests that destroying a window with explicit capture clears the capture
// state.
TEST_P(EventDispatcherTest, DestroyingCaptureWindowRemovesExplicitCapture) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
EventDispatcher* dispatcher = event_dispatcher();
@@ -1514,7 +1536,8 @@ TEST_P(EventDispatcherTest, CaptureInNonClientAreaOverridesActualPoint) {
}
TEST_P(EventDispatcherTest, ProcessPointerEvents) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1564,7 +1587,8 @@ TEST_P(EventDispatcherTest, ProcessPointerEvents) {
}
TEST_P(EventDispatcherTest, ResetClearsPointerDown) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -1603,8 +1627,8 @@ TEST_P(EventDispatcherTest, ResetClearsCapture) {
// Tests that events on a parent of a modal window are blocked.
TEST_P(EventDispatcherTest, ModalWindowEventOnModalParent) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 5));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1656,8 +1680,8 @@ TEST_P(EventDispatcherTest, ModalWindowEventOnModalParent) {
// Tests that events on a modal child target the modal child itself.
TEST_P(EventDispatcherTest, ModalWindowEventOnModalChild) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 5));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1690,9 +1714,9 @@ TEST_P(EventDispatcherTest, ModalWindowEventOnModalChild) {
// Tests that events on an unrelated window are not affected by the modal
// window.
TEST_P(EventDispatcherTest, ModalWindowEventOnUnrelatedWindow) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
- std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 6));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 5));
+ std::unique_ptr<ServerWindow> w3 = CreateChildWindow(viz::FrameSinkId(1, 6));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1725,10 +1749,10 @@ TEST_P(EventDispatcherTest, ModalWindowEventOnUnrelatedWindow) {
// Tests that events on a descendant of a modal parent target the modal child.
TEST_P(EventDispatcherTest, ModalWindowEventOnDescendantOfModalParent) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
std::unique_ptr<ServerWindow> w11 =
- CreateChildWindowWithParent(WindowId(1, 4), w1.get());
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
+ CreateChildWindowWithParent(viz::FrameSinkId(1, 4), w1.get());
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 5));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1756,10 +1780,10 @@ TEST_P(EventDispatcherTest,
ModalWindowEventOnDescendantOfModalParentWithFallback) {
test_event_dispatcher_delegate()->EnableFallbackToRoot();
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
std::unique_ptr<ServerWindow> w11 =
- CreateChildWindowWithParent(WindowId(1, 4), w1.get());
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
+ CreateChildWindowWithParent(viz::FrameSinkId(1, 4), w1.get());
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 5));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1792,7 +1816,7 @@ TEST_P(EventDispatcherTest,
// Tests that events on a system modal window target the modal window itself.
TEST_P(EventDispatcherTest, ModalWindowEventOnSystemModal) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1821,7 +1845,7 @@ TEST_P(EventDispatcherTest, ModalWindowEventOnSystemModal) {
// Tests that events outside of system modal window target the modal window.
TEST_P(EventDispatcherTest, ModalWindowEventOutsideSystemModal) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1846,7 +1870,7 @@ TEST_P(EventDispatcherTest, ModalWindowEventOutsideSystemModal) {
TEST_P(EventDispatcherTest, ModalWindowEventOutsideSystemModalWithFallback) {
test_event_dispatcher_delegate()->EnableFallbackToRoot();
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1876,13 +1900,13 @@ TEST_P(EventDispatcherTest, ModalWindowEventOutsideSystemModalWithFallback) {
// Tests events on a sub-window of system modal window target the window itself.
TEST_P(EventDispatcherTest, ModalWindowEventSubWindowSystemModal) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
w1->SetModalType(MODAL_TYPE_SYSTEM);
event_dispatcher()->AddSystemModalWindow(w1.get());
std::unique_ptr<ServerWindow> w2 =
- CreateChildWindowWithParent(WindowId(1, 4), w1.get());
- std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 5));
+ CreateChildWindowWithParent(viz::FrameSinkId(1, 4), w1.get());
+ std::unique_ptr<ServerWindow> w3 = CreateChildWindow(viz::FrameSinkId(1, 5));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1927,10 +1951,10 @@ TEST_P(EventDispatcherTest, ModalWindowEventSubWindowSystemModal) {
// Tests that setting capture to a descendant of a modal parent fails.
TEST_P(EventDispatcherTest, ModalWindowSetCaptureDescendantOfModalParent) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
std::unique_ptr<ServerWindow> w11 =
- CreateChildWindowWithParent(WindowId(1, 4), w1.get());
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
+ CreateChildWindowWithParent(viz::FrameSinkId(1, 4), w1.get());
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 5));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1946,9 +1970,9 @@ TEST_P(EventDispatcherTest, ModalWindowSetCaptureDescendantOfModalParent) {
// Tests that setting capture to a window unrelated to a modal parent works.
TEST_P(EventDispatcherTest, ModalWindowSetCaptureUnrelatedWindow) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4));
- std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 5));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 4));
+ std::unique_ptr<ServerWindow> w3 = CreateChildWindow(viz::FrameSinkId(1, 5));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1964,8 +1988,8 @@ TEST_P(EventDispatcherTest, ModalWindowSetCaptureUnrelatedWindow) {
// Tests that setting capture fails when there is a system modal window.
TEST_P(EventDispatcherTest, ModalWindowSystemSetCapture) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 4));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -1980,9 +2004,9 @@ TEST_P(EventDispatcherTest, ModalWindowSystemSetCapture) {
// Tests having multiple system modal windows.
TEST_P(EventDispatcherTest, ModalWindowMultipleSystemModals) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4));
- std::unique_ptr<ServerWindow> w3 = CreateChildWindow(WindowId(1, 5));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 4));
+ std::unique_ptr<ServerWindow> w3 = CreateChildWindow(viz::FrameSinkId(1, 5));
w2->SetVisible(false);
@@ -2025,11 +2049,11 @@ TEST_P(EventDispatcherTest, ModalWindowMultipleSystemModals) {
}
TEST_P(EventDispatcherTest, CaptureNotResetOnParentChange) {
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
w1->set_event_targeting_policy(mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
std::unique_ptr<ServerWindow> w11 =
- CreateChildWindowWithParent(WindowId(1, 4), w1.get());
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 5));
+ CreateChildWindowWithParent(viz::FrameSinkId(1, 4), w1.get());
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 5));
w2->set_event_targeting_policy(mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
@@ -2060,7 +2084,8 @@ TEST_P(EventDispatcherTest, CaptureNotResetOnParentChange) {
}
TEST_P(EventDispatcherTest, ChangeCaptureFromClientToNonclient) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
event_dispatcher()->SetCaptureWindow(child.get(), kNonclientAreaId);
EXPECT_EQ(kNonclientAreaId,
event_dispatcher()->capture_window_client_id());
@@ -2078,7 +2103,8 @@ TEST_P(EventDispatcherTest, MoveMouseFromNoTargetToValidTarget) {
ServerWindow* root = root_window();
root->set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -2106,7 +2132,8 @@ TEST_P(EventDispatcherTest, NoTargetToTargetWithMouseDown) {
ServerWindow* root = root_window();
root->set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -2141,8 +2168,8 @@ TEST_P(EventDispatcherTest, DontSendExitToSameClientWhenCaptureChanges) {
ServerWindow* root = root_window();
root->set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
- std::unique_ptr<ServerWindow> c1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> c2 = CreateChildWindow(WindowId(1, 4));
+ std::unique_ptr<ServerWindow> c1 = CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> c2 = CreateChildWindow(viz::FrameSinkId(1, 4));
root->SetBounds(gfx::Rect(0, 0, 100, 100));
c1->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -2175,7 +2202,7 @@ TEST_P(EventDispatcherTest, DontSendExitToSameClientWhenCaptureChanges) {
TEST_P(EventDispatcherTest, MousePointerClearedOnDestroy) {
root_window()->set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
- std::unique_ptr<ServerWindow> c1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> c1 = CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
c1->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -2192,7 +2219,8 @@ TEST_P(EventDispatcherTest, MousePointerClearedOnDestroy) {
}
TEST_P(EventDispatcherTest, LocationHonorsTransform) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
gfx::Transform transform;
transform.Scale(SkIntToMScalar(2), SkIntToMScalar(2));
@@ -2244,7 +2272,8 @@ TEST_P(EventDispatcherTest, KeyDoesntHideCursorWithNoList) {
event_dispatcher_delegate->last_cursor_visibility());
// Set focused window for EventDispatcher dispatches key events.
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
event_dispatcher_delegate->SetFocusedWindowFromEventDispatcher(child.get());
ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
@@ -2264,7 +2293,8 @@ TEST_P(EventDispatcherTest, KeyDoesntHideCursorOnMatch) {
// Set focused window for EventDispatcher dispatches key events.
TestEventDispatcherDelegate* event_dispatcher_delegate =
test_event_dispatcher_delegate();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
event_dispatcher_delegate->SetFocusedWindowFromEventDispatcher(child.get());
ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
@@ -2284,7 +2314,8 @@ TEST_P(EventDispatcherTest, KeyHidesCursorOnNoMatch) {
// Set focused window for EventDispatcher dispatches key events.
TestEventDispatcherDelegate* event_dispatcher_delegate =
test_event_dispatcher_delegate();
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
event_dispatcher_delegate->SetFocusedWindowFromEventDispatcher(child.get());
ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
@@ -2297,9 +2328,9 @@ TEST_P(EventDispatcherTest, KeyHidesCursorOnNoMatch) {
TEST_P(EventDispatcherTest, ChildModal) {
std::unique_ptr<ServerWindow> modal_parent =
- CreateChildWindow(WindowId(1, 3));
+ CreateChildWindow(viz::FrameSinkId(1, 3));
std::unique_ptr<ServerWindow> child_modal_window =
- CreateChildWindow(WindowId(1, 4));
+ CreateChildWindow(viz::FrameSinkId(1, 4));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
modal_parent->SetBounds(gfx::Rect(10, 10, 30, 30));
@@ -2323,12 +2354,12 @@ TEST_P(EventDispatcherTest, ChildModal) {
TEST_P(EventDispatcherTest, DontCancelWhenMovedToSeparateDisplay) {
TestServerWindowDelegate window_delegate2(viz_host_proxy());
- ServerWindow root2(&window_delegate2, WindowId(1, 100));
+ ServerWindow root2(&window_delegate2, viz::FrameSinkId(1, 100));
root2.set_is_activation_parent(true);
window_delegate2.set_root_window(&root2);
root2.SetVisible(true);
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
event_dispatcher()->SetCaptureWindow(w1.get(), kClientAreaId);
ASSERT_EQ(w1.get(), event_dispatcher()->capture_window());
test_event_dispatcher_delegate()->set_root(&root2);
@@ -2344,8 +2375,8 @@ TEST_P(EventDispatcherTest, MouseCursorSourceWindowChangesWithSystemModal) {
event_dispatcher()->modal_window_controller()->SetBlockingContainers(
{blocking_containers});
- std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
- std::unique_ptr<ServerWindow> w2 = CreateChildWindow(WindowId(1, 4));
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(viz::FrameSinkId(1, 3));
+ std::unique_ptr<ServerWindow> w2 = CreateChildWindow(viz::FrameSinkId(1, 4));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
root_window()->set_is_activation_parent(true);
@@ -2374,7 +2405,8 @@ TEST_P(EventDispatcherTest, DontQueryWhileMouseIsDown) {
if (!is_event_processing_async())
return;
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
@@ -2396,7 +2428,8 @@ TEST_P(EventDispatcherTest, DontQueryWhileMouseIsDown) {
}
TEST_P(EventDispatcherVizTargeterTest, ProcessEvent) {
- std::unique_ptr<ServerWindow> child = CreateChildWindow(WindowId(1, 3));
+ std::unique_ptr<ServerWindow> child =
+ CreateChildWindow(viz::FrameSinkId(1, 3));
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
child->SetBounds(gfx::Rect(10, 10, 20, 20));
diff --git a/chromium/services/ui/ws/event_targeter.cc b/chromium/services/ui/ws/event_targeter.cc
index 0bae4d8da24..4d5c6577846 100644
--- a/chromium/services/ui/ws/event_targeter.cc
+++ b/chromium/services/ui/ws/event_targeter.cc
@@ -9,6 +9,7 @@
#include "base/metrics/user_metrics.h"
#include "base/task_scheduler/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/viz/common/features.h"
#include "components/viz/host/hit_test/hit_test_query.h"
#include "services/ui/common/switches.h"
#include "services/ui/ws/event_location.h"
@@ -47,8 +48,7 @@ void EventTargeter::FindTargetForLocationNow(
ServerWindow* root = event_targeter_delegate_->GetRootWindowForDisplay(
event_location.display_id);
DeepestWindow deepest_window;
- if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kUseVizHitTest)) {
+ if (!features::IsVizHitTestingEnabled()) {
if (root) {
deepest_window = ui::ws::FindDeepestVisibleWindowForLocation(
root, event_source, gfx::ToFlooredPoint(event_location.raw_location));
@@ -59,7 +59,7 @@ void EventTargeter::FindTargetForLocationNow(
event_location.display_id);
if (hit_test_query) {
viz::Target target = hit_test_query->FindTargetForLocation(
- event_source, gfx::ToFlooredPoint(event_location.raw_location));
+ event_source, event_location.raw_location);
if (target.frame_sink_id.is_valid()) {
ServerWindow* target_window =
event_targeter_delegate_->GetWindowFromFrameSinkId(
diff --git a/chromium/services/ui/ws/focus_controller_unittest.cc b/chromium/services/ui/ws/focus_controller_unittest.cc
index 985334d1b5c..4b8498f257c 100644
--- a/chromium/services/ui/ws/focus_controller_unittest.cc
+++ b/chromium/services/ui/ws/focus_controller_unittest.cc
@@ -92,21 +92,21 @@ class FocusControllerTest : public testing::Test {
TEST_F(FocusControllerTest, Basic) {
TestServerWindowDelegate server_window_delegate(viz_host_proxy());
- ServerWindow root(&server_window_delegate, WindowId(1, 1));
+ ServerWindow root(&server_window_delegate, viz::FrameSinkId(1, 1));
server_window_delegate.set_root_window(&root);
root.SetVisible(true);
root.set_is_activation_parent(true);
- ServerWindow child(&server_window_delegate, WindowId(1, 2));
+ ServerWindow child(&server_window_delegate, viz::FrameSinkId(1, 2));
child.SetVisible(true);
child.set_is_activation_parent(true);
root.Add(&child);
- ServerWindow child_child(&server_window_delegate, WindowId(1, 3));
+ ServerWindow child_child(&server_window_delegate, viz::FrameSinkId(1, 3));
child_child.SetVisible(true);
child.Add(&child_child);
child_child.set_is_activation_parent(true);
// Sibling of |child|.
- ServerWindow child2(&server_window_delegate, WindowId(1, 4));
+ ServerWindow child2(&server_window_delegate, viz::FrameSinkId(1, 4));
child2.SetVisible(true);
root.Add(&child2);
@@ -191,19 +191,19 @@ class TestServerWindowDelegate2 : public ServerWindowDelegate {
TEST_F(FocusControllerTest, ActiveWindowMovesToDifferentDisplay) {
TestServerWindowDelegate2 server_window_delegate(viz_host_proxy());
- ServerWindow root1(&server_window_delegate, WindowId(1, 1));
+ ServerWindow root1(&server_window_delegate, viz::FrameSinkId(1, 1));
root1.SetVisible(true);
root1.set_is_activation_parent(true);
- ServerWindow root2(&server_window_delegate, WindowId(1, 2));
+ ServerWindow root2(&server_window_delegate, viz::FrameSinkId(1, 2));
root2.SetVisible(true);
root2.set_is_activation_parent(true);
- ServerWindow child(&server_window_delegate, WindowId(1, 3));
+ ServerWindow child(&server_window_delegate, viz::FrameSinkId(1, 3));
root1.Add(&child);
child.SetVisible(true);
child.set_is_activation_parent(true);
- ServerWindow child_child(&server_window_delegate, WindowId(1, 4));
+ ServerWindow child_child(&server_window_delegate, viz::FrameSinkId(1, 4));
child.Add(&child_child);
child_child.SetVisible(true);
diff --git a/chromium/services/ui/ws/frame_generator_unittest.cc b/chromium/services/ui/ws/frame_generator_unittest.cc
index 99998d17180..32202bcc22a 100644
--- a/chromium/services/ui/ws/frame_generator_unittest.cc
+++ b/chromium/services/ui/ws/frame_generator_unittest.cc
@@ -55,6 +55,11 @@ class TestClientBinding : public viz::mojom::CompositorFrameSink,
last_begin_frame_ack_ = ack;
}
+ void DidAllocateSharedBitmap(mojo::ScopedSharedBufferHandle buffer,
+ const viz::SharedBitmapId& id) override {}
+
+ void DidDeleteSharedBitmap(const viz::SharedBitmapId& id) override {}
+
void SetNeedsBeginFrame(bool needs_begin_frame) override {
if (needs_begin_frame == observing_begin_frames_)
return;
diff --git a/chromium/services/ui/ws/gpu_host.cc b/chromium/services/ui/ws/gpu_host.cc
index 938c2bdc4df..87e28b7d4ec 100644
--- a/chromium/services/ui/ws/gpu_host.cc
+++ b/chromium/services/ui/ws/gpu_host.cc
@@ -10,6 +10,7 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "components/discardable_memory/service/discardable_shared_memory_manager.h"
#include "components/viz/host/server_gpu_memory_buffer_manager.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "gpu/ipc/client/gpu_memory_buffer_impl_shared_memory.h"
@@ -46,15 +47,18 @@ bool HasSplitVizProcess() {
} // namespace
-DefaultGpuHost::DefaultGpuHost(GpuHostDelegate* delegate,
- service_manager::Connector* connector)
+DefaultGpuHost::DefaultGpuHost(
+ GpuHostDelegate* delegate,
+ service_manager::Connector* connector,
+ discardable_memory::DiscardableSharedMemoryManager*
+ discardable_shared_memory_manager)
: delegate_(delegate),
next_client_id_(kInternalGpuChannelClientId + 1),
main_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
gpu_host_binding_(this),
- gpu_thread_("GpuThread"),
- viz_main_wait_(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED) {
+ gpu_thread_("GpuThread") {
+ DCHECK(discardable_shared_memory_manager);
+
auto request = MakeRequest(&viz_main_);
if (connector && HasSplitVizProcess()) {
connector->BindInterface(viz::mojom::kVizServiceName, std::move(request));
@@ -67,11 +71,17 @@ DefaultGpuHost::DefaultGpuHost(GpuHostDelegate* delegate,
base::Passed(MakeRequest(&viz_main_))));
}
+ discardable_memory::mojom::DiscardableSharedMemoryManagerPtr
+ discardable_manager_ptr;
+ service_manager::BindSourceInfo source_info;
+ discardable_shared_memory_manager->Bind(
+ mojo::MakeRequest(&discardable_manager_ptr), source_info);
+
viz::mojom::GpuHostPtr gpu_host_proxy;
gpu_host_binding_.Bind(mojo::MakeRequest(&gpu_host_proxy));
- viz_main_->CreateGpuService(MakeRequest(&gpu_service_),
- std::move(gpu_host_proxy),
- mojo::ScopedSharedBufferHandle());
+ viz_main_->CreateGpuService(
+ MakeRequest(&gpu_service_), std::move(gpu_host_proxy),
+ std::move(discardable_manager_ptr), mojo::ScopedSharedBufferHandle());
gpu_memory_buffer_manager_ =
std::make_unique<viz::ServerGpuMemoryBufferManager>(gpu_service_.get(),
next_client_id_++);
@@ -79,12 +89,11 @@ DefaultGpuHost::DefaultGpuHost(GpuHostDelegate* delegate,
DefaultGpuHost::~DefaultGpuHost() {
// TODO(crbug.com/620927): This should be removed once ozone-mojo is done.
- // Make sure |viz_main_impl_| has been successfully created (i.e. the task
- // posted in the constructor to run InitializeVizMain() has actually run).
if (gpu_thread_.IsRunning()) {
- viz_main_wait_.Wait();
- viz_main_impl_->TearDown();
- gpu_thread_.task_runner()->DeleteSoon(FROM_HERE, std::move(viz_main_impl_));
+ // Stop() will return after |viz_main_impl_| has been destroyed.
+ gpu_thread_.task_runner()->PostTask(
+ FROM_HERE, base::BindOnce(&DefaultGpuHost::DestroyVizMain,
+ base::Unretained(this)));
gpu_thread_.Stop();
}
}
@@ -139,7 +148,11 @@ void DefaultGpuHost::InitializeVizMain(viz::mojom::VizMainRequest request) {
deps.create_display_compositor = true;
viz_main_impl_ = std::make_unique<viz::VizMainImpl>(nullptr, std::move(deps));
viz_main_impl_->Bind(std::move(request));
- viz_main_wait_.Signal();
+}
+
+void DefaultGpuHost::DestroyVizMain() {
+ DCHECK(viz_main_impl_);
+ viz_main_impl_.reset();
}
void DefaultGpuHost::DidInitialize(
diff --git a/chromium/services/ui/ws/gpu_host.h b/chromium/services/ui/ws/gpu_host.h
index bb51cabce9d..e2f8b25bf92 100644
--- a/chromium/services/ui/ws/gpu_host.h
+++ b/chromium/services/ui/ws/gpu_host.h
@@ -6,7 +6,6 @@
#define SERVICES_UI_WS_GPU_HOST_H_
#include "base/single_thread_task_runner.h"
-#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "components/viz/service/main/viz_main_impl.h"
@@ -24,6 +23,10 @@
#include "services/ui/public/interfaces/arc.mojom.h"
#endif // defined(OS_CHROMEOS)
+namespace discardable_memory {
+class DiscardableSharedMemoryManager;
+}
+
namespace service_manager {
class Connector;
}
@@ -67,7 +70,9 @@ class GpuHost {
class DefaultGpuHost : public GpuHost, public viz::mojom::GpuHost {
public:
DefaultGpuHost(GpuHostDelegate* delegate,
- service_manager::Connector* connector);
+ service_manager::Connector* connector,
+ discardable_memory::DiscardableSharedMemoryManager*
+ discardable_shared_memory_manager);
~DefaultGpuHost() override;
private:
@@ -78,6 +83,7 @@ class DefaultGpuHost : public GpuHost, public viz::mojom::GpuHost {
// TODO(crbug.com/611505): this goes away after the gpu proces split in mus.
void InitializeVizMain(viz::mojom::VizMainRequest request);
+ void DestroyVizMain();
// GpuHost:
void Add(mojom::GpuRequest request) override;
@@ -123,9 +129,6 @@ class DefaultGpuHost : public GpuHost, public viz::mojom::GpuHost {
// TODO(crbug.com/620927): This should be removed once ozone-mojo is done.
base::Thread gpu_thread_;
std::unique_ptr<viz::VizMainImpl> viz_main_impl_;
- // This is used to make sure that the |viz_main_impl_| has been set up
- // correctly, before we start tearing it down.
- base::WaitableEvent viz_main_wait_;
mojo::StrongBindingSet<mojom::Gpu> gpu_bindings_;
#if defined(OS_CHROMEOS)
diff --git a/chromium/services/ui/ws/gpu_host_unittest.cc b/chromium/services/ui/ws/gpu_host_unittest.cc
index db5af3c99cf..7af0d907047 100644
--- a/chromium/services/ui/ws/gpu_host_unittest.cc
+++ b/chromium/services/ui/ws/gpu_host_unittest.cc
@@ -9,6 +9,7 @@
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/single_thread_task_runner.h"
+#include "components/discardable_memory/service/discardable_shared_memory_manager.h"
#include "components/viz/service/gl/gpu_service_impl.h"
#include "gpu/config/gpu_info.h"
#include "services/ui/public/interfaces/gpu.mojom.h"
@@ -85,6 +86,8 @@ class GpuHostTest : public testing::Test {
base::Thread io_thread_;
TestGpuHostDelegate gpu_host_delegate_;
+ discardable_memory::DiscardableSharedMemoryManager
+ discardable_memory_manager_;
std::unique_ptr<TestGpuService> gpu_service_;
viz::mojom::GpuServicePtr gpu_service_ptr_;
std::unique_ptr<DefaultGpuHost> gpu_host_;
@@ -103,7 +106,8 @@ void GpuHostTest::DestroyHost() {
void GpuHostTest::SetUp() {
testing::Test::SetUp();
- gpu_host_ = std::make_unique<DefaultGpuHost>(&gpu_host_delegate_, nullptr);
+ gpu_host_ = std::make_unique<DefaultGpuHost>(&gpu_host_delegate_, nullptr,
+ &discardable_memory_manager_);
gpu_service_->Bind(mojo::MakeRequest(&gpu_service_ptr_));
gpu_host_->gpu_service_ = std::move(gpu_service_ptr_);
}
diff --git a/chromium/services/ui/ws/ids.h b/chromium/services/ui/ws/ids.h
index 113ec1701fd..7713711ebfd 100644
--- a/chromium/services/ui/ws/ids.h
+++ b/chromium/services/ui/ws/ids.h
@@ -7,15 +7,8 @@
#include <stdint.h>
-#include <string>
-#include <tuple>
-
-#include "base/containers/hash_tables.h"
-#include "base/hash.h"
-#include "base/strings/stringprintf.h"
#include "components/viz/common/surfaces/frame_sink_id.h"
#include "services/ui/common/types.h"
-#include "services/ui/common/util.h"
namespace ui {
namespace ws {
@@ -26,74 +19,14 @@ const ClientSpecificId kInvalidClientId = 0;
const Id kInvalidTransportId = 0;
-// A client id used to indicate WindowServer.
+// Client id used to indicate the window was created by the WindowServer.
const ClientSpecificId kWindowServerClientId = 1;
-// Every window has a unique id associated with it (WindowId). The id is a
-// combination of the id assigned to the client (the high order bits) and
-// a unique id for the window. Each client (WindowTree) refers to the window
-// by an id assigned by the client (ClientWindowId). To facilitate this
-// WindowTree maintains a mapping between WindowId and ClientWindowId.
-//
-// This model works when the client initiates creation of windows, which is
-// the typical use case. Embed roots and the WindowManager are special, they
-// get access to windows created by other clients. These clients see the
-// id assigned on the server. Such clients have to take care that they only
-// create windows using their client id. To do otherwise could result in
-// multiple windows having the same ClientWindowId. WindowTree enforces
-// that embed roots use the client id in creating the window id to avoid
-// possible conflicts.
-
// Used for ids assigned by the client.
using ClientWindowId = viz::FrameSinkId;
-struct WindowId {
- constexpr WindowId(ClientSpecificId client_id, ClientSpecificId window_id)
- : client_id(client_id), window_id(window_id) {}
- constexpr WindowId() : client_id(0), window_id(0) {}
-
- bool operator==(const WindowId& other) const {
- return other.client_id == client_id && other.window_id == window_id;
- }
-
- bool operator!=(const WindowId& other) const { return !(*this == other); }
-
- bool operator<(const WindowId& other) const {
- return std::tie(client_id, window_id) <
- std::tie(other.client_id, other.window_id);
- }
-
- std::string ToString() const {
- return base::StringPrintf("%u:%u", client_id, window_id);
- }
-
- ClientSpecificId client_id;
- ClientSpecificId window_id;
-};
-
-inline WindowId WindowIdFromTransportId(Id id) {
- return WindowId(HiWord(id), LoWord(id));
-}
-
-// Returns a WindowId that is reserved to indicate no window. That is, no window
-// will ever be created with this id.
-inline WindowId InvalidWindowId() {
- return WindowId(kInvalidClientId, 0);
-}
-
-// Returns a root window id with a given index offset.
-inline WindowId RootWindowId(uint16_t index) {
- return WindowId(kWindowServerClientId, 2 + index);
-}
-
using ClientWindowIdHash = viz::FrameSinkIdHash;
-struct WindowIdHash {
- size_t operator()(const WindowId& id) const {
- return (id.client_id << 16) | id.window_id;
- }
-};
-
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/modal_window_controller_unittest.cc b/chromium/services/ui/ws/modal_window_controller_unittest.cc
index d254f6a06f1..9eb1dbe1320 100644
--- a/chromium/services/ui/ws/modal_window_controller_unittest.cc
+++ b/chromium/services/ui/ws/modal_window_controller_unittest.cc
@@ -29,11 +29,11 @@ class ModalWindowControllerTest : public testing::Test {
TEST_F(ModalWindowControllerTest, MinContainer) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root_window(&window_delegate, WindowId(1, 1));
+ ServerWindow root_window(&window_delegate, viz::FrameSinkId(1, 1));
window_delegate.set_root_window(&root_window);
- ServerWindow container1(&window_delegate, WindowId(1, 2));
- ServerWindow container2(&window_delegate, WindowId(1, 3));
- ServerWindow container3(&window_delegate, WindowId(1, 4));
+ ServerWindow container1(&window_delegate, viz::FrameSinkId(1, 2));
+ ServerWindow container2(&window_delegate, viz::FrameSinkId(1, 3));
+ ServerWindow container3(&window_delegate, viz::FrameSinkId(1, 4));
root_window.SetVisible(true);
container1.SetVisible(true);
@@ -47,7 +47,7 @@ TEST_F(ModalWindowControllerTest, MinContainer) {
blocking_containers[0].min_container = &container2;
modal_window_controller.SetBlockingContainers(blocking_containers);
- ServerWindow window(&window_delegate, WindowId(1, 5));
+ ServerWindow window(&window_delegate, viz::FrameSinkId(1, 5));
window.SetVisible(true);
// Window should be blocked when not attached to hierarchy.
@@ -75,11 +75,11 @@ TEST_F(ModalWindowControllerTest, MinContainer) {
TEST_F(ModalWindowControllerTest, SystemModalContainer) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root_window(&window_delegate, WindowId(1, 1));
+ ServerWindow root_window(&window_delegate, viz::FrameSinkId(1, 1));
window_delegate.set_root_window(&root_window);
- ServerWindow container1(&window_delegate, WindowId(1, 2));
- ServerWindow container2(&window_delegate, WindowId(1, 3));
- ServerWindow container3(&window_delegate, WindowId(1, 4));
+ ServerWindow container1(&window_delegate, viz::FrameSinkId(1, 2));
+ ServerWindow container2(&window_delegate, viz::FrameSinkId(1, 3));
+ ServerWindow container3(&window_delegate, viz::FrameSinkId(1, 4));
root_window.SetVisible(true);
container1.SetVisible(true);
@@ -97,13 +97,13 @@ TEST_F(ModalWindowControllerTest, SystemModalContainer) {
blocking_containers[0].min_container = &container2;
modal_window_controller.SetBlockingContainers(blocking_containers);
- ServerWindow window(&window_delegate, WindowId(1, 5));
+ ServerWindow window(&window_delegate, viz::FrameSinkId(1, 5));
window.SetVisible(true);
container2.Add(&window);
EXPECT_FALSE(modal_window_controller.IsWindowBlocked(&window));
- ServerWindow modal_window(&window_delegate, WindowId(1, 6));
+ ServerWindow modal_window(&window_delegate, viz::FrameSinkId(1, 6));
modal_window.SetModalType(MODAL_TYPE_SYSTEM);
modal_window_controller.AddSystemModalWindow(&modal_window);
diff --git a/chromium/services/ui/ws/server_window.cc b/chromium/services/ui/ws/server_window.cc
index 3db7bb257ad..ced7f646761 100644
--- a/chromium/services/ui/ws/server_window.cc
+++ b/chromium/services/ui/ws/server_window.cc
@@ -20,29 +20,15 @@
namespace ui {
namespace ws {
-ServerWindow::ServerWindow(ServerWindowDelegate* delegate, const WindowId& id)
- : ServerWindow(delegate,
- id,
- viz::FrameSinkId(id.client_id, id.window_id),
- Properties()) {}
-
ServerWindow::ServerWindow(ServerWindowDelegate* delegate,
- const WindowId& id,
const viz::FrameSinkId& frame_sink_id,
const Properties& properties)
: delegate_(delegate),
- id_(id),
- parent_(nullptr),
- stacking_target_(nullptr),
- transient_parent_(nullptr),
- modal_type_(MODAL_TYPE_NONE),
- visible_(false),
+ owning_tree_id_(frame_sink_id.client_id()),
// Default to kPointer as kNull doesn't change the cursor, it leaves
// the last non-null cursor.
cursor_(ui::CursorType::kPointer),
non_client_cursor_(ui::CursorType::kPointer),
- opacity_(1),
- can_focus_(true),
properties_(properties),
// Don't notify newly added observers during notification. This causes
// problems for code that adds an observer as part of an observer
@@ -131,9 +117,7 @@ void ServerWindow::UpdateFrameSinkId(const viz::FrameSinkId& frame_sink_id) {
auto* host_frame_sink_manager = delegate_->GetVizHostProxy();
DCHECK(host_frame_sink_manager);
host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id, this);
-#if DCHECK_IS_ON()
host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id, GetName());
-#endif
if (frame_sink_id_.is_valid()) {
if (parent()) {
host_frame_sink_manager->UnregisterFrameSinkHierarchy(
@@ -269,19 +253,6 @@ const ServerWindow* ServerWindow::GetRootForDrawn() const {
return delegate_->GetRootWindowForDrawn(this);
}
-ServerWindow* ServerWindow::GetChildWindow(const WindowId& window_id) {
- if (id_ == window_id)
- return this;
-
- for (ServerWindow* child : children_) {
- ServerWindow* window = child->GetChildWindow(window_id);
- if (window)
- return window;
- }
-
- return nullptr;
-}
-
bool ServerWindow::AddTransientWindow(ServerWindow* child) {
if (child->transient_parent())
child->transient_parent()->RemoveTransientWindow(child);
@@ -413,11 +384,9 @@ void ServerWindow::SetProperty(const std::string& name,
} else if (it != properties_.end()) {
properties_.erase(it);
}
-#if DCHECK_IS_ON()
auto* host_frame_sink_manager = delegate_->GetVizHostProxy();
if (host_frame_sink_manager && name == mojom::WindowManager::kName_Property)
host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_, GetName());
-#endif
for (auto& observer : observers_)
observer.OnWindowSharedPropertyChanged(this, name, value);
@@ -487,10 +456,9 @@ std::string ServerWindow::GetDebugWindowInfo() const {
if (has_created_compositor_frame_sink_)
frame_sink = " [" + frame_sink_id_.ToString() + "]";
- return base::StringPrintf("id=%s visible=%s bounds=%s name=%s%s",
- id_.ToString().c_str(), visible_ ? "true" : "false",
- bounds_.ToString().c_str(), name.c_str(),
- frame_sink.c_str());
+ return base::StringPrintf(
+ "visible=%s bounds=%s name=%s%s", visible_ ? "true" : "false",
+ bounds_.ToString().c_str(), name.c_str(), frame_sink.c_str());
}
void ServerWindow::BuildDebugInfo(const std::string& depth,
diff --git a/chromium/services/ui/ws/server_window.h b/chromium/services/ui/ws/server_window.h
index 2b13a6e4cc6..673e8ad5004 100644
--- a/chromium/services/ui/ws/server_window.h
+++ b/chromium/services/ui/ws/server_window.h
@@ -52,13 +52,11 @@ class ServerWindow : public viz::HostFrameSinkClient {
using Properties = std::map<std::string, std::vector<uint8_t>>;
using Windows = std::vector<ServerWindow*>;
- ServerWindow(ServerWindowDelegate* delegate, const WindowId& id);
// |frame_sink_id| needs to be an input here as we are creating frame_sink_id_
// based on the ClientWindowId clients provided.
ServerWindow(ServerWindowDelegate* delegate,
- const WindowId& id,
const viz::FrameSinkId& frame_sink_id,
- const Properties& properties);
+ const Properties& properties = Properties());
~ServerWindow() override;
void AddObserver(ServerWindowObserver* observer);
@@ -78,7 +76,8 @@ class ServerWindow : public viz::HostFrameSinkClient {
viz::mojom::CompositorFrameSinkRequest request,
viz::mojom::CompositorFrameSinkClientPtr client);
- const WindowId& id() const { return id_; }
+ // Id of the tree that owns and created this window.
+ ClientSpecificId owning_tree_id() const { return owning_tree_id_; }
const viz::FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
void UpdateFrameSinkId(const viz::FrameSinkId& frame_sink_id);
@@ -139,10 +138,6 @@ class ServerWindow : public viz::HostFrameSinkClient {
const Windows& children() const { return children_; }
- // Returns the ServerWindow object with the provided |id| if it lies in a
- // subtree of |this|.
- ServerWindow* GetChildWindow(const WindowId& id);
-
// Transient window management.
// Adding transient child fails if the child window is modal to system.
bool AddTransientWindow(ServerWindow* child);
@@ -258,30 +253,32 @@ class ServerWindow : public viz::HostFrameSinkClient {
void OnStackingChanged();
ServerWindowDelegate* const delegate_;
- const WindowId id_;
+ // This is the client id of the WindowTree that owns this window. This is
+ // cached as the |frame_sink_id_| may change.
+ const ClientSpecificId owning_tree_id_;
// This may change for embed windows.
viz::FrameSinkId frame_sink_id_;
base::Optional<viz::LocalSurfaceId> current_local_surface_id_;
- ServerWindow* parent_;
+ ServerWindow* parent_ = nullptr;
Windows children_;
// Transient window management.
// If non-null we're actively restacking transient as the result of a
// transient ancestor changing.
- ServerWindow* stacking_target_;
- ServerWindow* transient_parent_;
+ ServerWindow* stacking_target_ = nullptr;
+ ServerWindow* transient_parent_ = nullptr;
Windows transient_children_;
- ModalType modal_type_;
- bool visible_;
+ ModalType modal_type_ = MODAL_TYPE_NONE;
+ bool visible_ = false;
gfx::Rect bounds_;
gfx::Insets client_area_;
std::vector<gfx::Rect> additional_client_areas_;
ui::CursorData cursor_;
ui::CursorData non_client_cursor_;
- float opacity_;
- bool can_focus_;
+ float opacity_ = 1.0f;
+ bool can_focus_ = true;
mojom::EventTargetingPolicy event_targeting_policy_ =
mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS;
gfx::Transform transform_;
diff --git a/chromium/services/ui/ws/server_window_drawn_tracker_unittest.cc b/chromium/services/ui/ws/server_window_drawn_tracker_unittest.cc
index 55f589bdb99..290d81110b7 100644
--- a/chromium/services/ui/ws/server_window_drawn_tracker_unittest.cc
+++ b/chromium/services/ui/ws/server_window_drawn_tracker_unittest.cc
@@ -70,10 +70,10 @@ class TestServerWindowDrawnTrackerObserver
DISALLOW_COPY_AND_ASSIGN(TestServerWindowDrawnTrackerObserver);
};
-WindowId MakeWindowId() {
+viz::FrameSinkId MakeFrameSinkId() {
constexpr int client_id = 1;
static int window_id = 0;
- return WindowId(client_id, ++window_id);
+ return viz::FrameSinkId(client_id, ++window_id);
}
} // namespace
@@ -96,7 +96,7 @@ class ServerWindowDrawnTrackerTest : public testing::Test {
TEST_F(ServerWindowDrawnTrackerTest, ChangeBecauseOfDeletionAndVisibility) {
TestServerWindowDelegate server_window_delegate(viz_host_proxy());
std::unique_ptr<ServerWindow> window(
- new ServerWindow(&server_window_delegate, MakeWindowId()));
+ new ServerWindow(&server_window_delegate, MakeFrameSinkId()));
server_window_delegate.set_root_window(window.get());
TestServerWindowDrawnTrackerObserver drawn_observer;
ServerWindowDrawnTracker tracker(window.get(), &drawn_observer);
@@ -139,10 +139,10 @@ TEST_F(ServerWindowDrawnTrackerTest, ChangeBecauseOfDeletionAndVisibility) {
TEST_F(ServerWindowDrawnTrackerTest, ChangeBecauseOfRemovingFromRoot) {
TestServerWindowDelegate server_window_delegate(viz_host_proxy());
- ServerWindow root(&server_window_delegate, MakeWindowId());
+ ServerWindow root(&server_window_delegate, MakeFrameSinkId());
server_window_delegate.set_root_window(&root);
root.SetVisible(true);
- ServerWindow child(&server_window_delegate, MakeWindowId());
+ ServerWindow child(&server_window_delegate, MakeFrameSinkId());
child.SetVisible(true);
root.Add(&child);
@@ -168,14 +168,14 @@ TEST_F(ServerWindowDrawnTrackerTest, ChangeBecauseOfRemovingFromRoot) {
TEST_F(ServerWindowDrawnTrackerTest, ChangeBecauseOfRemovingAncestorFromRoot) {
TestServerWindowDelegate server_window_delegate(viz_host_proxy());
- ServerWindow root(&server_window_delegate, MakeWindowId());
+ ServerWindow root(&server_window_delegate, MakeFrameSinkId());
server_window_delegate.set_root_window(&root);
root.SetVisible(true);
- ServerWindow child(&server_window_delegate, MakeWindowId());
+ ServerWindow child(&server_window_delegate, MakeFrameSinkId());
child.SetVisible(true);
root.Add(&child);
- ServerWindow child_child(&server_window_delegate, MakeWindowId());
+ ServerWindow child_child(&server_window_delegate, MakeFrameSinkId());
child_child.SetVisible(true);
child.Add(&child_child);
@@ -201,10 +201,10 @@ TEST_F(ServerWindowDrawnTrackerTest, ChangeBecauseOfRemovingAncestorFromRoot) {
TEST_F(ServerWindowDrawnTrackerTest, VisibilityChangeFromNonParentAncestor) {
TestServerWindowDelegate server_window_delegate(viz_host_proxy());
- ServerWindow root(&server_window_delegate, MakeWindowId());
- ServerWindow child1(&server_window_delegate, MakeWindowId());
- ServerWindow child2(&server_window_delegate, MakeWindowId());
- ServerWindow child3(&server_window_delegate, MakeWindowId());
+ ServerWindow root(&server_window_delegate, MakeFrameSinkId());
+ ServerWindow child1(&server_window_delegate, MakeFrameSinkId());
+ ServerWindow child2(&server_window_delegate, MakeFrameSinkId());
+ ServerWindow child3(&server_window_delegate, MakeFrameSinkId());
server_window_delegate.set_root_window(&root);
root.Add(&child1);
@@ -244,11 +244,11 @@ TEST_F(ServerWindowDrawnTrackerTest, VisibilityChangeFromNonParentAncestor) {
TEST_F(ServerWindowDrawnTrackerTest, TreeHierarchyChangeFromNonParentAncestor) {
TestServerWindowDelegate server_window_delegate(viz_host_proxy());
- ServerWindow root(&server_window_delegate, MakeWindowId());
- ServerWindow child1(&server_window_delegate, MakeWindowId());
- ServerWindow child2(&server_window_delegate, MakeWindowId());
- ServerWindow child11(&server_window_delegate, MakeWindowId());
- ServerWindow child111(&server_window_delegate, MakeWindowId());
+ ServerWindow root(&server_window_delegate, MakeFrameSinkId());
+ ServerWindow child1(&server_window_delegate, MakeFrameSinkId());
+ ServerWindow child2(&server_window_delegate, MakeFrameSinkId());
+ ServerWindow child11(&server_window_delegate, MakeFrameSinkId());
+ ServerWindow child111(&server_window_delegate, MakeFrameSinkId());
server_window_delegate.set_root_window(&root);
root.Add(&child1);
diff --git a/chromium/services/ui/ws/test_change_tracker.cc b/chromium/services/ui/ws/test_change_tracker.cc
index fb2518a327f..8b29a80a9f4 100644
--- a/chromium/services/ui/ws/test_change_tracker.cc
+++ b/chromium/services/ui/ws/test_change_tracker.cc
@@ -19,7 +19,8 @@ namespace ws {
std::string WindowIdToString(Id id) {
return (id == 0) ? "null"
- : base::StringPrintf("%d,%d", HiWord(id), LoWord(id));
+ : base::StringPrintf("%d,%d", ClientIdFromTransportId(id),
+ ClientWindowIdFromTransportId(id));
}
namespace {
@@ -404,7 +405,7 @@ void TestChangeTracker::OnWindowInputEvent(
}
void TestChangeTracker::OnPointerEventObserved(const ui::Event& event,
- uint32_t window_id) {
+ Id window_id) {
Change change;
change.type = CHANGE_TYPE_POINTER_WATCHER_EVENT;
change.event_action = static_cast<int32_t>(event.type());
diff --git a/chromium/services/ui/ws/test_change_tracker.h b/chromium/services/ui/ws/test_change_tracker.h
index 070d4cee058..c1b8f340f0c 100644
--- a/chromium/services/ui/ws/test_change_tracker.h
+++ b/chromium/services/ui/ws/test_change_tracker.h
@@ -179,8 +179,7 @@ class TestChangeTracker {
int64_t display_id,
const gfx::PointF& event_location_in_screen_pixel_layout,
bool matches_pointer_watcher);
- void OnPointerEventObserved(const ui::Event& event,
- uint32_t window_id);
+ void OnPointerEventObserved(const ui::Event& event, Id window_id);
void OnWindowSharedPropertyChanged(
Id window_id,
const std::string& name,
diff --git a/chromium/services/ui/ws/test_utils.cc b/chromium/services/ui/ws/test_utils.cc
index 2ba4e127167..9a3ee0e3d02 100644
--- a/chromium/services/ui/ws/test_utils.cc
+++ b/chromium/services/ui/ws/test_utils.cc
@@ -10,7 +10,7 @@
#include "base/strings/string_number_conversions.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "gpu/ipc/client/gpu_channel_host.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/ui/common/image_cursors_set.h"
#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/ws/cursor_location_manager.h"
@@ -204,9 +204,9 @@ bool EventDispatcherTestApi::IsObservingWindow(ServerWindow* window) {
WindowTree* TestDisplayBinding::CreateWindowTree(ServerWindow* root) {
const uint32_t embed_flags = 0;
WindowTree* tree = window_server_->EmbedAtWindow(
- root, service_manager::mojom::kRootUserID,
- ui::mojom::WindowTreeClientPtr(), embed_flags,
+ root, ui::mojom::WindowTreeClientPtr(), embed_flags,
base::WrapUnique(new WindowManagerAccessPolicy));
+ WindowTreeTestApi(tree).set_is_for_embedding(false);
tree->ConfigureWindowManager(automatically_create_display_roots_);
return tree;
}
@@ -238,7 +238,7 @@ void TestWindowManager::WmDisplayRemoved(int64_t display_id) {
display_removed_id_ = display_id;
}
-void TestWindowManager::WmSetModalType(uint32_t window_id, ui::ModalType type) {
+void TestWindowManager::WmSetModalType(Id window_id, ui::ModalType type) {
on_set_modal_type_called_ = true;
}
@@ -267,23 +267,23 @@ void TestWindowManager::WmMoveDragImage(
void TestWindowManager::WmDestroyDragImage() {}
void TestWindowManager::WmPerformMoveLoop(uint32_t change_id,
- uint32_t window_id,
+ Id window_id,
mojom::MoveLoopSource source,
const gfx::Point& cursor_location) {
on_perform_move_loop_called_ = true;
}
-void TestWindowManager::WmCancelMoveLoop(uint32_t window_id) {}
+void TestWindowManager::WmCancelMoveLoop(uint32_t change_id) {}
-void TestWindowManager::WmDeactivateWindow(uint32_t window_id) {}
+void TestWindowManager::WmDeactivateWindow(Id window_id) {}
void TestWindowManager::WmStackAbove(uint32_t change_id,
- uint32_t above_id,
- uint32_t below_id) {}
+ Id above_id,
+ Id below_id) {}
-void TestWindowManager::WmStackAtTop(uint32_t change_id, uint32_t window_id) {}
+void TestWindowManager::WmStackAtTop(uint32_t change_id, Id window_id) {}
-void TestWindowManager::WmPerformWmAction(uint32_t window_id,
+void TestWindowManager::WmPerformWmAction(Id window_id,
const std::string& action) {
last_wm_action_ = action;
}
@@ -297,7 +297,7 @@ void TestWindowManager::OnAccelerator(uint32_t ack_id,
void TestWindowManager::OnCursorTouchVisibleChanged(bool enabled) {}
-void TestWindowManager::OnEventBlockedByModalWindow(uint32_t window_id) {}
+void TestWindowManager::OnEventBlockedByModalWindow(Id window_id) {}
// TestWindowTreeClient -------------------------------------------------------
@@ -321,7 +321,7 @@ void TestWindowTreeClient::OnEmbed(
tracker_.OnEmbed(std::move(root), drawn);
}
-void TestWindowTreeClient::OnEmbeddedAppDisconnected(uint32_t window) {
+void TestWindowTreeClient::OnEmbeddedAppDisconnected(Id window) {
tracker_.OnEmbeddedAppDisconnected(window);
}
@@ -350,7 +350,7 @@ void TestWindowTreeClient::OnTopLevelCreated(
}
void TestWindowTreeClient::OnWindowBoundsChanged(
- uint32_t window,
+ Id window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
const base::Optional<viz::LocalSurfaceId>& local_surface_id) {
@@ -359,60 +359,57 @@ void TestWindowTreeClient::OnWindowBoundsChanged(
}
void TestWindowTreeClient::OnWindowTransformChanged(
- uint32_t window,
+ Id window,
const gfx::Transform& old_transform,
const gfx::Transform& new_transform) {}
void TestWindowTreeClient::OnClientAreaChanged(
- uint32_t window_id,
+ Id window_id,
const gfx::Insets& new_client_area,
const std::vector<gfx::Rect>& new_additional_client_areas) {}
-void TestWindowTreeClient::OnTransientWindowAdded(
- uint32_t window_id,
- uint32_t transient_window_id) {}
+void TestWindowTreeClient::OnTransientWindowAdded(Id window_id,
+ Id transient_window_id) {}
-void TestWindowTreeClient::OnTransientWindowRemoved(
- uint32_t window_id,
- uint32_t transient_window_id) {}
+void TestWindowTreeClient::OnTransientWindowRemoved(Id window_id,
+ Id transient_window_id) {}
void TestWindowTreeClient::OnWindowHierarchyChanged(
- uint32_t window,
- uint32_t old_parent,
- uint32_t new_parent,
+ Id window,
+ Id old_parent,
+ Id new_parent,
std::vector<mojom::WindowDataPtr> windows) {
tracker_.OnWindowHierarchyChanged(window, old_parent, new_parent,
std::move(windows));
}
-void TestWindowTreeClient::OnWindowReordered(uint32_t window_id,
- uint32_t relative_window_id,
+void TestWindowTreeClient::OnWindowReordered(Id window_id,
+ Id relative_window_id,
mojom::OrderDirection direction) {
tracker_.OnWindowReordered(window_id, relative_window_id, direction);
}
-void TestWindowTreeClient::OnWindowDeleted(uint32_t window) {
+void TestWindowTreeClient::OnWindowDeleted(Id window) {
tracker_.OnWindowDeleted(window);
}
-void TestWindowTreeClient::OnWindowVisibilityChanged(uint32_t window,
- bool visible) {
+void TestWindowTreeClient::OnWindowVisibilityChanged(Id window, bool visible) {
tracker_.OnWindowVisibilityChanged(window, visible);
}
-void TestWindowTreeClient::OnWindowOpacityChanged(uint32_t window,
+void TestWindowTreeClient::OnWindowOpacityChanged(Id window,
float old_opacity,
float new_opacity) {
tracker_.OnWindowOpacityChanged(window, new_opacity);
}
-void TestWindowTreeClient::OnWindowParentDrawnStateChanged(uint32_t window,
+void TestWindowTreeClient::OnWindowParentDrawnStateChanged(Id window,
bool drawn) {
tracker_.OnWindowParentDrawnStateChanged(window, drawn);
}
void TestWindowTreeClient::OnWindowSharedPropertyChanged(
- uint32_t window,
+ Id window,
const std::string& name,
const base::Optional<std::vector<uint8_t>>& new_data) {
tracker_.OnWindowSharedPropertyChanged(window, name, new_data);
@@ -420,9 +417,9 @@ void TestWindowTreeClient::OnWindowSharedPropertyChanged(
void TestWindowTreeClient::OnWindowInputEvent(
uint32_t event_id,
- uint32_t window,
+ Id window,
int64_t display_id,
- uint32_t display_root_window,
+ Id display_root_window,
const gfx::PointF& event_location_in_screen_pixel_layout,
std::unique_ptr<ui::Event> event,
bool matches_pointer_watcher) {
@@ -433,16 +430,16 @@ void TestWindowTreeClient::OnWindowInputEvent(
void TestWindowTreeClient::OnPointerEventObserved(
std::unique_ptr<ui::Event> event,
- uint32_t window_id,
+ Id window_id,
int64_t display_id) {
tracker_.OnPointerEventObserved(*event.get(), window_id);
}
-void TestWindowTreeClient::OnWindowFocused(uint32_t focused_window_id) {
+void TestWindowTreeClient::OnWindowFocused(Id focused_window_id) {
tracker_.OnWindowFocused(focused_window_id);
}
-void TestWindowTreeClient::OnWindowCursorChanged(uint32_t window_id,
+void TestWindowTreeClient::OnWindowCursorChanged(Id window_id,
ui::CursorData cursor) {
tracker_.OnWindowCursorChanged(window_id, cursor);
}
@@ -454,28 +451,28 @@ void TestWindowTreeClient::OnWindowSurfaceChanged(
void TestWindowTreeClient::OnDragDropStart(
const std::unordered_map<std::string, std::vector<uint8_t>>& mime_data) {}
-void TestWindowTreeClient::OnDragEnter(uint32_t window,
+void TestWindowTreeClient::OnDragEnter(Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
const OnDragEnterCallback& callback) {}
-void TestWindowTreeClient::OnDragOver(uint32_t window,
+void TestWindowTreeClient::OnDragOver(Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
const OnDragOverCallback& callback) {}
-void TestWindowTreeClient::OnDragLeave(uint32_t window) {}
+void TestWindowTreeClient::OnDragLeave(Id window) {}
void TestWindowTreeClient::OnCompleteDrop(
- uint32_t window,
+ Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
const OnCompleteDropCallback& callback) {}
-void TestWindowTreeClient::OnPerformDragDropCompleted(uint32_t window,
+void TestWindowTreeClient::OnPerformDragDropCompleted(uint32_t change_id,
bool success,
uint32_t action_taken) {}
@@ -486,7 +483,7 @@ void TestWindowTreeClient::OnChangeCompleted(uint32_t change_id, bool success) {
tracker_.OnChangeCompleted(change_id, success);
}
-void TestWindowTreeClient::RequestClose(uint32_t window_id) {}
+void TestWindowTreeClient::RequestClose(Id window_id) {}
void TestWindowTreeClient::GetWindowManager(
mojo::AssociatedInterfaceRequest<mojom::WindowManager> internal) {}
@@ -631,9 +628,9 @@ ServerWindow* WindowEventTargetingHelper::CreatePrimaryTree(
embed_window->set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
WindowTree* tree1 = window_server()->GetTreeWithRoot(embed_window);
+ WindowTreeTestApi(tree1).set_is_for_embedding(false);
EXPECT_NE(nullptr, tree1);
EXPECT_NE(tree1, wm_tree);
- WindowTreeTestApi(tree1).set_user_id(wm_tree->user_id());
embed_window->SetBounds(window_bounds, base::nullopt);
@@ -727,8 +724,12 @@ void TestPlatformDisplay::Init(PlatformDisplayDelegate* delegate) {
}
void TestPlatformDisplay::SetViewportSize(const gfx::Size& size) {}
void TestPlatformDisplay::SetTitle(const base::string16& title) {}
-void TestPlatformDisplay::SetCapture() {}
-void TestPlatformDisplay::ReleaseCapture() {}
+void TestPlatformDisplay::SetCapture() {
+ has_capture_ = true;
+}
+void TestPlatformDisplay::ReleaseCapture() {
+ has_capture_ = false;
+}
void TestPlatformDisplay::SetCursor(const ui::CursorData& cursor) {
*cursor_storage_ = cursor;
}
@@ -777,11 +778,9 @@ base::subtle::Atomic32 CursorLocationManagerTestApi::current_cursor_location() {
// -----------------------------------------------------------------------------
void AddWindowManager(WindowServer* window_server,
- const UserId& user_id,
bool automatically_create_display_roots) {
- window_server->window_manager_window_tree_factory_set()
- ->Add(user_id, nullptr)
- ->CreateWindowTree(nullptr, nullptr, automatically_create_display_roots);
+ window_server->window_manager_window_tree_factory()->CreateWindowTree(
+ nullptr, nullptr, automatically_create_display_roots);
}
display::Display MakeDisplay(int origin_x,
@@ -802,7 +801,7 @@ display::Display MakeDisplay(int origin_x,
ServerWindow* FirstRoot(WindowTree* tree) {
return tree->roots().size() == 1u
- ? tree->GetWindow((*tree->roots().begin())->id())
+ ? const_cast<ServerWindow*>(*(tree->roots().begin()))
: nullptr;
}
diff --git a/chromium/services/ui/ws/test_utils.h b/chromium/services/ui/ws/test_utils.h
index 3f3806fb7c8..060bd617d70 100644
--- a/chromium/services/ui/ws/test_utils.h
+++ b/chromium/services/ui/ws/test_utils.h
@@ -31,9 +31,7 @@
#include "services/ui/ws/platform_display_factory.h"
#include "services/ui/ws/test_change_tracker.h"
#include "services/ui/ws/user_activity_monitor.h"
-#include "services/ui/ws/user_id.h"
#include "services/ui/ws/window_manager_state.h"
-#include "services/ui/ws/window_manager_window_tree_factory_set.h"
#include "services/ui/ws/window_server_delegate.h"
#include "services/ui/ws/window_tree.h"
#include "services/ui/ws/window_tree_binding.h"
@@ -120,7 +118,7 @@ class WindowTreeTestApi {
explicit WindowTreeTestApi(WindowTree* tree);
~WindowTreeTestApi();
- void set_user_id(const UserId& user_id) { tree_->user_id_ = user_id; }
+ void set_is_for_embedding(bool value) { tree_->is_for_embedding_ = value; }
void set_window_manager_internal(mojom::WindowManager* wm_internal) {
tree_->window_manager_internal_ = wm_internal;
}
@@ -158,6 +156,8 @@ class WindowTreeTestApi {
bool ProcessSwapDisplayRoots(int64_t display_id1, int64_t display_id2) {
return tree_->ProcessSwapDisplayRoots(display_id1, display_id2);
}
+ size_t event_queue_size() const { return tree_->event_queue_.size(); }
+ bool HasEventInFlight() const { return tree_->event_ack_id_ != 0u; }
private:
WindowTree* tree_;
@@ -405,15 +405,15 @@ class TestWindowManager : public mojom::WindowManager {
void WmDisplayRemoved(int64_t display_id) override;
void WmDisplayModified(const display::Display& display) override {}
void WmSetBounds(uint32_t change_id,
- uint32_t window_id,
+ Id window_id,
const gfx::Rect& bounds) override {}
void WmSetProperty(
uint32_t change_id,
- uint32_t window_id,
+ Id window_id,
const std::string& name,
const base::Optional<std::vector<uint8_t>>& value) override {}
- void WmSetModalType(uint32_t window_id, ui::ModalType type) override;
- void WmSetCanFocus(uint32_t window_id, bool can_focus) override {}
+ void WmSetModalType(Id window_id, ui::ModalType type) override;
+ void WmSetCanFocus(Id window_id, bool can_focus) override {}
void WmCreateTopLevelWindow(
uint32_t change_id,
const viz::FrameSinkId& frame_sink_id,
@@ -429,21 +429,19 @@ class TestWindowManager : public mojom::WindowManager {
const WmMoveDragImageCallback& callback) override;
void WmDestroyDragImage() override;
void WmPerformMoveLoop(uint32_t change_id,
- uint32_t window_id,
+ Id window_id,
mojom::MoveLoopSource source,
const gfx::Point& cursor_location) override;
- void WmCancelMoveLoop(uint32_t window_id) override;
- void WmDeactivateWindow(uint32_t window_id) override;
- void WmStackAbove(uint32_t change_id, uint32_t above_id,
- uint32_t below_id) override;
- void WmStackAtTop(uint32_t change_id, uint32_t window_id) override;
- void WmPerformWmAction(uint32_t window_id,
- const std::string& action) override;
+ void WmCancelMoveLoop(uint32_t change_id) override;
+ void WmDeactivateWindow(Id window_id) override;
+ void WmStackAbove(uint32_t change_id, Id above_id, Id below_id) override;
+ void WmStackAtTop(uint32_t change_id, Id window_id) override;
+ void WmPerformWmAction(Id window_id, const std::string& action) override;
void OnAccelerator(uint32_t ack_id,
uint32_t accelerator_id,
std::unique_ptr<ui::Event> event) override;
void OnCursorTouchVisibleChanged(bool enabled) override;
- void OnEventBlockedByModalWindow(uint32_t window_id) override;
+ void OnEventBlockedByModalWindow(Id window_id) override;
std::string last_wm_action_;
@@ -490,7 +488,7 @@ class TestWindowTreeClient : public ui::mojom::WindowTreeClient {
Id focused_window_id,
bool drawn,
const base::Optional<viz::LocalSurfaceId>& local_surface_id) override;
- void OnEmbeddedAppDisconnected(uint32_t window) override;
+ void OnEmbeddedAppDisconnected(Id window) override;
void OnUnembed(Id window_id) override;
void OnCaptureChanged(Id new_capture_window_id,
Id old_capture_window_id) override;
@@ -503,80 +501,77 @@ class TestWindowTreeClient : public ui::mojom::WindowTreeClient {
bool drawn,
const base::Optional<viz::LocalSurfaceId>& local_surface_id) override;
void OnWindowBoundsChanged(
- uint32_t window,
+ Id window,
const gfx::Rect& old_bounds,
const gfx::Rect& new_bounds,
const base::Optional<viz::LocalSurfaceId>& local_surface_id) override;
- void OnWindowTransformChanged(uint32_t window,
+ void OnWindowTransformChanged(Id window,
const gfx::Transform& old_transform,
const gfx::Transform& new_transform) override;
void OnClientAreaChanged(
- uint32_t window_id,
+ Id window_id,
const gfx::Insets& new_client_area,
const std::vector<gfx::Rect>& new_additional_client_areas) override;
- void OnTransientWindowAdded(uint32_t window_id,
- uint32_t transient_window_id) override;
- void OnTransientWindowRemoved(uint32_t window_id,
- uint32_t transient_window_id) override;
+ void OnTransientWindowAdded(Id window_id, Id transient_window_id) override;
+ void OnTransientWindowRemoved(Id window_id, Id transient_window_id) override;
void OnWindowHierarchyChanged(
- uint32_t window,
- uint32_t old_parent,
- uint32_t new_parent,
+ Id window,
+ Id old_parent,
+ Id new_parent,
std::vector<mojom::WindowDataPtr> windows) override;
- void OnWindowReordered(uint32_t window_id,
- uint32_t relative_window_id,
+ void OnWindowReordered(Id window_id,
+ Id relative_window_id,
mojom::OrderDirection direction) override;
- void OnWindowDeleted(uint32_t window) override;
- void OnWindowVisibilityChanged(uint32_t window, bool visible) override;
- void OnWindowOpacityChanged(uint32_t window,
+ void OnWindowDeleted(Id window) override;
+ void OnWindowVisibilityChanged(Id window, bool visible) override;
+ void OnWindowOpacityChanged(Id window,
float old_opacity,
float new_opacity) override;
- void OnWindowParentDrawnStateChanged(uint32_t window, bool drawn) override;
+ void OnWindowParentDrawnStateChanged(Id window, bool drawn) override;
void OnWindowSharedPropertyChanged(
- uint32_t window,
+ Id window,
const std::string& name,
const base::Optional<std::vector<uint8_t>>& new_data) override;
void OnWindowInputEvent(
uint32_t event_id,
- uint32_t window,
+ Id window,
int64_t display_id,
- uint32_t display_root_window,
+ Id display_root_window,
const gfx::PointF& event_location_in_screen_pixel_layout,
std::unique_ptr<ui::Event> event,
bool matches_pointer_watcher) override;
void OnPointerEventObserved(std::unique_ptr<ui::Event> event,
- uint32_t window_id,
+ Id window_id,
int64_t display_id) override;
- void OnWindowFocused(uint32_t focused_window_id) override;
- void OnWindowCursorChanged(uint32_t window_id,
- ui::CursorData cursor) override;
+ void OnWindowFocused(Id focused_window_id) override;
+ void OnWindowCursorChanged(Id window_id, ui::CursorData cursor) override;
void OnWindowSurfaceChanged(Id window_id,
const viz::SurfaceInfo& surface_info) override;
void OnDragDropStart(
const std::unordered_map<std::string, std::vector<uint8_t>>& mime_data)
override;
- void OnDragEnter(uint32_t window,
+ void OnDragEnter(Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
const OnDragEnterCallback& callback) override;
- void OnDragOver(uint32_t window,
+ void OnDragOver(Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
const OnDragOverCallback& callback) override;
- void OnDragLeave(uint32_t window) override;
- void OnCompleteDrop(uint32_t window,
+ void OnDragLeave(Id window) override;
+ void OnCompleteDrop(Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
const OnCompleteDropCallback& callback) override;
- void OnPerformDragDropCompleted(uint32_t window,
+ void OnPerformDragDropCompleted(uint32_t change_id,
bool success,
uint32_t action_taken) override;
void OnDragDropDone() override;
void OnChangeCompleted(uint32_t change_id, bool success) override;
- void RequestClose(uint32_t window_id) override;
+ void RequestClose(Id window_id) override;
void GetWindowManager(
mojo::AssociatedInterfaceRequest<mojom::WindowManager> internal) override;
@@ -807,6 +802,8 @@ class TestPlatformDisplay : public PlatformDisplay {
const display::ViewportMetrics& metrics() const { return metrics_; }
+ bool has_capture() const { return has_capture_; }
+
// PlatformDisplay:
void Init(PlatformDisplayDelegate* delegate) override;
void SetViewportSize(const gfx::Size& size) override;
@@ -834,6 +831,7 @@ class TestPlatformDisplay : public PlatformDisplay {
display::Display::Rotation::ROTATE_0;
float cursor_scale_ = 1.0f;
gfx::Rect confine_cursor_bounds_;
+ bool has_capture_ = false;
DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplay);
};
@@ -855,10 +853,9 @@ class CursorLocationManagerTestApi {
// -----------------------------------------------------------------------------
-// Adds a new WM to |window_server| for |user_id|. Creates
-// WindowManagerWindowTreeFactory and associated WindowTree for the WM.
+// Adds a WM to |window_server|. Creates WindowManagerWindowTreeFactory and
+// associated WindowTree for the WM.
void AddWindowManager(WindowServer* window_server,
- const UserId& user_id,
bool automatically_create_display_roots = true);
// Create a new Display object with specified origin, pixel size and device
diff --git a/chromium/services/ui/ws/threaded_image_cursors.cc b/chromium/services/ui/ws/threaded_image_cursors.cc
index 02d79276059..aaab5cad6a1 100644
--- a/chromium/services/ui/ws/threaded_image_cursors.cc
+++ b/chromium/services/ui/ws/threaded_image_cursors.cc
@@ -98,9 +98,10 @@ void SetCustomCursorOnResourceThread(
// |platform_window| is owned by the UI Service thread, so setting the
// cursor on it also needs to happen on that thread.
ui_service_task_runner_->PostTask(
- FROM_HERE, base::Bind(&ThreadedImageCursors::SetCursorOnPlatformWindow,
- threaded_image_cursors_weak_ptr, platform_cursor,
- platform_window));
+ FROM_HERE,
+ base::Bind(&ThreadedImageCursors::SetCursorOnPlatformWindowAndUnref,
+ threaded_image_cursors_weak_ptr, platform_cursor,
+ platform_window));
}
}
#endif // defined(USE_OZONE)
@@ -207,5 +208,25 @@ void ThreadedImageCursors::SetCursorOnPlatformWindow(
platform_window->SetCursor(platform_cursor);
}
+#if defined(USE_OZONE)
+void ThreadedImageCursors::SetCursorOnPlatformWindowAndUnref(
+ ui::PlatformCursor platform_cursor,
+ ui::PlatformWindow* platform_window) {
+ SetCursorOnPlatformWindow(platform_cursor, platform_window);
+
+ // The PlatformCursor returned by CreateAnimatedCursor() has a single
+ // refcount which is owned by the caller. If we were returned a valid
+ // |platform_cursor|, we must unref it here. All implementations of
+ // PlatformWindow::SetCursor() which need to keep the PlatformCursor have
+ // increased the refcount for their self.
+ //
+ // Note: Cursors returned by SetPlatformCursor() do not return custom bitmap
+ // cursors. The refcount of such a cursor is owned by the caller and
+ // shouldn't be refed/unrefed by the caller.
+ if (platform_cursor)
+ ui::CursorFactoryOzone::GetInstance()->UnrefImageCursor(platform_cursor);
+}
+#endif
+
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/threaded_image_cursors.h b/chromium/services/ui/ws/threaded_image_cursors.h
index 5b3f37695b0..b9ce89f7975 100644
--- a/chromium/services/ui/ws/threaded_image_cursors.h
+++ b/chromium/services/ui/ws/threaded_image_cursors.h
@@ -66,6 +66,10 @@ class ThreadedImageCursors {
// Helper method. Sets |platform_cursor| on the |platform_window|.
void SetCursorOnPlatformWindow(ui::PlatformCursor platform_cursor,
ui::PlatformWindow* platform_window);
+#if defined(USE_OZONE)
+ void SetCursorOnPlatformWindowAndUnref(ui::PlatformCursor platform_cursor,
+ ui::PlatformWindow* platform_window);
+#endif
private:
// The object used for performing the actual cursor operations.
diff --git a/chromium/services/ui/ws/transient_windows_unittest.cc b/chromium/services/ui/ws/transient_windows_unittest.cc
index 5ca7da21364..19dca6b6a79 100644
--- a/chromium/services/ui/ws/transient_windows_unittest.cc
+++ b/chromium/services/ui/ws/transient_windows_unittest.cc
@@ -42,9 +42,9 @@ class TestTransientWindowObserver : public ServerWindowObserver {
};
ServerWindow* CreateTestWindow(TestServerWindowDelegate* delegate,
- const WindowId& window_id,
+ const viz::FrameSinkId& frame_sink_id,
ServerWindow* parent) {
- ServerWindow* window = new ServerWindow(delegate, window_id);
+ ServerWindow* window = new ServerWindow(delegate, frame_sink_id);
window->SetVisible(true);
if (parent)
parent->Add(window);
@@ -59,8 +59,12 @@ std::string ChildWindowIDsAsString(ServerWindow* parent) {
++i) {
if (!result.empty())
result += " ";
- WindowId id = (*i)->id();
- result += base::IntToString((id.client_id << 16) | id.window_id);
+ const viz::FrameSinkId& id = (*i)->frame_sink_id();
+ if (id.client_id() != 0) {
+ // All use cases of this expect the client_id to be 0.
+ return "unexpected-client-id";
+ }
+ result += base::IntToString(id.sink_id());
}
return result;
}
@@ -85,15 +89,15 @@ class TransientWindowsTest : public testing::Test {
TEST_F(TransientWindowsTest, TransientChildren) {
TestServerWindowDelegate server_window_delegate(viz_host_proxy());
- std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&server_window_delegate, WindowId(1, 0), nullptr));
- std::unique_ptr<ServerWindow> w1(
- CreateTestWindow(&server_window_delegate, WindowId(1, 1), parent.get()));
- std::unique_ptr<ServerWindow> w3(
- CreateTestWindow(&server_window_delegate, WindowId(1, 2), parent.get()));
+ std::unique_ptr<ServerWindow> parent(CreateTestWindow(
+ &server_window_delegate, viz::FrameSinkId(1, 0), nullptr));
+ std::unique_ptr<ServerWindow> w1(CreateTestWindow(
+ &server_window_delegate, viz::FrameSinkId(1, 1), parent.get()));
+ std::unique_ptr<ServerWindow> w3(CreateTestWindow(
+ &server_window_delegate, viz::FrameSinkId(1, 2), parent.get()));
- ServerWindow* w2 =
- CreateTestWindow(&server_window_delegate, WindowId(1, 3), parent.get());
+ ServerWindow* w2 = CreateTestWindow(&server_window_delegate,
+ viz::FrameSinkId(1, 3), parent.get());
// w2 is now owned by w1.
w1->AddTransientWindow(w2);
@@ -111,14 +115,14 @@ TEST_F(TransientWindowsTest, TransientChildren) {
TEST_F(TransientWindowsTest, DontStackUponCreation) {
TestServerWindowDelegate delegate(viz_host_proxy());
std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&delegate, WindowId(0, 1), nullptr));
+ CreateTestWindow(&delegate, viz::FrameSinkId(0, 1), nullptr));
std::unique_ptr<ServerWindow> window0(
- CreateTestWindow(&delegate, WindowId(0, 2), parent.get()));
+ CreateTestWindow(&delegate, viz::FrameSinkId(0, 2), parent.get()));
std::unique_ptr<ServerWindow> window1(
- CreateTestWindow(&delegate, WindowId(0, 3), parent.get()));
+ CreateTestWindow(&delegate, viz::FrameSinkId(0, 3), parent.get()));
ServerWindow* window2 =
- CreateTestWindow(&delegate, WindowId(0, 4), parent.get());
+ CreateTestWindow(&delegate, viz::FrameSinkId(0, 4), parent.get());
window0->AddTransientWindow(window2);
EXPECT_EQ("2 3 4", ChildWindowIDsAsString(parent.get()));
}
@@ -128,11 +132,11 @@ TEST_F(TransientWindowsTest, DontStackUponCreation) {
TEST_F(TransientWindowsTest, RestackUponAddOrRemoveTransientWindow) {
TestServerWindowDelegate delegate(viz_host_proxy());
std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&delegate, WindowId(0, 1), nullptr));
+ CreateTestWindow(&delegate, viz::FrameSinkId(0, 1), nullptr));
std::unique_ptr<ServerWindow> windows[4];
for (int i = 0; i < 4; i++)
windows[i].reset(
- CreateTestWindow(&delegate, WindowId(0, i + 2), parent.get()));
+ CreateTestWindow(&delegate, viz::FrameSinkId(0, i + 2), parent.get()));
EXPECT_EQ("2 3 4 5", ChildWindowIDsAsString(parent.get()));
@@ -165,9 +169,9 @@ TEST_F(TransientWindowsTest, RestackUponAddOrRemoveTransientWindow) {
TEST_F(TransientWindowsTest, TransientWindowObserverNotified) {
TestServerWindowDelegate delegate(viz_host_proxy());
std::unique_ptr<ServerWindow> parent(
- CreateTestWindow(&delegate, WindowId(0, 1), nullptr));
+ CreateTestWindow(&delegate, viz::FrameSinkId(0, 1), nullptr));
std::unique_ptr<ServerWindow> w1(
- CreateTestWindow(&delegate, WindowId(0, 2), parent.get()));
+ CreateTestWindow(&delegate, viz::FrameSinkId(0, 2), parent.get()));
TestTransientWindowObserver test_observer;
parent->AddObserver(&test_observer);
diff --git a/chromium/services/ui/ws/user_display_manager.cc b/chromium/services/ui/ws/user_display_manager.cc
index 22ecc112b21..a5e30a39407 100644
--- a/chromium/services/ui/ws/user_display_manager.cc
+++ b/chromium/services/ui/ws/user_display_manager.cc
@@ -15,12 +15,9 @@
namespace ui {
namespace ws {
-UserDisplayManager::UserDisplayManager(UserDisplayManagerDelegate* delegate,
- const UserId& user_id)
+UserDisplayManager::UserDisplayManager(UserDisplayManagerDelegate* delegate)
: delegate_(delegate),
- user_id_(user_id),
- got_valid_frame_decorations_(
- delegate->GetFrameDecorationsForUser(user_id, nullptr)) {}
+ got_valid_frame_decorations_(delegate->GetFrameDecorations(nullptr)) {}
UserDisplayManager::~UserDisplayManager() {}
@@ -80,8 +77,7 @@ mojom::WsDisplayPtr UserDisplayManager::ToWsDisplayPtr(
const display::Display& display) {
mojom::WsDisplayPtr ws_display = mojom::WsDisplay::New();
ws_display->display = display;
- delegate_->GetFrameDecorationsForUser(user_id_,
- &ws_display->frame_decoration_values);
+ delegate_->GetFrameDecorations(&ws_display->frame_decoration_values);
return ws_display;
}
diff --git a/chromium/services/ui/ws/user_display_manager.h b/chromium/services/ui/ws/user_display_manager.h
index 8b889cda57a..71dab7c094b 100644
--- a/chromium/services/ui/ws/user_display_manager.h
+++ b/chromium/services/ui/ws/user_display_manager.h
@@ -11,7 +11,6 @@
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/ui/public/interfaces/display_manager.mojom.h"
-#include "services/ui/ws/user_id.h"
namespace display {
class Display;
@@ -23,10 +22,10 @@ namespace ws {
class UserDisplayManagerDelegate;
// Provides per user display state.
+// TODO(sky): merge this with ui::ws::DisplayManager (and rename).
class UserDisplayManager : public mojom::DisplayManager {
public:
- UserDisplayManager(UserDisplayManagerDelegate* delegate,
- const UserId& user_id);
+ UserDisplayManager(UserDisplayManagerDelegate* delegate);
~UserDisplayManager() override;
void DisableAutomaticNotification();
@@ -72,8 +71,6 @@ class UserDisplayManager : public mojom::DisplayManager {
UserDisplayManagerDelegate* delegate_;
- const UserId user_id_;
-
// Set to true the first time at least one Display has valid frame values.
bool got_valid_frame_decorations_;
diff --git a/chromium/services/ui/ws/user_display_manager_delegate.h b/chromium/services/ui/ws/user_display_manager_delegate.h
index 40a87e39680..a95a58604c8 100644
--- a/chromium/services/ui/ws/user_display_manager_delegate.h
+++ b/chromium/services/ui/ws/user_display_manager_delegate.h
@@ -8,18 +8,15 @@
#include <stdint.h>
#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
-#include "services/ui/ws/user_id.h"
namespace ui {
namespace ws {
class UserDisplayManagerDelegate {
public:
- // Gets the frame decorations for the specified user. Returns true if the
- // decorations have been set, false otherwise. |values| may be null.
- virtual bool GetFrameDecorationsForUser(
- const UserId& user_id,
- mojom::FrameDecorationValuesPtr* values) = 0;
+ // Gets the frame decorations. Returns true if the decorations have been set,
+ // false otherwise. |values| may be null.
+ virtual bool GetFrameDecorations(mojom::FrameDecorationValuesPtr* values) = 0;
virtual int64_t GetInternalDisplayId() = 0;
diff --git a/chromium/services/ui/ws/user_display_manager_unittest.cc b/chromium/services/ui/ws/user_display_manager_unittest.cc
index dc0003595fa..4681b85143f 100644
--- a/chromium/services/ui/ws/user_display_manager_unittest.cc
+++ b/chromium/services/ui/ws/user_display_manager_unittest.cc
@@ -22,7 +22,7 @@
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/test_utils.h"
#include "services/ui/ws/window_manager_state.h"
-#include "services/ui/ws/window_manager_window_tree_factory_set.h"
+#include "services/ui/ws/window_manager_window_tree_factory.h"
#include "services/ui/ws/window_server.h"
#include "services/ui/ws/window_server_delegate.h"
#include "services/ui/ws/window_tree.h"
@@ -34,8 +34,6 @@ namespace ws {
namespace test {
namespace {
-const char kUserId1[] = "123";
-
mojom::FrameDecorationValuesPtr CreateDefaultFrameDecorationValues() {
return mojom::FrameDecorationValues::New();
}
@@ -71,29 +69,26 @@ class UserDisplayManagerTest : public TaskRunnerTestBase {
TEST_F(UserDisplayManagerTest, OnlyNotifyWhenFrameDecorationsSet) {
screen_manager().AddDisplay();
- TestDisplayManagerObserver display_manager_observer1;
+ TestDisplayManagerObserver display_manager_observer;
DisplayManager* display_manager = window_server()->display_manager();
- AddWindowManager(window_server(), kUserId1);
- UserDisplayManager* user_display_manager1 =
- display_manager->GetUserDisplayManager(kUserId1);
- ASSERT_TRUE(user_display_manager1);
- user_display_manager1->AddObserver(display_manager_observer1.GetPtr());
+ AddWindowManager(window_server());
+ UserDisplayManager* user_display_manager =
+ display_manager->GetUserDisplayManager();
+ ASSERT_TRUE(user_display_manager);
+ user_display_manager->AddObserver(display_manager_observer.GetPtr());
RunUntilIdle();
// Observer should not have been notified yet.
- EXPECT_EQ(std::string(),
- display_manager_observer1.GetAndClearObserverCalls());
+ EXPECT_EQ(std::string(), display_manager_observer.GetAndClearObserverCalls());
// Set the frame decoration values, which should trigger sending immediately.
ASSERT_EQ(1u, display_manager->displays().size());
- window_server()
- ->window_manager_window_tree_factory_set()
- ->GetWindowManagerStateForUser(kUserId1)
- ->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
+ window_server()->GetWindowManagerState()->SetFrameDecorationValues(
+ CreateDefaultFrameDecorationValues());
RunUntilIdle();
EXPECT_EQ("OnDisplaysChanged 1 -1",
- display_manager_observer1.GetAndClearObserverCalls());
+ display_manager_observer.GetAndClearObserverCalls());
}
TEST_F(UserDisplayManagerTest, AddObserverAfterFrameDecorationsSet) {
@@ -101,17 +96,15 @@ TEST_F(UserDisplayManagerTest, AddObserverAfterFrameDecorationsSet) {
TestDisplayManagerObserver display_manager_observer1;
DisplayManager* display_manager = window_server()->display_manager();
- AddWindowManager(window_server(), kUserId1);
- UserDisplayManager* user_display_manager1 =
- display_manager->GetUserDisplayManager(kUserId1);
- ASSERT_TRUE(user_display_manager1);
+ AddWindowManager(window_server());
+ UserDisplayManager* user_display_manager =
+ display_manager->GetUserDisplayManager();
+ ASSERT_TRUE(user_display_manager);
ASSERT_EQ(1u, display_manager->displays().size());
- window_server()
- ->window_manager_window_tree_factory_set()
- ->GetWindowManagerStateForUser(kUserId1)
- ->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
+ window_server()->GetWindowManagerState()->SetFrameDecorationValues(
+ CreateDefaultFrameDecorationValues());
- user_display_manager1->AddObserver(display_manager_observer1.GetPtr());
+ user_display_manager->AddObserver(display_manager_observer1.GetPtr());
RunUntilIdle();
EXPECT_EQ("OnDisplaysChanged 1 -1",
@@ -123,16 +116,14 @@ TEST_F(UserDisplayManagerTest, AddRemoveDisplay) {
TestDisplayManagerObserver display_manager_observer1;
DisplayManager* display_manager = window_server()->display_manager();
- AddWindowManager(window_server(), kUserId1);
- UserDisplayManager* user_display_manager1 =
- display_manager->GetUserDisplayManager(kUserId1);
- ASSERT_TRUE(user_display_manager1);
+ AddWindowManager(window_server());
+ UserDisplayManager* user_display_manager =
+ display_manager->GetUserDisplayManager();
+ ASSERT_TRUE(user_display_manager);
ASSERT_EQ(1u, display_manager->displays().size());
- window_server()
- ->window_manager_window_tree_factory_set()
- ->GetWindowManagerStateForUser(kUserId1)
- ->SetFrameDecorationValues(CreateDefaultFrameDecorationValues());
- user_display_manager1->AddObserver(display_manager_observer1.GetPtr());
+ window_server()->GetWindowManagerState()->SetFrameDecorationValues(
+ CreateDefaultFrameDecorationValues());
+ user_display_manager->AddObserver(display_manager_observer1.GetPtr());
RunUntilIdle();
EXPECT_EQ("OnDisplaysChanged 1 -1",
diff --git a/chromium/services/ui/ws/user_id.h b/chromium/services/ui/ws/user_id.h
deleted file mode 100644
index 59291c68d96..00000000000
--- a/chromium/services/ui/ws/user_id.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// 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.
-
-#ifndef SERVICES_UI_WS_USER_ID_H_
-#define SERVICES_UI_WS_USER_ID_H_
-
-#include <string>
-
-namespace ui {
-namespace ws {
-
-using UserId = std::string;
-
-inline UserId InvalidUserId() {
- return std::string();
-}
-
-} // namespace ws
-} // namespace ui
-
-#endif // SERVICES_UI_WS_USER_ID_H_
diff --git a/chromium/services/ui/ws/user_id_tracker.cc b/chromium/services/ui/ws/user_id_tracker.cc
deleted file mode 100644
index 4640368823f..00000000000
--- a/chromium/services/ui/ws/user_id_tracker.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-// 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.
-
-#include "services/ui/ws/user_id_tracker.h"
-
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/ui/ws/user_id_tracker_observer.h"
-
-namespace ui {
-namespace ws {
-
-UserIdTracker::UserIdTracker()
- : active_id_(service_manager::mojom::kRootUserID) {
- ids_.insert(active_id_);
-}
-
-UserIdTracker::~UserIdTracker() {
-}
-
-bool UserIdTracker::IsValidUserId(const UserId& id) const {
- return ids_.count(id) > 0;
-}
-
-void UserIdTracker::SetActiveUserId(const UserId& id) {
- DCHECK(IsValidUserId(id));
- if (id == active_id_)
- return;
-
- const UserId previously_active_id = active_id_;
- active_id_ = id;
- for (auto& observer : observers_)
- observer.OnActiveUserIdChanged(previously_active_id, id);
-}
-
-void UserIdTracker::AddUserId(const UserId& id) {
- if (IsValidUserId(id))
- return;
-
- ids_.insert(id);
- for (auto& observer : observers_)
- observer.OnUserIdAdded(id);
-}
-
-void UserIdTracker::RemoveUserId(const UserId& id) {
- DCHECK(IsValidUserId(id));
- ids_.erase(id);
- for (auto& observer : observers_)
- observer.OnUserIdRemoved(id);
-}
-
-void UserIdTracker::AddObserver(UserIdTrackerObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void UserIdTracker::RemoveObserver(UserIdTrackerObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void UserIdTracker::Bind(mojom::UserAccessManagerRequest request) {
- bindings_.AddBinding(this, std::move(request));
-}
-
-void UserIdTracker::SetActiveUser(const std::string& user_id) {
- if (!IsValidUserId(user_id))
- AddUserId(user_id);
- SetActiveUserId(user_id);
-}
-
-} // namespace ws
-} // namespace ui
diff --git a/chromium/services/ui/ws/user_id_tracker.h b/chromium/services/ui/ws/user_id_tracker.h
deleted file mode 100644
index 1d9fdaf822c..00000000000
--- a/chromium/services/ui/ws/user_id_tracker.h
+++ /dev/null
@@ -1,62 +0,0 @@
-// 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.
-
-#ifndef SERVICES_UI_WS_USER_ID_TRACKER_H_
-#define SERVICES_UI_WS_USER_ID_TRACKER_H_
-
-#include <stdint.h>
-
-#include <set>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/ui/public/interfaces/user_access_manager.mojom.h"
-#include "services/ui/ws/user_id.h"
-
-namespace ui {
-namespace ws {
-
-class UserIdTrackerObserver;
-
-// Tracks the set of known/valid user ids.
-class UserIdTracker : public mojom::UserAccessManager {
- public:
- UserIdTracker();
- ~UserIdTracker() override;
-
- bool IsValidUserId(const UserId& id) const;
-
- const UserId& active_id() const { return active_id_; }
-
- // Adds a new known user. Does nothing if |id| is not known.
- void SetActiveUserId(const UserId& id);
- void AddUserId(const UserId& id);
- void RemoveUserId(const UserId& id);
-
- void AddObserver(UserIdTrackerObserver* observer);
- void RemoveObserver(UserIdTrackerObserver* observer);
-
- void Bind(mojom::UserAccessManagerRequest request);
-
- private:
- using UserIdSet = std::set<UserId>;
-
- // mojom::UserAccessManager:
- void SetActiveUser(const std::string& user_id) override;
-
- base::ObserverList<UserIdTrackerObserver> observers_;
-
- UserIdSet ids_;
- UserId active_id_;
-
- mojo::BindingSet<mojom::UserAccessManager> bindings_;
-
- DISALLOW_COPY_AND_ASSIGN(UserIdTracker);
-};
-
-} // namespace ws
-} // namespace ui
-
-#endif // SERVICES_UI_WS_USER_ID_TRACKER_H_
diff --git a/chromium/services/ui/ws/user_id_tracker_observer.h b/chromium/services/ui/ws/user_id_tracker_observer.h
deleted file mode 100644
index 23d5eae02b7..00000000000
--- a/chromium/services/ui/ws/user_id_tracker_observer.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-
-#ifndef SERVICES_UI_WS_USER_ID_TRACKER_OBSERVER_H_
-#define SERVICES_UI_WS_USER_ID_TRACKER_OBSERVER_H_
-
-#include <stdint.h>
-
-#include "services/ui/ws/user_id.h"
-
-namespace ui {
-namespace ws {
-
-class UserIdTrackerObserver {
- public:
- virtual void OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) {}
- virtual void OnUserIdAdded(const UserId& id) {}
- virtual void OnUserIdRemoved(const UserId& id) {}
-
- protected:
- virtual ~UserIdTrackerObserver() {}
-};
-
-} // namespace ws
-} // namespace ui
-
-#endif // SERVICES_UI_WS_USER_ID_TRACKER_OBSERVER_H_
diff --git a/chromium/services/ui/ws/window_coordinate_conversions_unittest.cc b/chromium/services/ui/ws/window_coordinate_conversions_unittest.cc
index 9978c9c76c7..5e25ec80943 100644
--- a/chromium/services/ui/ws/window_coordinate_conversions_unittest.cc
+++ b/chromium/services/ui/ws/window_coordinate_conversions_unittest.cc
@@ -29,12 +29,12 @@ class WindowCoordinateConversions : public testing::Test {
TEST_F(WindowCoordinateConversions, Transform) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root(&window_delegate, WindowId(1, 2));
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
root.set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
root.SetVisible(true);
root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
- ServerWindow child(&window_delegate, WindowId(1, 3));
+ ServerWindow child(&window_delegate, viz::FrameSinkId(1, 3));
root.Add(&child);
child.SetVisible(true);
child.SetBounds(gfx::Rect(0, 0, 20, 20), base::nullopt);
@@ -45,7 +45,7 @@ TEST_F(WindowCoordinateConversions, Transform) {
transform.Scale(SkIntToMScalar(2), SkIntToMScalar(2));
child.SetTransform(transform);
- ServerWindow child_child(&window_delegate, WindowId(1, 4));
+ ServerWindow child_child(&window_delegate, viz::FrameSinkId(1, 4));
child.Add(&child_child);
child_child.SetVisible(true);
child_child.SetBounds(gfx::Rect(4, 6, 12, 24), base::nullopt);
diff --git a/chromium/services/ui/ws/window_finder.cc b/chromium/services/ui/ws/window_finder.cc
index b8efd8d9a09..1f99e990757 100644
--- a/chromium/services/ui/ws/window_finder.cc
+++ b/chromium/services/ui/ws/window_finder.cc
@@ -6,7 +6,6 @@
#include "base/containers/adapters.h"
#include "services/ui/ws/server_window.h"
-#include "services/ui/ws/server_window_delegate.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/point_f.h"
@@ -87,6 +86,7 @@ gfx::Transform TransformFromParent(const ServerWindow* window,
bool FindDeepestVisibleWindowForLocationImpl(
ServerWindow* window,
+ bool is_root_window,
EventSource event_source,
const gfx::Point& location_in_root,
const gfx::Point& location_in_window,
@@ -95,7 +95,11 @@ bool FindDeepestVisibleWindowForLocationImpl(
// 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_in_window)) {
+ //
+ // Display roots aren't allowed to have non-client areas. This is important
+ // as roots may have a transform, which causes problem in comparing sizes.
+ if (!is_root_window &&
+ IsLocationInNonclientArea(window, location_in_window)) {
deepest_window->window = window;
deepest_window->in_non_client_area = true;
return true;
@@ -133,9 +137,10 @@ bool FindDeepestVisibleWindowForLocationImpl(
continue;
}
+ const bool child_is_root = false;
if (FindDeepestVisibleWindowForLocationImpl(
- child, event_source, location_in_root, location_in_child,
- child_transform, deepest_window)) {
+ child, child_is_root, event_source, location_in_root,
+ location_in_child, child_transform, deepest_window)) {
return true;
}
}
@@ -164,9 +169,10 @@ DeepestWindow FindDeepestVisibleWindowForLocation(ServerWindow* root_window,
DeepestWindow result;
// Allow the root to have a transform, which mirrors what happens with
// WindowManagerDisplayRoot.
- FindDeepestVisibleWindowForLocationImpl(root_window, event_source, location,
- initial_location, root_transform,
- &result);
+ const bool is_root_window = true;
+ FindDeepestVisibleWindowForLocationImpl(
+ root_window, is_root_window, event_source, location, initial_location,
+ root_transform, &result);
return result;
}
diff --git a/chromium/services/ui/ws/window_finder_unittest.cc b/chromium/services/ui/ws/window_finder_unittest.cc
index 8e87df97566..f6a28af9415 100644
--- a/chromium/services/ui/ws/window_finder_unittest.cc
+++ b/chromium/services/ui/ws/window_finder_unittest.cc
@@ -29,19 +29,19 @@ class WindowFinderTest : public testing::Test {
TEST_F(WindowFinderTest, FindDeepestVisibleWindow) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root(&window_delegate, WindowId(1, 2));
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
root.set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
window_delegate.set_root_window(&root);
root.SetVisible(true);
root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
- ServerWindow child1(&window_delegate, WindowId(1, 3));
+ ServerWindow child1(&window_delegate, viz::FrameSinkId(1, 3));
root.Add(&child1);
child1.SetVisible(true);
child1.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
- ServerWindow child2(&window_delegate, WindowId(1, 4));
+ ServerWindow child2(&window_delegate, viz::FrameSinkId(1, 4));
root.Add(&child2);
child2.SetVisible(true);
child2.SetBounds(gfx::Rect(15, 15, 20, 20), base::nullopt);
@@ -74,12 +74,12 @@ TEST_F(WindowFinderTest, FindDeepestVisibleWindow) {
TEST_F(WindowFinderTest, FindDeepestVisibleWindowNonClientArea) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root(&window_delegate, WindowId(1, 2));
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
window_delegate.set_root_window(&root);
root.SetVisible(true);
root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
- ServerWindow child1(&window_delegate, WindowId(1, 3));
+ ServerWindow child1(&window_delegate, viz::FrameSinkId(1, 3));
root.Add(&child1);
child1.SetVisible(true);
child1.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
@@ -125,12 +125,12 @@ TEST_F(WindowFinderTest, FindDeepestVisibleWindowNonClientArea) {
TEST_F(WindowFinderTest, FindDeepestVisibleWindowHitTestMask) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root(&window_delegate, WindowId(1, 2));
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
window_delegate.set_root_window(&root);
root.SetVisible(true);
root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
- ServerWindow child_with_mask(&window_delegate, WindowId(1, 4));
+ ServerWindow child_with_mask(&window_delegate, viz::FrameSinkId(1, 4));
root.Add(&child_with_mask);
child_with_mask.SetVisible(true);
child_with_mask.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
@@ -149,19 +149,19 @@ TEST_F(WindowFinderTest, FindDeepestVisibleWindowHitTestMask) {
TEST_F(WindowFinderTest, FindDeepestVisibleWindowOverNonTarget) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root(&window_delegate, WindowId(1, 2));
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
window_delegate.set_root_window(&root);
root.SetVisible(true);
root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
// Create two windows, |child1| and |child2|. The two overlap but |child2| is
// not a valid event target.
- ServerWindow child1(&window_delegate, WindowId(1, 3));
+ ServerWindow child1(&window_delegate, viz::FrameSinkId(1, 3));
root.Add(&child1);
child1.SetVisible(true);
child1.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
- ServerWindow child2(&window_delegate, WindowId(1, 4));
+ ServerWindow child2(&window_delegate, viz::FrameSinkId(1, 4));
root.Add(&child2);
child2.set_event_targeting_policy(mojom::EventTargetingPolicy::NONE);
child2.SetVisible(true);
@@ -176,7 +176,7 @@ TEST_F(WindowFinderTest, FindDeepestVisibleWindowOverNonTarget) {
TEST_F(WindowFinderTest, NonClientPreferredOverChild) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root(&window_delegate, WindowId(1, 2));
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
window_delegate.set_root_window(&root);
root.SetVisible(true);
root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
@@ -184,13 +184,13 @@ TEST_F(WindowFinderTest, NonClientPreferredOverChild) {
// Create two windows, |child| and |child_child|; |child| is a child of the
// root and |child_child| and child of |child|. All share the same size with
// |child| having a non-client area.
- ServerWindow child(&window_delegate, WindowId(1, 3));
+ ServerWindow child(&window_delegate, viz::FrameSinkId(1, 3));
root.Add(&child);
child.SetVisible(true);
child.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
child.SetClientArea(gfx::Insets(2, 3, 4, 5), std::vector<gfx::Rect>());
- ServerWindow child_child(&window_delegate, WindowId(1, 4));
+ ServerWindow child_child(&window_delegate, viz::FrameSinkId(1, 4));
child.Add(&child_child);
child_child.SetVisible(true);
child_child.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
@@ -203,13 +203,13 @@ TEST_F(WindowFinderTest, NonClientPreferredOverChild) {
TEST_F(WindowFinderTest, FindDeepestVisibleWindowWithTransform) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root(&window_delegate, WindowId(1, 2));
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
root.set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
window_delegate.set_root_window(&root);
root.SetVisible(true);
root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
- ServerWindow child(&window_delegate, WindowId(1, 3));
+ ServerWindow child(&window_delegate, viz::FrameSinkId(1, 3));
root.Add(&child);
child.SetVisible(true);
child.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
@@ -224,7 +224,7 @@ TEST_F(WindowFinderTest, FindDeepestVisibleWindowWithTransform) {
&root, EventSource::MOUSE, gfx::Point(9, 9))
.window);
- ServerWindow child_child(&window_delegate, WindowId(1, 4));
+ ServerWindow child_child(&window_delegate, viz::FrameSinkId(1, 4));
child.Add(&child_child);
child_child.SetVisible(true);
child_child.SetBounds(gfx::Rect(12, 12, 4, 4), base::nullopt);
@@ -249,12 +249,12 @@ TEST_F(WindowFinderTest, FindDeepestVisibleWindowWithTransform) {
TEST_F(WindowFinderTest, FindDeepestVisibleWindowWithTransformOnParent) {
TestServerWindowDelegate window_delegate(viz_host_proxy());
- ServerWindow root(&window_delegate, WindowId(1, 2));
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
root.set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
root.SetVisible(true);
root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
- ServerWindow child(&window_delegate, WindowId(1, 3));
+ ServerWindow child(&window_delegate, viz::FrameSinkId(1, 3));
root.Add(&child);
child.SetVisible(true);
child.SetBounds(gfx::Rect(10, 10, 10, 10), base::nullopt);
@@ -273,5 +273,47 @@ TEST_F(WindowFinderTest, FindDeepestVisibleWindowWithTransformOnParent) {
.window);
}
+// Creates the following window hierarchy:
+// root
+// |- c1 (has .5x transform, and is used as the root in
+// FindDeepestVisibleWindowForLocation).
+// |- c2
+// |- c3
+// With various assertions around hit testing.
+TEST_F(WindowFinderTest,
+ FindDeepestVisibleWindowWithTransformOnParentMagnified) {
+ TestServerWindowDelegate window_delegate(viz_host_proxy());
+ ServerWindow root(&window_delegate, viz::FrameSinkId(1, 2));
+ root.set_event_targeting_policy(
+ mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
+ root.SetVisible(true);
+ root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
+ window_delegate.set_root_window(&root);
+ ServerWindow c1(&window_delegate, viz::FrameSinkId(1, 3));
+ root.Add(&c1);
+ c1.SetVisible(true);
+ c1.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
+ gfx::Transform transform;
+ transform.Scale(SkFloatToMScalar(.5f), SkFloatToMScalar(.5f));
+ c1.SetTransform(transform);
+
+ ServerWindow c2(&window_delegate, viz::FrameSinkId(1, 4));
+ c1.Add(&c2);
+ c2.SetVisible(true);
+ c2.SetBounds(gfx::Rect(0, 0, 200, 200), base::nullopt);
+
+ ServerWindow c3(&window_delegate, viz::FrameSinkId(1, 5));
+ c2.Add(&c3);
+ c3.SetVisible(true);
+ c3.SetBounds(gfx::Rect(0, 190, 200, 10), base::nullopt);
+
+ EXPECT_EQ(&c2, FindDeepestVisibleWindowForLocation(&c1, EventSource::MOUSE,
+ gfx::Point(55, 55))
+ .window);
+ EXPECT_EQ(&c3, FindDeepestVisibleWindowForLocation(&c1, EventSource::MOUSE,
+ gfx::Point(0, 99))
+ .window);
+}
+
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/window_manager_access_policy.cc b/chromium/services/ui/ws/window_manager_access_policy.cc
index 20d99da8297..fe53b8ef915 100644
--- a/chromium/services/ui/ws/window_manager_access_policy.cc
+++ b/chromium/services/ui/ws/window_manager_access_policy.cc
@@ -231,7 +231,7 @@ bool WindowManagerAccessPolicy::IsValidIdForNewWindow(
bool WindowManagerAccessPolicy::WasCreatedByThisClient(
const ServerWindow* window) const {
- return window->id().client_id == client_id_;
+ return window->owning_tree_id() == client_id_;
}
} // namespace ws
diff --git a/chromium/services/ui/ws/window_manager_client_unittest.cc b/chromium/services/ui/ws/window_manager_client_unittest.cc
index df3ba09731f..f56a95d2dc0 100644
--- a/chromium/services/ui/ws/window_manager_client_unittest.cc
+++ b/chromium/services/ui/ws/window_manager_client_unittest.cc
@@ -36,8 +36,7 @@ Id server_id(aura::Window* window) {
return aura::WindowMus::Get(window)->server_id();
}
-aura::Window* GetChildWindowByServerId(aura::WindowTreeClient* client,
- aura::Id id) {
+aura::Window* GetChildWindowByServerId(aura::WindowTreeClient* client, Id id) {
return aura::WindowTreeClientPrivate(client).GetWindowByServerId(id);
}
@@ -331,8 +330,9 @@ TEST_F(WindowServerTest, Embed) {
// WindowTreeHost::window() is the single root of the embed.
EXPECT_EQ(1u, embed_result->window_tree_client->GetRoots().size());
EXPECT_EQ(embed_root, GetFirstRoot(embed_result->window_tree_client.get()));
- EXPECT_EQ(LoWord(server_id(window)), LoWord(server_id(embed_root)));
- EXPECT_NE(0u, server_id(embed_root) >> 16);
+ EXPECT_EQ(ClientWindowIdFromTransportId(server_id(window)),
+ ClientWindowIdFromTransportId(server_id(embed_root)));
+ EXPECT_NE(0u, ClientIdFromTransportId(server_id(embed_root)));
EXPECT_EQ(nullptr, embed_root->parent());
EXPECT_TRUE(embed_root->children().empty());
}
@@ -345,8 +345,9 @@ TEST_F(WindowServerTest, EmbeddedDoesntSeeChild) {
std::unique_ptr<EmbedResult> embed_result = Embed(window_manager(), window);
ASSERT_TRUE(embed_result->IsValid());
aura::Window* embed_root = embed_result->window_tree_host->window();
- EXPECT_EQ(LoWord(server_id(window)), LoWord(server_id(embed_root)));
- EXPECT_NE(0u, server_id(embed_root) >> 16);
+ EXPECT_EQ(ClientWindowIdFromTransportId(server_id(window)),
+ ClientWindowIdFromTransportId(server_id(embed_root)));
+ EXPECT_NE(0u, ClientIdFromTransportId(server_id(embed_root)));
EXPECT_EQ(nullptr, embed_root->parent());
EXPECT_TRUE(embed_root->children().empty());
}
@@ -453,9 +454,11 @@ TEST_F(WindowServerTest, Reorder) {
// |embedded|'s WindowTree has an id_ of embedded_client_id, so window11's
// client_id part should be embedded_client_id in the WindowTree for
// window_manager(). Similar for window12.
- ClientSpecificId embedded_client_id = test::kWindowManagerClientId + 1;
- Id window11_in_wm = embedded_client_id << 16 | LoWord(server_id(window11));
- Id window12_in_wm = embedded_client_id << 16 | LoWord(server_id(window12));
+ Id embedded_client_id = test::kWindowManagerClientId + 1;
+ Id window11_in_wm = embedded_client_id << 32 |
+ ClientWindowIdFromTransportId(server_id(window11));
+ Id window12_in_wm = embedded_client_id << 32 |
+ ClientWindowIdFromTransportId(server_id(window12));
{
window11->parent()->StackChildAtTop(window11);
diff --git a/chromium/services/ui/ws/window_manager_display_root.cc b/chromium/services/ui/ws/window_manager_display_root.cc
index 9b5f1242ec7..0e419875bd7 100644
--- a/chromium/services/ui/ws/window_manager_display_root.cc
+++ b/chromium/services/ui/ws/window_manager_display_root.cc
@@ -25,10 +25,10 @@ WindowManagerDisplayRoot::WindowManagerDisplayRoot(Display* display)
properties[mojom::WindowManager::kName_Property] =
std::vector<uint8_t>(name.begin(), name.end());
- WindowId id = window_server()->display_manager()->GetAndAdvanceNextRootId();
- ClientWindowId client_window_id(id.client_id, id.window_id);
+ const ClientWindowId client_window_id =
+ window_server()->display_manager()->GetAndAdvanceNextRootId();
root_.reset(
- window_server()->CreateServerWindow(id, client_window_id, properties));
+ window_server()->CreateServerWindow(client_window_id, properties));
root_->set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
// Our root is always a child of the Display's root. Do this
diff --git a/chromium/services/ui/ws/window_manager_state.cc b/chromium/services/ui/ws/window_manager_state.cc
index 6960a749928..e0e5b0a4645 100644
--- a/chromium/services/ui/ws/window_manager_state.cc
+++ b/chromium/services/ui/ws/window_manager_state.cc
@@ -10,7 +10,7 @@
#include "base/logging.h"
#include "base/memory/weak_ptr.h"
#include "components/viz/host/host_frame_sink_manager.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/ui/common/accelerator_util.h"
#include "services/ui/ws/accelerator.h"
#include "services/ui/ws/cursor_location_manager.h"
@@ -23,7 +23,6 @@
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/server_window_tracker.h"
#include "services/ui/ws/user_display_manager.h"
-#include "services/ui/ws/user_id_tracker.h"
#include "services/ui/ws/window_manager_display_root.h"
#include "services/ui/ws/window_server.h"
#include "services/ui/ws/window_tree.h"
@@ -74,8 +73,10 @@ std::unique_ptr<ui::Event> CoalesceEvents(std::unique_ptr<ui::Event> first,
const ServerWindow* GetEmbedRoot(const ServerWindow* window) {
DCHECK(window);
const ServerWindow* embed_root = window->parent();
- while (embed_root && embed_root->id().client_id == window->id().client_id)
+ while (embed_root &&
+ embed_root->owning_tree_id() == window->owning_tree_id()) {
embed_root = embed_root->parent();
+ }
return embed_root;
}
@@ -189,7 +190,7 @@ void WindowManagerState::SetFrameDecorationValues(
got_frame_decoration_values_ = true;
frame_decoration_values_ = values.Clone();
UserDisplayManager* user_display_manager =
- display_manager()->GetUserDisplayManager(user_id());
+ display_manager()->GetUserDisplayManager();
user_display_manager->OnFrameDecorationValuesChanged();
if (window_server()->display_creation_config() ==
DisplayCreationConfig::MANUAL &&
@@ -200,7 +201,6 @@ void WindowManagerState::SetFrameDecorationValues(
bool WindowManagerState::SetCapture(ServerWindow* window,
ClientSpecificId client_id) {
- DCHECK(IsActive());
if (capture_window() == window &&
client_id == event_dispatcher_.capture_window_client_id()) {
return true;
@@ -298,10 +298,6 @@ void WindowManagerState::DeleteWindowManagerDisplayRoot(
}
}
-const UserId& WindowManagerState::user_id() const {
- return window_tree_->user_id();
-}
-
void WindowManagerState::OnWillDestroyTree(WindowTree* tree) {
event_dispatcher_.OnWillDestroyDragTargetConnection(tree);
@@ -317,42 +313,6 @@ void WindowManagerState::OnWillDestroyTree(WindowTree* tree) {
: mojom::EventResult::UNHANDLED);
}
-ServerWindow* WindowManagerState::GetOrphanedRootWithId(const WindowId& id) {
- for (auto& display_root_ptr : orphaned_window_manager_display_roots_) {
- if (display_root_ptr->root()->id() == id)
- return display_root_ptr->root();
- }
- return nullptr;
-}
-
-bool WindowManagerState::IsActive() const {
- return window_server()->user_id_tracker()->active_id() == user_id();
-}
-
-void WindowManagerState::Activate(const gfx::Point& mouse_location_on_display,
- int64_t display_id) {
- SetAllRootWindowsVisible(true);
- event_dispatcher_.Reset();
-
- // Fake a mouse event to update cursor and ensure mouse location in client
- // is up to date.
- PointerEvent move_event(ET_POINTER_MOVED, mouse_location_on_display,
- mouse_location_on_display, EF_NONE, EF_NONE,
- PointerDetails(EventPointerType::POINTER_TYPE_MOUSE,
- MouseEvent::kMousePointerId),
- base::TimeTicks::Now());
- ProcessEvent(&move_event, display_id);
-}
-
-void WindowManagerState::Deactivate() {
- SetAllRootWindowsVisible(false);
- event_dispatcher_.Reset();
- // The tree is no longer active, so no point in dispatching any further
- // events.
- base::queue<std::unique_ptr<QueuedEvent>> event_queue;
- event_queue.swap(event_queue_);
-}
-
void WindowManagerState::ProcessEvent(ui::Event* event, int64_t display_id) {
EventLocation event_location(display_id);
if (event->IsLocatedEvent()) {
@@ -399,8 +359,8 @@ void WindowManagerState::OnAcceleratorAck(
} else {
// We're not going to process the event any further, notify event observers.
// We don't do this first to ensure we don't send an event twice to clients.
- window_server()->SendToPointerWatchers(*details->event, user_id(), nullptr,
- nullptr, details->display_id);
+ window_server()->SendToPointerWatchers(*details->event, nullptr, nullptr,
+ details->display_id);
ProcessNextAvailableEvent();
}
}
@@ -444,11 +404,6 @@ void WindowManagerState::OnDisplayDestroying(Display* display) {
}
}
-void WindowManagerState::SetAllRootWindowsVisible(bool value) {
- for (auto& display_root_ptr : window_manager_display_roots_)
- display_root_ptr->root()->SetVisible(value);
-}
-
ServerWindow* WindowManagerState::GetWindowManagerRootForDisplayRoot(
ServerWindow* window) {
for (auto& display_root_ptr : window_manager_display_roots_) {
@@ -531,7 +486,7 @@ void WindowManagerState::DispatchInputEventToWindowImpl(
in_flight_event_dispatch_details_->post_target_accelerator = accelerator;
// Ignore |tree| because it will receive the event via normal dispatch.
- window_server()->SendToPointerWatchers(event, user_id(), target, tree,
+ window_server()->SendToPointerWatchers(event, target, tree,
event_location.display_id);
tree->DispatchInputEvent(
@@ -568,7 +523,7 @@ void WindowManagerState::HandleDebugAccelerator(DebugAcceleratorType type,
// Error so it will be collected in system logs.
for (Display* display : display_manager()->displays()) {
WindowManagerDisplayRoot* display_root =
- display->GetWindowManagerDisplayRootForUser(user_id());
+ display->window_manager_display_root();
if (display_root) {
LOG(ERROR) << "ServerWindow hierarchy:\n"
<< display_root->root()->GetDebugWindowHierarchy();
@@ -576,7 +531,8 @@ void WindowManagerState::HandleDebugAccelerator(DebugAcceleratorType type,
}
ServerWindow* focused_window = GetFocusedWindowForEventDispatcher(display_id);
LOG(ERROR) << "Focused window: "
- << (focused_window ? focused_window->id().ToString() : "(null)");
+ << (focused_window ? focused_window->frame_sink_id().ToString()
+ : "(null)");
#endif
}
@@ -606,8 +562,7 @@ bool WindowManagerState::ConvertPointToScreen(int64_t display_id,
if (!display)
return false;
- WindowManagerDisplayRoot* root =
- display->GetWindowManagerDisplayRootForUser(user_id());
+ WindowManagerDisplayRoot* root = display->window_manager_display_root();
if (!root)
return false;
@@ -615,7 +570,7 @@ bool WindowManagerState::ConvertPointToScreen(int64_t display_id,
gfx::Transform transform;
transform.Scale(originated_display.device_scale_factor(),
originated_display.device_scale_factor());
- transform *= display->GetWindowManagerDisplayRootForUser(user_id())
+ transform *= display->window_manager_display_root()
->GetClientVisibleRoot()
->transform();
gfx::Transform invert;
@@ -691,7 +646,6 @@ void WindowManagerState::OnAccelerator(uint32_t accelerator_id,
int64_t display_id,
const ui::Event& event,
AcceleratorPhase phase) {
- DCHECK(IsActive());
const bool needs_ack = phase == AcceleratorPhase::PRE;
WindowTree::AcceleratorCallback ack_callback;
if (needs_ack) {
@@ -707,7 +661,6 @@ void WindowManagerState::OnAccelerator(uint32_t accelerator_id,
void WindowManagerState::SetFocusedWindowFromEventDispatcher(
ServerWindow* new_focused_window) {
- DCHECK(IsActive());
window_server()->SetFocusedWindow(new_focused_window);
}
@@ -729,7 +682,12 @@ ServerWindow* WindowManagerState::GetFocusedWindowForEventDispatcher(
void WindowManagerState::SetNativeCapture(ServerWindow* window) {
DCHECK(window);
- DCHECK(IsActive());
+
+ // Classic ash expects no native grab when in unified display.
+ // See http://crbug.com/773348 for details.
+ if (display_manager()->InUnifiedDisplayMode())
+ return;
+
WindowManagerDisplayRoot* display_root =
display_manager()->GetWindowManagerDisplayRoot(window);
DCHECK(display_root);
@@ -738,6 +696,11 @@ void WindowManagerState::SetNativeCapture(ServerWindow* window) {
}
void WindowManagerState::ReleaseNativeCapture() {
+ // Classic ash expects no native grab when in unified display.
+ // See http://crbug.com/773348 for details.
+ if (display_manager()->InUnifiedDisplayMode())
+ return;
+
// Tests trigger calling this without a corresponding SetNativeCapture().
// TODO(sky): maybe abstract this away so that DCHECK can be added?
if (!platform_display_with_capture_)
@@ -764,7 +727,7 @@ void WindowManagerState::OnMouseCursorLocationChanged(
if (ConvertPointToScreen(display_id, &point_in_screen)) {
window_server()
->display_manager()
- ->GetCursorLocationManager(user_id())
+ ->cursor_location_manager()
->OnMouseCursorLocationChanged(point_in_screen);
}
// If the display the |point_in_display| is on has been deleted, keep the old
@@ -795,7 +758,6 @@ void WindowManagerState::DispatchInputEventToWindow(
const EventLocation& event_location,
const ui::Event& event,
Accelerator* accelerator) {
- DCHECK(IsActive());
// TODO(sky): this needs to see if another wms has capture and if so forward
// to it.
if (in_flight_event_dispatch_details_) {
@@ -852,7 +814,7 @@ ClientSpecificId WindowManagerState::GetEventTargetClientId(
WindowTree* tree = window_server()->GetTreeWithRoot(window);
if (!tree) {
// Window is not an embed root, event goes to owner of the window.
- tree = window_server()->GetTreeWithId(window->id().client_id);
+ tree = window_server()->GetTreeWithId(window->owning_tree_id());
}
DCHECK(tree);
@@ -861,7 +823,7 @@ ClientSpecificId WindowManagerState::GetEventTargetClientId(
tree->HasRoot(window) ? window : GetEmbedRoot(window);
while (tree && tree->embedder_intercepts_events()) {
DCHECK(tree->HasRoot(embed_root));
- tree = window_server()->GetTreeWithId(embed_root->id().client_id);
+ tree = window_server()->GetTreeWithId(embed_root->owning_tree_id());
embed_root = GetEmbedRoot(embed_root);
}
DCHECK(tree);
@@ -873,8 +835,7 @@ ServerWindow* WindowManagerState::GetRootWindowForDisplay(int64_t display_id) {
if (!display)
return nullptr;
- return display->GetWindowManagerDisplayRootForUser(user_id())
- ->GetClientVisibleRoot();
+ return display->window_manager_display_root()->GetClientVisibleRoot();
}
ServerWindow* WindowManagerState::GetRootWindowForEventDispatch(
@@ -901,7 +862,7 @@ bool WindowManagerState::IsWindowInDisplayRoot(const ServerWindow* window) {
void WindowManagerState::OnEventTargetNotFound(const ui::Event& event,
int64_t display_id) {
- window_server()->SendToPointerWatchers(event, user_id(), nullptr, /* window */
+ window_server()->SendToPointerWatchers(event, nullptr, /* window */
nullptr /* ignore_tree */, display_id);
if (event.IsMousePointerEvent())
UpdateNativeCursorFromDispatcher();
diff --git a/chromium/services/ui/ws/window_manager_state.h b/chromium/services/ui/ws/window_manager_state.h
index ed9ac9dc47e..fb01e1aa92d 100644
--- a/chromium/services/ui/ws/window_manager_state.h
+++ b/chromium/services/ui/ws/window_manager_state.h
@@ -21,7 +21,6 @@
#include "services/ui/ws/event_dispatcher.h"
#include "services/ui/ws/event_dispatcher_delegate.h"
#include "services/ui/ws/server_window_observer.h"
-#include "services/ui/ws/user_id.h"
#include "services/ui/ws/window_server.h"
namespace viz {
@@ -50,8 +49,6 @@ class WindowManagerState : public EventDispatcherDelegate,
explicit WindowManagerState(WindowTree* window_tree);
~WindowManagerState() override;
- const UserId& user_id() const;
-
WindowTree* window_tree() { return window_tree_; }
const WindowTree* window_tree() const { return window_tree_; }
@@ -95,24 +92,12 @@ class WindowManagerState : public EventDispatcherDelegate,
// Deletes the WindowManagerDisplayRoot whose root is |display_root|.
void DeleteWindowManagerDisplayRoot(ServerWindow* display_root);
- // Returns the ServerWindow corresponding to an orphaned root with the
- // specified id. See |orphaned_window_manager_display_roots_| for details on
- // what on orphaned root is.
- ServerWindow* GetOrphanedRootWithId(const WindowId& id);
-
// TODO(sky): EventDispatcher is really an implementation detail and should
// not be exposed.
EventDispatcher* event_dispatcher() { return &event_dispatcher_; }
CursorState& cursor_state() { return cursor_state_; }
- // Returns true if this is the WindowManager of the active user.
- bool IsActive() const;
-
- void Activate(const gfx::Point& mouse_location_on_display,
- int64_t display_id);
- void Deactivate();
-
// Processes an event from PlatformDisplay. This doesn't take ownership of
// |event|, but it may modify it.
void ProcessEvent(ui::Event* event, int64_t display_id);
@@ -193,9 +178,6 @@ class WindowManagerState : public EventDispatcherDelegate,
// Called when a Display is deleted.
void OnDisplayDestroying(Display* display);
- // Sets the visibility of all window manager roots windows to |value|.
- void SetAllRootWindowsVisible(bool value);
-
// Returns the ServerWindow that is the root of the WindowManager for
// |window|. |window| corresponds to the root of a Display.
ServerWindow* GetWindowManagerRootForDisplayRoot(ServerWindow* window);
diff --git a/chromium/services/ui/ws/window_manager_state_unittest.cc b/chromium/services/ui/ws/window_manager_state_unittest.cc
index bc845633476..5f3def7a16f 100644
--- a/chromium/services/ui/ws/window_manager_state_unittest.cc
+++ b/chromium/services/ui/ws/window_manager_state_unittest.cc
@@ -12,7 +12,7 @@
#include "base/memory/ref_counted.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/ui/common/accelerator_util.h"
#include "services/ui/common/switches.h"
#include "services/ui/ws/accelerator.h"
@@ -164,7 +164,7 @@ void WindowManagerStateTest::OnEventAckTimeout(
void WindowManagerStateTest::SetUp() {
window_event_targeting_helper_.SetTaskRunner(task_runner_);
window_manager_state_ = window_event_targeting_helper_.display()
- ->GetActiveWindowManagerDisplayRoot()
+ ->window_manager_display_root()
->window_manager_state();
window_ = window_event_targeting_helper_.CreatePrimaryTree(
gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 50, 50));
@@ -568,22 +568,19 @@ TEST_F(WindowManagerStateTest, AckTimeout) {
"InputEvent window=" + kWindowManagerClientIdString + ",1 event_action=7",
ChangesToDescription1(*tracker->changes())[0]);
- OnEventAckTimeout(window()->id().client_id);
+ OnEventAckTimeout(window()->owning_tree_id());
EXPECT_TRUE(window_manager()->on_accelerator_called());
EXPECT_EQ(accelerator->id(), window_manager()->on_accelerator_id());
}
TEST_F(WindowManagerStateTest, InterceptingEmbedderReceivesEvents) {
WindowTree* embedder_tree = tree();
- ServerWindow* embedder_root = window();
const ClientWindowId embed_window_id(embedder_tree->id(), 12);
embedder_tree->NewWindow(embed_window_id, ServerWindow::Properties());
ServerWindow* embedder_window =
embedder_tree->GetWindowByClientId(embed_window_id);
ASSERT_TRUE(
- embedder_tree->AddWindow(ClientWindowId(embedder_root->id().client_id,
- embedder_root->id().window_id),
- embed_window_id));
+ embedder_tree->AddWindow(FirstRootId(embedder_tree), embed_window_id));
TestWindowTreeClient* embedder_client = wm_client();
@@ -725,12 +722,11 @@ TEST(WindowManagerStateShutdownTest, DestroyTreeBeforeDisplay) {
TestScreenManager screen_manager;
screen_manager.Init(window_server->display_manager());
screen_manager.AddDisplay();
- const UserId kUserId1 = "2";
- AddWindowManager(window_server, kUserId1);
+ AddWindowManager(window_server);
ASSERT_EQ(1u, window_server->display_manager()->displays().size());
Display* display = *(window_server->display_manager()->displays().begin());
WindowManagerDisplayRoot* window_manager_display_root =
- display->GetWindowManagerDisplayRootForUser(kUserId1);
+ display->window_manager_display_root();
ASSERT_TRUE(window_manager_display_root);
WindowTree* tree =
window_manager_display_root->window_manager_state()->window_tree();
@@ -769,12 +765,16 @@ TEST(WindowManagerStateEventTest, AdjustEventLocation) {
WindowServer* window_server = ws_test_helper.window_server();
TestScreenManager screen_manager;
screen_manager.Init(window_server->display_manager());
- const UserId kUserId1 = "2";
- AddWindowManager(window_server, kUserId1);
- window_server->user_id_tracker()->AddUserId(kUserId1);
- window_server->user_id_tracker()->SetActiveUserId(kUserId1);
+ AddWindowManager(window_server);
const int64_t first_display_id = screen_manager.AddDisplay();
const int64_t second_display_id = screen_manager.AddDisplay();
+ Display* first_display =
+ window_server->display_manager()->GetDisplayById(first_display_id);
+ // As there are no child windows make sure the root is a valid target.
+ first_display->window_manager_display_root()
+ ->GetClientVisibleRoot()
+ ->set_event_targeting_policy(
+ mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
Display* second_display =
window_server->display_manager()->GetDisplayById(second_display_id);
ASSERT_TRUE(second_display);
@@ -792,7 +792,7 @@ TEST(WindowManagerStateEventTest, AdjustEventLocation) {
ui::PointerDetails(EventPointerType::POINTER_TYPE_MOUSE, 0),
base::TimeTicks());
WindowManagerDisplayRoot* window_manager_display_root =
- second_display->GetWindowManagerDisplayRootForUser(kUserId1);
+ second_display->window_manager_display_root();
TestChangeTracker* tracker =
ws_test_helper.window_server_delegate()->last_client()->tracker();
tracker->changes()->clear();
@@ -823,8 +823,7 @@ TEST_F(WindowManagerStateTest, CursorLocationManagerUpdatedOnMouseMove) {
// Tests add display with kInvalidDisplayId.
window_manager_state()->ProcessEvent(&move, display::kInvalidDisplayId);
CursorLocationManager* cursor_location_manager =
- window_server()->display_manager()->GetCursorLocationManager(
- window_manager_state()->user_id());
+ window_server()->display_manager()->cursor_location_manager();
// The location reported to clients is offset by the root transform.
EXPECT_EQ(
gfx::Point(19, 18),
@@ -832,6 +831,27 @@ TEST_F(WindowManagerStateTest, CursorLocationManagerUpdatedOnMouseMove) {
.current_cursor_location()));
}
+TEST_F(WindowManagerStateTest, SetCapture) {
+ ASSERT_EQ(1u, window_server()->display_manager()->displays().size());
+ Display* display = *(window_server()->display_manager()->displays().begin());
+ TestPlatformDisplay* platform_display =
+ static_cast<TestPlatformDisplay*>(display->platform_display());
+ EXPECT_TRUE(window_tree()->SetCapture(FirstRootId(window_tree())));
+ EXPECT_EQ(FirstRoot(window_tree()), window_manager_state()->capture_window());
+ EXPECT_TRUE(platform_display->has_capture());
+ EXPECT_TRUE(window_tree()->ReleaseCapture(FirstRootId(window_tree())));
+ EXPECT_FALSE(platform_display->has_capture());
+
+ // In unified mode capture should not propagate to the PlatformDisplay. This
+ // is for compatibility with classic ash. See http://crbug.com/773348.
+ display->SetDisplay(display::Display(display::kUnifiedDisplayId));
+ EXPECT_TRUE(window_tree()->SetCapture(FirstRootId(window_tree())));
+ EXPECT_EQ(FirstRoot(window_tree()), window_manager_state()->capture_window());
+ EXPECT_FALSE(platform_display->has_capture());
+ EXPECT_TRUE(window_tree()->ReleaseCapture(FirstRootId(window_tree())));
+ EXPECT_FALSE(platform_display->has_capture());
+}
+
TEST_F(WindowManagerStateTestAsync, CursorResetOverNoTargetAsync) {
ASSERT_EQ(1u, window_server()->display_manager()->displays().size());
const ClientWindowId child_window_id(window_tree()->id(), 11);
diff --git a/chromium/services/ui/ws/window_manager_window_tree_factory.cc b/chromium/services/ui/ws/window_manager_window_tree_factory.cc
index ab38d7b2c3d..7e279889869 100644
--- a/chromium/services/ui/ws/window_manager_window_tree_factory.cc
+++ b/chromium/services/ui/ws/window_manager_window_tree_factory.cc
@@ -6,7 +6,7 @@
#include "base/bind.h"
#include "services/ui/ws/display_creation_config.h"
-#include "services/ui/ws/window_manager_window_tree_factory_set.h"
+#include "services/ui/ws/window_manager_window_tree_factory_observer.h"
#include "services/ui/ws/window_server.h"
#include "services/ui/ws/window_server_delegate.h"
#include "services/ui/ws/window_tree.h"
@@ -15,17 +15,30 @@ namespace ui {
namespace ws {
WindowManagerWindowTreeFactory::WindowManagerWindowTreeFactory(
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
- const UserId& user_id,
- mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request)
- : WindowManagerWindowTreeFactory(window_manager_window_tree_factory_set,
- user_id) {
- if (request.is_pending())
- binding_.Bind(std::move(request));
-}
+ WindowServer* window_server)
+ : window_server_(window_server), binding_(this) {}
WindowManagerWindowTreeFactory::~WindowManagerWindowTreeFactory() {}
+void WindowManagerWindowTreeFactory::Bind(
+ mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request) {
+ binding_.Bind(std::move(request));
+}
+
+void WindowManagerWindowTreeFactory::AddObserver(
+ WindowManagerWindowTreeFactoryObserver* observer) {
+ observers_.AddObserver(observer);
+}
+
+void WindowManagerWindowTreeFactory::RemoveObserver(
+ WindowManagerWindowTreeFactoryObserver* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+void WindowManagerWindowTreeFactory::OnTreeDestroyed() {
+ window_tree_ = nullptr;
+}
+
void WindowManagerWindowTreeFactory::CreateWindowTree(
mojom::WindowTreeRequest window_tree_request,
mojom::WindowTreeClientPtr window_tree_client,
@@ -42,35 +55,23 @@ void WindowManagerWindowTreeFactory::CreateWindowTree(
// If the config is MANUAL, then all WindowManagers must connect as MANUAL.
if (!automatically_create_display_roots &&
- GetWindowServer()->display_creation_config() ==
+ window_server_->display_creation_config() ==
DisplayCreationConfig::AUTOMATIC) {
DVLOG(1) << "CreateWindowTree() called with manual and automatic.";
return;
}
- SetWindowTree(GetWindowServer()->CreateTreeForWindowManager(
- user_id_, std::move(window_tree_request), std::move(window_tree_client),
+ SetWindowTree(window_server_->CreateTreeForWindowManager(
+ std::move(window_tree_request), std::move(window_tree_client),
automatically_create_display_roots));
}
-WindowManagerWindowTreeFactory::WindowManagerWindowTreeFactory(
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
- const UserId& user_id)
- : window_manager_window_tree_factory_set_(
- window_manager_window_tree_factory_set),
- user_id_(user_id),
- binding_(this) {}
-
-WindowServer* WindowManagerWindowTreeFactory::GetWindowServer() {
- return window_manager_window_tree_factory_set_->window_server();
-}
-
void WindowManagerWindowTreeFactory::SetWindowTree(WindowTree* window_tree) {
DCHECK(!window_tree_);
window_tree_ = window_tree;
- window_manager_window_tree_factory_set_
- ->OnWindowManagerWindowTreeFactoryReady(this);
+ for (WindowManagerWindowTreeFactoryObserver& observer : observers_)
+ observer.OnWindowManagerWindowTreeFactoryReady(this);
}
} // namespace ws
diff --git a/chromium/services/ui/ws/window_manager_window_tree_factory.h b/chromium/services/ui/ws/window_manager_window_tree_factory.h
index ce56479db8b..7c2b2f11359 100644
--- a/chromium/services/ui/ws/window_manager_window_tree_factory.h
+++ b/chromium/services/ui/ws/window_manager_window_tree_factory.h
@@ -9,12 +9,11 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom.h"
-#include "services/ui/ws/user_id.h"
namespace ui {
namespace ws {
-class WindowManagerWindowTreeFactorySet;
+class WindowManagerWindowTreeFactoryObserver;
class WindowServer;
class WindowTree;
@@ -22,37 +21,37 @@ class WindowTree;
class WindowManagerWindowTreeFactory
: public mojom::WindowManagerWindowTreeFactory {
public:
- WindowManagerWindowTreeFactory(
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set,
- const UserId& user_id,
- mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request);
+ explicit WindowManagerWindowTreeFactory(WindowServer* window_server);
~WindowManagerWindowTreeFactory() override;
- const UserId& user_id() const { return user_id_; }
-
WindowTree* window_tree() { return window_tree_; }
+ bool is_bound() const { return binding_.is_bound(); }
+
+ void Bind(
+ mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request);
+
+ void AddObserver(WindowManagerWindowTreeFactoryObserver* observer);
+ void RemoveObserver(WindowManagerWindowTreeFactoryObserver* observer);
+
+ void OnTreeDestroyed();
+
// mojom::WindowManagerWindowTreeFactory:
void CreateWindowTree(mojom::WindowTreeRequest window_tree_request,
mojom::WindowTreeClientPtr window_tree_client,
bool window_manager_creates_roots) override;
private:
- // Used by tests.
- WindowManagerWindowTreeFactory(WindowManagerWindowTreeFactorySet* registry,
- const UserId& user_id);
-
- WindowServer* GetWindowServer();
-
void SetWindowTree(WindowTree* window_tree);
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set_;
- const UserId user_id_;
+ WindowServer* window_server_;
mojo::Binding<mojom::WindowManagerWindowTreeFactory> binding_;
// Owned by WindowServer.
WindowTree* window_tree_ = nullptr;
+ base::ObserverList<WindowManagerWindowTreeFactoryObserver> observers_;
+
DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactory);
};
diff --git a/chromium/services/ui/ws/window_manager_window_tree_factory_set_observer.h b/chromium/services/ui/ws/window_manager_window_tree_factory_observer.h
index ec12c9fb1ab..70a0ff7c1de 100644
--- a/chromium/services/ui/ws/window_manager_window_tree_factory_set_observer.h
+++ b/chromium/services/ui/ws/window_manager_window_tree_factory_observer.h
@@ -1,26 +1,26 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2018 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 SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
-#define SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
+#ifndef SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_OBSERVER_H_
+#define SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_OBSERVER_H_
namespace ui {
namespace ws {
class WindowManagerWindowTreeFactory;
-class WindowManagerWindowTreeFactorySetObserver {
+class WindowManagerWindowTreeFactoryObserver {
public:
// Called when the WindowTree associated with |factory| has been set
virtual void OnWindowManagerWindowTreeFactoryReady(
WindowManagerWindowTreeFactory* factory) = 0;
protected:
- virtual ~WindowManagerWindowTreeFactorySetObserver() {}
+ virtual ~WindowManagerWindowTreeFactoryObserver() {}
};
} // namespace ws
} // namespace ui
-#endif // SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_OBSERVER_H_
+#endif // SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_OBSERVER_H_
diff --git a/chromium/services/ui/ws/window_manager_window_tree_factory_set.cc b/chromium/services/ui/ws/window_manager_window_tree_factory_set.cc
deleted file mode 100644
index 4d1981c5c17..00000000000
--- a/chromium/services/ui/ws/window_manager_window_tree_factory_set.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// 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.
-
-#include "services/ui/ws/window_manager_window_tree_factory_set.h"
-
-#include "services/ui/ws/user_id_tracker_observer.h"
-#include "services/ui/ws/window_manager_window_tree_factory.h"
-#include "services/ui/ws/window_manager_window_tree_factory_set_observer.h"
-#include "services/ui/ws/window_server.h"
-#include "services/ui/ws/window_tree.h"
-
-namespace ui {
-namespace ws {
-
-WindowManagerWindowTreeFactorySet::WindowManagerWindowTreeFactorySet(
- WindowServer* window_server,
- UserIdTracker* id_tracker)
- : id_tracker_(id_tracker), window_server_(window_server) {
- id_tracker_->AddObserver(this);
-}
-
-WindowManagerWindowTreeFactorySet::~WindowManagerWindowTreeFactorySet() {
- id_tracker_->RemoveObserver(this);
-}
-
-WindowManagerWindowTreeFactory* WindowManagerWindowTreeFactorySet::Add(
- const UserId& user_id,
- mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request) {
- if (factories_.count(user_id)) {
- DVLOG(1) << "can only have one factory per user";
- return nullptr;
- }
-
- std::unique_ptr<WindowManagerWindowTreeFactory> factory_ptr(
- new WindowManagerWindowTreeFactory(this, user_id, std::move(request)));
- WindowManagerWindowTreeFactory* factory = factory_ptr.get();
- factories_[user_id] = std::move(factory_ptr);
- return factory;
-}
-
-WindowManagerState*
-WindowManagerWindowTreeFactorySet::GetWindowManagerStateForUser(
- const UserId& user_id) {
- auto it = factories_.find(user_id);
- if (it == factories_.end())
- return nullptr;
- return it->second->window_tree()
- ? it->second->window_tree()->window_manager_state()
- : nullptr;
-}
-
-void WindowManagerWindowTreeFactorySet::DeleteFactoryAssociatedWithTree(
- WindowTree* window_tree) {
- for (auto it = factories_.begin(); it != factories_.end(); ++it) {
- if (it->second->window_tree() == window_tree) {
- factories_.erase(it);
- return;
- }
- }
-}
-
-std::vector<WindowManagerWindowTreeFactory*>
-WindowManagerWindowTreeFactorySet::GetFactories() {
- std::vector<WindowManagerWindowTreeFactory*> result;
- for (auto& pair : factories_)
- result.push_back(pair.second.get());
- return result;
-}
-
-void WindowManagerWindowTreeFactorySet::AddObserver(
- WindowManagerWindowTreeFactorySetObserver* observer) {
- observers_.AddObserver(observer);
-}
-
-void WindowManagerWindowTreeFactorySet::RemoveObserver(
- WindowManagerWindowTreeFactorySetObserver* observer) {
- observers_.RemoveObserver(observer);
-}
-
-void WindowManagerWindowTreeFactorySet::OnWindowManagerWindowTreeFactoryReady(
- WindowManagerWindowTreeFactory* factory) {
- for (auto& observer : observers_)
- observer.OnWindowManagerWindowTreeFactoryReady(factory);
-}
-
-void WindowManagerWindowTreeFactorySet::OnUserIdRemoved(const UserId& id) {
- factories_.erase(id);
-}
-
-} // namespace ws
-} // namespace ui
diff --git a/chromium/services/ui/ws/window_manager_window_tree_factory_set.h b/chromium/services/ui/ws/window_manager_window_tree_factory_set.h
deleted file mode 100644
index b20c3bcdffc..00000000000
--- a/chromium/services/ui/ws/window_manager_window_tree_factory_set.h
+++ /dev/null
@@ -1,86 +0,0 @@
-// 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.
-
-#ifndef SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
-#define SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/observer_list.h"
-#include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom.h"
-#include "services/ui/ws/user_id_tracker_observer.h"
-
-namespace ui {
-namespace ws {
-
-class UserIdTracker;
-class WindowManagerState;
-class WindowManagerWindowTreeFactory;
-class WindowManagerWindowTreeFactorySetObserver;
-class WindowServer;
-class WindowTree;
-
-// WindowManagerWindowTreeFactorySet tracks the set of registered
-// WindowManagerWindowTreeHostFactories.
-class WindowManagerWindowTreeFactorySet : public UserIdTrackerObserver {
- public:
- WindowManagerWindowTreeFactorySet(WindowServer* window_server,
- UserIdTracker* tracker);
- ~WindowManagerWindowTreeFactorySet() override;
-
- WindowServer* window_server() { return window_server_; }
-
- // Creates a new WindowManagerWindowTreeFactory for the specified user,
- // unless one has been set, in which case the call is ignored. The newly
- // created WindowManagerWindowTreeFactory does not immediately have a
- // WindowTree associated with it.
- WindowManagerWindowTreeFactory* Add(
- const UserId& user_id,
- mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request);
-
- // Returns the WindowManagerState for the specified user, or null if
- // not yet set.
- WindowManagerState* GetWindowManagerStateForUser(const UserId& user_id);
-
- // Deletes the WindowManagerWindowTreeFactory associated with |tree|. Does
- // nothing if there is no WindowManagerWindowTreeFactory associated with
- // |tree|.
- void DeleteFactoryAssociatedWithTree(WindowTree* tree);
-
- // Returns all the factories, even those that may not have a WindowTree
- // associated with them.
- std::vector<WindowManagerWindowTreeFactory*> GetFactories();
-
- void AddObserver(WindowManagerWindowTreeFactorySetObserver* observer);
- void RemoveObserver(WindowManagerWindowTreeFactorySetObserver* observer);
-
- private:
- friend class WindowManagerWindowTreeFactory;
-
- // Called by WindowManagerWindowTreeFactory when CreateWindowTree() has
- // been called.
- void OnWindowManagerWindowTreeFactoryReady(
- WindowManagerWindowTreeFactory* factory);
-
- // UserIdTrackerObserver:
- void OnUserIdRemoved(const UserId& id) override;
-
- UserIdTracker* id_tracker_;
- WindowServer* window_server_;
-
- std::map<UserId, std::unique_ptr<WindowManagerWindowTreeFactory>> factories_;
-
- base::ObserverList<WindowManagerWindowTreeFactorySetObserver> observers_;
-
- DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactorySet);
-};
-
-} // namespace ws
-} // namespace ui
-
-#endif // SERVICES_UI_WS_WINDOW_MANAGER_WINDOW_TREE_FACTORY_SET_H_
diff --git a/chromium/services/ui/ws/window_server.cc b/chromium/services/ui/ws/window_server.cc
index 974c9ee3734..626b6225297 100644
--- a/chromium/services/ui/ws/window_server.cc
+++ b/chromium/services/ui/ws/window_server.cc
@@ -41,7 +41,7 @@ bool IsWindowConsideredWindowManagerRoot(const Display* display,
return false;
const WindowManagerDisplayRoot* display_root =
- display->GetActiveWindowManagerDisplayRoot();
+ display->window_manager_display_root();
return display_root && display_root->GetClientVisibleRoot() == window;
}
@@ -135,11 +135,12 @@ struct WindowServer::CurrentDragLoopState {
WindowServer::WindowServer(WindowServerDelegate* delegate, bool should_host_viz)
: delegate_(delegate),
next_client_id_(kWindowServerClientId + 1),
- display_manager_(new DisplayManager(this, &user_id_tracker_)),
+ display_manager_(std::make_unique<DisplayManager>(this)),
current_operation_(nullptr),
in_destructor_(false),
next_wm_change_id_(0),
- window_manager_window_tree_factory_set_(this, &user_id_tracker_),
+ window_manager_window_tree_factory_(
+ std::make_unique<WindowManagerWindowTreeFactory>(this)),
host_frame_sink_manager_(
should_host_viz ? std::make_unique<viz::HostFrameSinkManager>()
: nullptr),
@@ -149,8 +150,7 @@ WindowServer::WindowServer(WindowServerDelegate* delegate, bool should_host_viz)
display_creation_config_(DisplayCreationConfig::UNKNOWN) {
if (host_frame_sink_manager_)
host_frame_sink_manager_->WillAssignTemporaryReferencesExternally();
- user_id_tracker_.AddObserver(this);
- OnUserIdAdded(user_id_tracker_.active_id());
+ user_activity_monitor_ = std::make_unique<UserActivityMonitor>(nullptr);
}
WindowServer::~WindowServer() {
@@ -159,11 +159,6 @@ WindowServer::~WindowServer() {
for (auto& pair : tree_map_)
pair.second->PrepareForWindowServerShutdown();
- // Shutdown GPU before destroying PlatformWindows for displays so that
- // GLSurfaces corresponding to a windows AcceleratedWidget gets destroyed
- // first.
- gpu_host_.reset();
-
// Destroys the window trees results in querying for the display. Tear down
// the displays first so that the trees are notified of the display going
// away while the display is still valid.
@@ -193,28 +188,27 @@ ThreadedImageCursorsFactory* WindowServer::GetThreadedImageCursorsFactory() {
}
ServerWindow* WindowServer::CreateServerWindow(
- const WindowId& id,
const viz::FrameSinkId& frame_sink_id,
const std::map<std::string, std::vector<uint8_t>>& properties) {
- ServerWindow* window = new ServerWindow(this, id, frame_sink_id, properties);
+ ServerWindow* window = new ServerWindow(this, frame_sink_id, properties);
window->AddObserver(this);
return window;
}
ClientSpecificId WindowServer::GetAndAdvanceNextClientId() {
const ClientSpecificId id = next_client_id_++;
- DCHECK_LT(id, next_client_id_);
+ CHECK_NE(0u, next_client_id_);
return id;
}
WindowTree* WindowServer::EmbedAtWindow(
ServerWindow* root,
- const UserId& user_id,
mojom::WindowTreeClientPtr client,
uint32_t flags,
std::unique_ptr<AccessPolicy> access_policy) {
- std::unique_ptr<WindowTree> tree_ptr(
- new WindowTree(this, user_id, root, std::move(access_policy)));
+ const bool is_for_embedding = true;
+ std::unique_ptr<WindowTree> tree_ptr = std::make_unique<WindowTree>(
+ this, is_for_embedding, root, std::move(access_policy));
WindowTree* tree = tree_ptr.get();
if (flags & mojom::kEmbedFlagEmbedderInterceptsEvents)
tree->set_embedder_intercepts_events();
@@ -249,15 +243,16 @@ void WindowServer::AddTree(std::unique_ptr<WindowTree> tree_impl_ptr,
}
WindowTree* WindowServer::CreateTreeForWindowManager(
- const UserId& user_id,
mojom::WindowTreeRequest window_tree_request,
mojom::WindowTreeClientPtr window_tree_client,
bool automatically_create_display_roots) {
delegate_->OnWillCreateTreeForWindowManager(
automatically_create_display_roots);
- std::unique_ptr<WindowTree> window_tree(new WindowTree(
- this, user_id, nullptr, base::WrapUnique(new WindowManagerAccessPolicy)));
+ const bool is_for_embedding = false;
+ std::unique_ptr<WindowTree> window_tree = std::make_unique<WindowTree>(
+ this, is_for_embedding, nullptr,
+ base::WrapUnique(new WindowManagerAccessPolicy));
std::unique_ptr<WindowTreeBinding> window_tree_binding =
delegate_->CreateWindowTreeBinding(
WindowServerDelegate::BindingType::WINDOW_MANAGER, this,
@@ -286,7 +281,8 @@ void WindowServer::DestroyTree(WindowTree* tree) {
for (auto& pair : tree_map_)
pair.second->OnWindowDestroyingTreeImpl(tree);
- window_manager_window_tree_factory_set_.DeleteFactoryAssociatedWithTree(tree);
+ if (window_manager_window_tree_factory_->window_tree() == tree)
+ window_manager_window_tree_factory_->OnTreeDestroyed();
// Remove any requests from the client that resulted in a call to the window
// manager and we haven't gotten a response back yet.
@@ -313,29 +309,6 @@ WindowTree* WindowServer::GetTreeWithClientName(
return nullptr;
}
-ServerWindow* WindowServer::GetWindow(const WindowId& id) {
- // kWindowServerClientId is used for Display and WindowManager nodes.
- if (id.client_id == kWindowServerClientId) {
- for (Display* display : display_manager_->displays()) {
- ServerWindow* window = display->GetRootWithId(id);
- if (window)
- return window;
- }
- // WindowManagerDisplayRoots are destroyed by the client and not held by
- // the Display.
- for (auto& pair : tree_map_) {
- if (pair.second->window_manager_state()) {
- ServerWindow* window =
- pair.second->window_manager_state()->GetOrphanedRootWithId(id);
- if (window)
- return window;
- }
- }
- }
- WindowTree* tree = GetTreeWithId(id.client_id);
- return tree ? tree->GetWindow(id) : nullptr;
-}
-
void WindowServer::OnTreeMessagedClient(ClientSpecificId id) {
if (current_operation_)
current_operation_->MarkTreeAsMessaged(id);
@@ -356,10 +329,13 @@ const WindowTree* WindowServer::GetTreeWithRoot(
return nullptr;
}
-UserActivityMonitor* WindowServer::GetUserActivityMonitorForUser(
- const UserId& user_id) {
- DCHECK_GT(activity_monitor_map_.count(user_id), 0u);
- return activity_monitor_map_[user_id].get();
+void WindowServer::BindWindowManagerWindowTreeFactory(
+ mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request) {
+ if (window_manager_window_tree_factory_->is_bound()) {
+ DVLOG(1) << "Can only have one WindowManagerWindowTreeFactory";
+ return;
+ }
+ window_manager_window_tree_factory_->Bind(std::move(request));
}
bool WindowServer::SetFocusedWindow(ServerWindow* window) {
@@ -396,17 +372,15 @@ ServerWindow* WindowServer::GetFocusedWindow() {
return nullptr;
}
-void WindowServer::SetHighContrastMode(const UserId& user, bool enabled) {
+void WindowServer::SetHighContrastMode(bool enabled) {
// TODO(fsamuel): This doesn't really seem like it's a window server concept?
- if (IsUserInHighContrastMode(user) == enabled)
+ if (high_contrast_mode_ == enabled)
return;
- high_contrast_mode_[user] = enabled;
+ high_contrast_mode_ = enabled;
- if (user == user_id_tracker_.active_id()) {
- // Propagate the change to all Displays so that FrameGenerators start
- // requesting BeginFrames.
- display_manager_->SetHighContrastMode(enabled);
- }
+ // Propagate the change to all Displays so that FrameGenerators start
+ // requesting BeginFrames.
+ display_manager_->SetHighContrastMode(enabled);
}
uint32_t WindowServer::GenerateWindowManagerChangeId(
@@ -453,7 +427,7 @@ void WindowServer::WindowManagerCreatedTopLevelWindow(
WindowManagerSentBogusMessage();
return;
}
- if (window && (window->id().client_id != wm_tree->id() ||
+ if (window && (window->owning_tree_id() != wm_tree->id() ||
!window->children().empty() || GetTreeWithRoot(window))) {
DVLOG(1)
<< "WindowManager responded with invalid window; window should "
@@ -561,13 +535,12 @@ void WindowServer::ProcessWillChangeWindowCursor(ServerWindow* window,
}
void WindowServer::SendToPointerWatchers(const ui::Event& event,
- const UserId& user_id,
ServerWindow* target_window,
WindowTree* ignore_tree,
int64_t display_id) {
for (auto& pair : tree_map_) {
WindowTree* tree = pair.second.get();
- if (tree->user_id() == user_id && tree != ignore_tree)
+ if (tree != ignore_tree)
tree->SendToPointerWatcher(event, target_window, display_id);
}
}
@@ -674,10 +647,11 @@ void WindowServer::OnNoMoreDisplays() {
delegate_->OnNoMoreDisplays();
}
-WindowManagerState* WindowServer::GetWindowManagerStateForUser(
- const UserId& user_id) {
- return window_manager_window_tree_factory_set_.GetWindowManagerStateForUser(
- user_id);
+WindowManagerState* WindowServer::GetWindowManagerState() {
+ return window_manager_window_tree_factory_->window_tree()
+ ? window_manager_window_tree_factory_->window_tree()
+ ->window_manager_state()
+ : nullptr;
}
VizHostProxy* WindowServer::GetVizHostProxy() {
@@ -710,17 +684,14 @@ void WindowServer::OnFirstSurfaceActivation(
// We always use the owner of the window's id (even for an embedded window),
// because an embedded window's id is allocated by the parent's window tree.
- WindowTree* window_tree = GetTreeWithId(window->id().client_id);
+ WindowTree* window_tree = GetTreeWithId(window->owning_tree_id());
if (window_tree)
window_tree->ProcessWindowSurfaceChanged(window, surface_info);
}
-bool WindowServer::GetFrameDecorationsForUser(
- const UserId& user_id,
+bool WindowServer::GetFrameDecorations(
mojom::FrameDecorationValuesPtr* values) {
- WindowManagerState* window_manager_state =
- window_manager_window_tree_factory_set_.GetWindowManagerStateForUser(
- user_id);
+ WindowManagerState* window_manager_state = GetWindowManagerState();
if (!window_manager_state)
return false;
if (values && window_manager_state->got_frame_decoration_values())
@@ -788,17 +759,12 @@ void WindowServer::UpdateNativeCursorIfOver(ServerWindow* window) {
event_dispatcher->UpdateNonClientAreaForCurrentWindow();
}
-bool WindowServer::IsUserInHighContrastMode(const UserId& user) const {
- const auto iter = high_contrast_mode_.find(user);
- return (iter == high_contrast_mode_.end()) ? false : iter->second;
-}
-
void WindowServer::HandleTemporaryReferenceForNewSurface(
const viz::SurfaceId& surface_id,
ServerWindow* window) {
DCHECK(host_frame_sink_manager_);
// TODO(kylechar): Investigate adding tests for this.
- const ClientSpecificId window_client_id = window->id().client_id;
+ const ClientSpecificId window_client_id = window->owning_tree_id();
// Find the root ServerWindow for the client that embeds |window|, which is
// the root of the client that embeds |surface_id|. The client that embeds
@@ -807,7 +773,7 @@ void WindowServer::HandleTemporaryReferenceForNewSurface(
// embedder, so the first ServerWindow with a different client id will be the
// root of the embedder.
ServerWindow* current = window->parent();
- while (current && current->id().client_id == window_client_id)
+ while (current && current->owning_tree_id() == window_client_id)
current = current->parent();
// The client that embeds |window| is expected to submit a CompositorFrame
@@ -836,8 +802,11 @@ void WindowServer::CreateFrameSinkManager() {
viz::mojom::FrameSinkManagerParamsPtr params =
viz::mojom::FrameSinkManagerParams::New();
params->restart_id = viz_restart_id_++;
- params->number_of_frames_to_activation_deadline =
+ base::Optional<uint32_t> activation_deadline_in_frames =
switches::GetDeadlineToSynchronizeSurfaces();
+ params->use_activation_deadline = activation_deadline_in_frames.has_value();
+ params->activation_deadline_in_frames =
+ activation_deadline_in_frames.value_or(0u);
params->frame_sink_manager = std::move(frame_sink_manager_request);
params->frame_sink_manager_client = frame_sink_manager_client.PassInterface();
gpu_host_->CreateFrameSinkManager(std::move(params));
@@ -1072,17 +1041,5 @@ void WindowServer::OnGpuServiceInitialized() {
delegate_->StartDisplayInit();
}
-void WindowServer::OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) {
-}
-
-void WindowServer::OnUserIdAdded(const UserId& id) {
- activity_monitor_map_[id] = std::make_unique<UserActivityMonitor>(nullptr);
-}
-
-void WindowServer::OnUserIdRemoved(const UserId& id) {
- activity_monitor_map_.erase(id);
-}
-
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/window_server.h b/chromium/services/ui/ws/window_server.h
index e4c291d0a1f..5004b7e2135 100644
--- a/chromium/services/ui/ws/window_server.h
+++ b/chromium/services/ui/ws/window_server.h
@@ -27,10 +27,7 @@
#include "services/ui/ws/server_window_observer.h"
#include "services/ui/ws/server_window_tracker.h"
#include "services/ui/ws/user_display_manager_delegate.h"
-#include "services/ui/ws/user_id_tracker.h"
-#include "services/ui/ws/user_id_tracker_observer.h"
#include "services/ui/ws/video_detector_impl.h"
-#include "services/ui/ws/window_manager_window_tree_factory_set.h"
namespace ui {
namespace ws {
@@ -44,6 +41,7 @@ class ThreadedImageCursorsFactory;
class UserActivityMonitor;
class WindowManagerDisplayRoot;
class WindowManagerState;
+class WindowManagerWindowTreeFactory;
class WindowServerDelegate;
class WindowTree;
class WindowTreeBinding;
@@ -55,17 +53,13 @@ enum class DisplayCreationConfig;
class WindowServer : public ServerWindowDelegate,
public ServerWindowObserver,
public GpuHostDelegate,
- public UserDisplayManagerDelegate,
- public UserIdTrackerObserver {
+ public UserDisplayManagerDelegate {
public:
WindowServer(WindowServerDelegate* delegate, bool should_host_viz);
~WindowServer() override;
WindowServerDelegate* delegate() { return delegate_; }
- UserIdTracker* user_id_tracker() { return &user_id_tracker_; }
- const UserIdTracker* user_id_tracker() const { return &user_id_tracker_; }
-
DisplayManager* display_manager() { return display_manager_.get(); }
const DisplayManager* display_manager() const {
return display_manager_.get();
@@ -86,7 +80,6 @@ class WindowServer : public ServerWindowDelegate,
// Creates a new ServerWindow. The return value is owned by the caller, but
// must be destroyed before WindowServer.
ServerWindow* CreateServerWindow(
- const WindowId& id,
const viz::FrameSinkId& frame_sink_id,
const std::map<std::string, std::vector<uint8_t>>& properties);
@@ -96,7 +89,6 @@ class WindowServer : public ServerWindowDelegate,
// See description of WindowTree::Embed() for details. This assumes
// |transport_window_id| is valid.
WindowTree* EmbedAtWindow(ServerWindow* root,
- const UserId& user_id,
mojom::WindowTreeClientPtr client,
uint32_t flags,
std::unique_ptr<AccessPolicy> access_policy);
@@ -107,7 +99,6 @@ class WindowServer : public ServerWindowDelegate,
std::unique_ptr<WindowTreeBinding> binding,
mojom::WindowTreePtr tree_ptr);
WindowTree* CreateTreeForWindowManager(
- const UserId& user_id,
mojom::WindowTreeRequest window_tree_request,
mojom::WindowTreeClientPtr window_tree_client,
bool automatically_create_display_roots);
@@ -121,9 +112,6 @@ class WindowServer : public ServerWindowDelegate,
size_t num_trees() const { return tree_map_.size(); }
- // Returns the Window identified by |id|.
- ServerWindow* GetWindow(const WindowId& id);
-
OperationType current_operation_type() const {
return current_operation_ ? current_operation_->type()
: OperationType::NONE;
@@ -149,11 +137,15 @@ class WindowServer : public ServerWindowDelegate,
}
const WindowTree* GetTreeWithRoot(const ServerWindow* window) const;
- UserActivityMonitor* GetUserActivityMonitorForUser(const UserId& user_id);
+ UserActivityMonitor* user_activity_monitor() {
+ return user_activity_monitor_.get();
+ }
- WindowManagerWindowTreeFactorySet* window_manager_window_tree_factory_set() {
- return &window_manager_window_tree_factory_set_;
+ WindowManagerWindowTreeFactory* window_manager_window_tree_factory() {
+ return window_manager_window_tree_factory_.get();
}
+ void BindWindowManagerWindowTreeFactory(
+ mojo::InterfaceRequest<mojom::WindowManagerWindowTreeFactory> request);
// Sets focus to |window|. Returns true if |window| already has focus, or
// focus was successfully changed. Returns |false| if |window| is not a valid
@@ -161,7 +153,7 @@ class WindowServer : public ServerWindowDelegate,
bool SetFocusedWindow(ServerWindow* window);
ServerWindow* GetFocusedWindow();
- void SetHighContrastMode(const UserId& user, bool enabled);
+ void SetHighContrastMode(bool enabled);
// Returns a change id for the window manager that is associated with
// |source| and |client_change_id|. When the window manager replies
@@ -212,11 +204,10 @@ class WindowServer : public ServerWindowDelegate,
void ProcessWillChangeWindowCursor(ServerWindow* window,
const ui::CursorData& cursor);
- // Sends an |event| to all WindowTrees belonging to |user_id| that might be
- // observing events. Skips |ignore_tree| if it is non-null. |target_window| is
- // the target of the event.
+ // Sends an |event| to all WindowTrees that might be observing events. Skips
+ // |ignore_tree| if it is non-null. |target_window| is the target of the
+ // event.
void SendToPointerWatchers(const ui::Event& event,
- const UserId& user_id,
ServerWindow* target_window,
WindowTree* ignore_tree,
int64_t display_id);
@@ -248,7 +239,7 @@ class WindowServer : public ServerWindowDelegate,
void OnDisplayReady(Display* display, bool is_first);
void OnDisplayDestroyed(Display* display);
void OnNoMoreDisplays();
- WindowManagerState* GetWindowManagerStateForUser(const UserId& user_id);
+ WindowManagerState* GetWindowManagerState();
VideoDetectorImpl* video_detector() { return &video_detector_; }
@@ -258,9 +249,7 @@ class WindowServer : public ServerWindowDelegate,
ServerWindow* window) override;
// UserDisplayManagerDelegate:
- bool GetFrameDecorationsForUser(
- const UserId& user_id,
- mojom::FrameDecorationValuesPtr* values) override;
+ bool GetFrameDecorations(mojom::FrameDecorationValuesPtr* values) override;
int64_t GetInternalDisplayId() override;
private:
@@ -270,8 +259,6 @@ class WindowServer : public ServerWindowDelegate,
using WindowTreeMap =
std::map<ClientSpecificId, std::unique_ptr<WindowTree>>;
- using UserActivityMonitorMap =
- std::map<UserId, std::unique_ptr<UserActivityMonitor>>;
struct InFlightWindowManagerChange {
// Identifies the client that initiated the change.
@@ -311,8 +298,6 @@ class WindowServer : public ServerWindowDelegate,
// |window|.
void UpdateNativeCursorIfOver(ServerWindow* window);
- bool IsUserInHighContrastMode(const UserId& user) const;
-
// Finds the parent client that will embed |surface_id| and claims ownership
// of the temporary reference. If no parent client is found then tell GPU to
// immediately drop the temporary reference. |window| is the ServerWindow
@@ -371,14 +356,6 @@ class WindowServer : public ServerWindowDelegate,
// GpuHostDelegate:
void OnGpuServiceInitialized() override;
- // UserIdTrackerObserver:
- void OnActiveUserIdChanged(const UserId& previously_active_id,
- const UserId& active_id) override;
- void OnUserIdAdded(const UserId& id) override;
- void OnUserIdRemoved(const UserId& id) override;
-
- UserIdTracker user_id_tracker_;
-
WindowServerDelegate* delegate_;
// ID to use for next WindowTree.
@@ -397,7 +374,7 @@ class WindowServer : public ServerWindowDelegate,
Operation* current_operation_;
bool in_destructor_;
- std::map<UserId, bool> high_contrast_mode_;
+ bool high_contrast_mode_ = false;
// Maps from window manager change id to the client that initiated the
// request.
@@ -409,9 +386,10 @@ class WindowServer : public ServerWindowDelegate,
std::unique_ptr<GpuHost> gpu_host_;
base::Callback<void(ServerWindow*)> window_paint_callback_;
- UserActivityMonitorMap activity_monitor_map_;
+ std::unique_ptr<UserActivityMonitor> user_activity_monitor_;
- WindowManagerWindowTreeFactorySet window_manager_window_tree_factory_set_;
+ std::unique_ptr<WindowManagerWindowTreeFactory>
+ window_manager_window_tree_factory_;
viz::SurfaceId root_surface_id_;
diff --git a/chromium/services/ui/ws/window_server_test_base.cc b/chromium/services/ui/ws/window_server_test_base.cc
index 39ee5072319..fc19a867879 100644
--- a/chromium/services/ui/ws/window_server_test_base.cc
+++ b/chromium/services/ui/ws/window_server_test_base.cc
@@ -16,6 +16,7 @@
#include "ui/aura/env.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_host_mus.h"
+#include "ui/base/ui_base_features.h"
#include "ui/base/ui_base_switches.h"
#include "ui/display/display.h"
#include "ui/display/display_list.h"
@@ -93,9 +94,7 @@ WindowServerTestBase::ReleaseMostRecentClient() {
}
void WindowServerTestBase::SetUp() {
- base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kMus);
- base::CommandLine::ForCurrentProcess()->AppendSwitch(
- switches::kMusHostingViz);
+ feature_list_.InitAndEnableFeature(features::kMash);
WindowServerServiceTestBase::SetUp();
env_ = aura::Env::CreateInstance(aura::Env::Mode::MUS);
diff --git a/chromium/services/ui/ws/window_server_test_base.h b/chromium/services/ui/ws/window_server_test_base.h
index fce9196f27f..df9450766e6 100644
--- a/chromium/services/ui/ws/window_server_test_base.h
+++ b/chromium/services/ui/ws/window_server_test_base.h
@@ -9,6 +9,7 @@
#include <set>
#include "base/macros.h"
+#include "base/test/scoped_feature_list.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "services/ui/ws/window_server_service_test_base.h"
@@ -141,6 +142,8 @@ class WindowServerTestBase : public WindowServerServiceTestBase,
// |window_tree_host| is not deleted.
bool DeleteWindowTreeHost(aura::WindowTreeHostMus* window_tree_host);
+ base::test::ScopedFeatureList feature_list_;
+
std::unique_ptr<aura::Env> env_;
::wm::WMState wm_state_;
display::ScreenBase screen_;
diff --git a/chromium/services/ui/ws/window_tree.cc b/chromium/services/ui/ws/window_tree.cc
index 99ff1367f05..a9d27094408 100644
--- a/chromium/services/ui/ws/window_tree.cc
+++ b/chromium/services/ui/ws/window_tree.cc
@@ -14,6 +14,7 @@
#include "base/memory/ptr_util.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/map.h"
+#include "services/ui/common/util.h"
#include "services/ui/display/screen_manager.h"
#include "services/ui/ws/cursor_location_manager.h"
#include "services/ui/ws/debug_utils.h"
@@ -124,13 +125,12 @@ struct WindowTree::DragMoveState {
};
WindowTree::WindowTree(WindowServer* window_server,
- const UserId& user_id,
+ bool is_for_embedding,
ServerWindow* root,
std::unique_ptr<AccessPolicy> access_policy)
: window_server_(window_server),
- user_id_(user_id),
+ is_for_embedding_(is_for_embedding),
id_(window_server_->GetAndAdvanceNextClientId()),
- next_window_id_(1),
access_policy_(std::move(access_policy)),
event_ack_id_(0),
window_manager_internal_(nullptr),
@@ -204,20 +204,12 @@ void WindowTree::ConfigureWindowManager(
window_manager_state_ = std::make_unique<WindowManagerState>(this);
}
-const ServerWindow* WindowTree::GetWindow(const WindowId& id) const {
- if (id_ == id.client_id) {
- auto iter = created_window_map_.find(id);
- return iter == created_window_map_.end() ? nullptr : iter->second;
- }
- return window_server_->GetWindow(id);
-}
-
bool WindowTree::IsWindowKnown(const ServerWindow* window,
ClientWindowId* id) const {
if (!window)
return false;
- auto iter = window_id_to_client_id_map_.find(window->id());
- if (iter == window_id_to_client_id_map_.end())
+ auto iter = window_to_client_id_map_.find(window);
+ if (iter == window_to_client_id_map_.end())
return false;
if (id)
*id = iter->second;
@@ -230,9 +222,8 @@ bool WindowTree::HasRoot(const ServerWindow* window) const {
const ServerWindow* WindowTree::GetWindowByClientId(
const ClientWindowId& id) const {
- auto iter = client_id_to_window_id_map_.find(id);
- return iter == client_id_to_window_id_map_.end() ? nullptr
- : GetWindow(iter->second);
+ auto iter = client_id_to_window_map_.find(id);
+ return iter == client_id_to_window_map_.end() ? nullptr : iter->second;
}
const Display* WindowTree::GetDisplay(const ServerWindow* window) const {
@@ -267,9 +258,7 @@ void WindowTree::AddRootForWindowManager(const ServerWindow* root) {
DCHECK(automatically_create_display_roots_);
DCHECK(window_manager_internal_);
const ClientWindowId client_window_id = root->frame_sink_id();
- DCHECK_EQ(0u, client_id_to_window_id_map_.count(client_window_id));
- client_id_to_window_id_map_[client_window_id] = root->id();
- window_id_to_client_id_map_[root->id()] = client_window_id;
+ AddToMaps(root, client_window_id);
roots_.insert(root);
Display* ws_display = GetDisplay(root);
@@ -286,7 +275,7 @@ void WindowTree::OnWindowDestroyingTreeImpl(WindowTree* tree) {
// Notify our client if |tree| was embedded in any of our windows.
for (const auto* tree_root : tree->roots_) {
- const bool owns_tree_root = tree_root->id().client_id == id_;
+ const bool owns_tree_root = tree_root->owning_tree_id() == id_;
if (owns_tree_root)
client()->OnEmbeddedAppDisconnected(TransportIdForWindow(tree_root));
}
@@ -349,19 +338,17 @@ ServerWindow* WindowTree::ProcessSetDisplayRoot(
// Create a display if the window manager is extending onto a new display.
display = display_manager()->AddDisplayForWindowManager(
is_primary_display, display_to_create, viewport_metrics);
- } else if (!display->GetWindowManagerDisplayRootForUser(
- window_manager_state_->user_id())) {
+ } else if (!display->window_manager_display_root()) {
// Init the root if the display already existed as a mirroring destination.
display->InitWindowManagerDisplayRoots();
}
if (!mirrors.empty())
- NOTIMPLEMENTED() << "TODO(crbug.com/764472): Mus unified mode support.";
+ NOTIMPLEMENTED() << "TODO(crbug.com/806318): Mus+Viz mirroring/unified";
DCHECK(display);
WindowManagerDisplayRoot* display_root =
- display->GetWindowManagerDisplayRootForUser(
- window_manager_state_->user_id());
+ display->window_manager_display_root();
DCHECK(display_root);
display_root->root()->RemoveAllChildren();
@@ -404,11 +391,9 @@ bool WindowTree::ProcessSwapDisplayRoots(int64_t display_id1,
}
WindowManagerDisplayRoot* display_root1 =
- display1->GetWindowManagerDisplayRootForUser(
- window_manager_state_->user_id());
+ display1->window_manager_display_root();
WindowManagerDisplayRoot* display_root2 =
- display2->GetWindowManagerDisplayRootForUser(
- window_manager_state_->user_id());
+ display2->window_manager_display_root();
if (!display_root1->GetClientVisibleRoot() ||
!display_root2->GetClientVisibleRoot()) {
@@ -460,7 +445,6 @@ bool WindowTree::SetCapture(const ClientWindowId& client_window_id) {
display_root ? display_root->window_manager_state()->capture_window()
: nullptr;
if (window && window->IsDrawn() && display_root &&
- display_root->window_manager_state()->IsActive() &&
access_policy_->CanSetCapture(window) &&
(!current_capture_window ||
access_policy_->CanSetCapture(current_capture_window))) {
@@ -477,7 +461,6 @@ bool WindowTree::ReleaseCapture(const ClientWindowId& client_window_id) {
display_root ? display_root->window_manager_state()->capture_window()
: nullptr;
if (!window || !display_root ||
- !display_root->window_manager_state()->IsActive() ||
(current_capture_window &&
!access_policy_->CanSetCapture(current_capture_window)) ||
window != current_capture_window) {
@@ -498,13 +481,11 @@ bool WindowTree::NewWindow(
return false;
}
DCHECK(!GetWindowByClientId(client_window_id));
- const WindowId window_id = GenerateNewWindowId();
- DCHECK(!GetWindow(window_id));
- ServerWindow* window = window_server_->CreateServerWindow(
- window_id, client_window_id, properties);
- created_window_map_[window_id] = window;
- client_id_to_window_id_map_[client_window_id] = window_id;
- window_id_to_client_id_map_[window_id] = client_window_id;
+ DCHECK_EQ(id_, client_window_id.client_id());
+ ServerWindow* window =
+ window_server_->CreateServerWindow(client_window_id, properties);
+ created_windows_.insert(window);
+ AddToMaps(window, client_window_id);
return true;
}
@@ -575,7 +556,7 @@ bool WindowTree::DeleteWindow(const ClientWindowId& window_id) {
}
// Have the owner of the tree service the actual delete.
- WindowTree* tree = window_server_->GetTreeWithId(window->id().client_id);
+ WindowTree* tree = window_server_->GetTreeWithId(window->owning_tree_id());
return tree && tree->DeleteWindowImpl(this, window);
}
@@ -587,8 +568,8 @@ bool WindowTree::SetModalType(const ClientWindowId& window_id,
return false;
}
- if (user_id_ == InvalidUserId() && modal_type == MODAL_TYPE_SYSTEM) {
- DVLOG(1) << "SetModalType failed (invalid user id)";
+ if (is_for_embedding_ && modal_type == MODAL_TYPE_SYSTEM) {
+ DVLOG(1) << "SetModalType failed (not allowed for embedded clients)";
return false;
}
@@ -715,10 +696,7 @@ bool WindowTree::Embed(const ClientWindowId& window_id,
// embedder could effectively circumvent it by embedding itself.
if (embedder_intercepts_events_)
flags = mojom::kEmbedFlagEmbedderInterceptsEvents;
- // When embedding we don't know the user id of where the TreeClient came
- // from. Use an invalid id, which limits what the client is able to do.
- window_server_->EmbedAtWindow(window, InvalidUserId(),
- std::move(window_tree_client), flags,
+ window_server_->EmbedAtWindow(window, std::move(window_tree_client), flags,
base::WrapUnique(new DefaultAccessPolicy));
client()->OnFrameSinkIdAllocated(ClientWindowIdToTransportId(window_id),
window->frame_sink_id());
@@ -771,10 +749,7 @@ viz::FrameSinkId WindowTree::OnWindowManagerCreatedTopLevelWindow(
client()->OnChangeCompleted(client_change_id, false);
return viz::FrameSinkId();
}
- client_id_to_window_id_map_[waiting_for_top_level_window_info
- ->client_window_id] = window->id();
- window_id_to_client_id_map_[window->id()] =
- waiting_for_top_level_window_info->client_window_id;
+ AddToMaps(window, waiting_for_top_level_window_info->client_window_id);
roots_.insert(window);
Display* display = GetDisplay(window);
int64_t display_id = display ? display->GetId() : display::kInvalidDisplayId;
@@ -819,7 +794,7 @@ void WindowTree::OnEventOccurredOutsideOfModalWindow(
const ServerWindow* modal_window) {
DCHECK(window_manager_internal_);
// Only tell the window manager about windows it created.
- if (modal_window->id().client_id != id_)
+ if (modal_window->owning_tree_id() != id_)
return;
ClientWindowId client_window_id;
@@ -990,8 +965,7 @@ void WindowTree::ProcessWindowReorder(const ServerWindow* window,
void WindowTree::ProcessWindowDeleted(ServerWindow* window,
bool originated_change) {
- if (window->id().client_id == id_)
- created_window_map_.erase(window->id());
+ created_windows_.erase(window);
ClientWindowId client_window_id;
if (!IsWindowKnown(window, &client_window_id))
@@ -1139,9 +1113,8 @@ Id WindowTree::ClientWindowIdToTransportId(
const ClientWindowId& client_window_id) const {
if (client_window_id.client_id() == id_)
return client_window_id.sink_id();
- return (base::checked_cast<ClientSpecificId>(client_window_id.client_id())
- << 16) |
- base::checked_cast<ClientSpecificId>(client_window_id.sink_id());
+ const Id client_id = client_window_id.client_id();
+ return (client_id << 32) | client_window_id.sink_id();
}
bool WindowTree::ShouldRouteToWindowManager(const ServerWindow* window) const {
@@ -1149,7 +1122,7 @@ bool WindowTree::ShouldRouteToWindowManager(const ServerWindow* window) const {
return false; // We are the window manager, don't route to ourself.
// If the client created this window, then do not route it through the WM.
- if (window->id().client_id == id_)
+ if (window->owning_tree_id() == id_)
return false;
// If the client did not create the window, then it must be the root of the
@@ -1186,22 +1159,17 @@ void WindowTree::ProcessCaptureChanged(const ServerWindow* new_capture,
}
Id WindowTree::TransportIdForWindow(const ServerWindow* window) const {
- auto iter = window_id_to_client_id_map_.find(window->id());
- DCHECK(iter != window_id_to_client_id_map_.end());
+ auto iter = window_to_client_id_map_.find(window);
+ DCHECK(iter != window_to_client_id_map_.end());
return ClientWindowIdToTransportId(iter->second);
}
bool WindowTree::IsValidIdForNewWindow(const ClientWindowId& id) const {
// Reserve 0 to indicate a null window.
- return client_id_to_window_id_map_.count(id) == 0u &&
+ return client_id_to_window_map_.count(id) == 0u &&
access_policy_->IsValidIdForNewWindow(id) && id != ClientWindowId();
}
-WindowId WindowTree::GenerateNewWindowId() {
- // TODO(sky): deal with wrapping and uniqueness.
- return WindowId(id_, next_window_id_++);
-}
-
bool WindowTree::CanReorderWindow(const ServerWindow* window,
const ServerWindow* relative_window,
mojom::OrderDirection direction) const {
@@ -1272,7 +1240,7 @@ bool WindowTree::RemoveWindowFromParent(
bool WindowTree::DeleteWindowImpl(WindowTree* source, ServerWindow* window) {
DCHECK(window);
- DCHECK_EQ(window->id().client_id, id_);
+ DCHECK_EQ(window->owning_tree_id(), id_);
Operation op(source, window_server_, OperationType::DELETE_WINDOW);
delete window;
return true;
@@ -1292,9 +1260,7 @@ void WindowTree::GetUnknownWindowsFrom(
return;
const ClientWindowId client_window_id = window->frame_sink_id();
- DCHECK_EQ(0u, client_id_to_window_id_map_.count(client_window_id));
- client_id_to_window_id_map_[client_window_id] = window->id();
- window_id_to_client_id_map_[window->id()] = client_window_id;
+ AddToMaps(window, client_window_id);
if (!access_policy_->CanDescendIntoWindowForWindowTree(window))
return;
const ServerWindow::Windows& children = window->children();
@@ -1302,36 +1268,43 @@ void WindowTree::GetUnknownWindowsFrom(
GetUnknownWindowsFrom(child, windows);
}
+void WindowTree::AddToMaps(const ServerWindow* window,
+ const ClientWindowId& client_window_id) {
+ DCHECK_EQ(0u, client_id_to_window_map_.count(client_window_id));
+ client_id_to_window_map_[client_window_id] = window;
+ window_to_client_id_map_[window] = client_window_id;
+}
+
bool WindowTree::RemoveFromMaps(const ServerWindow* window) {
- auto iter = window_id_to_client_id_map_.find(window->id());
- if (iter == window_id_to_client_id_map_.end())
+ auto iter = window_to_client_id_map_.find(window);
+ if (iter == window_to_client_id_map_.end())
return false;
- client_id_to_window_id_map_.erase(iter->second);
- window_id_to_client_id_map_.erase(iter);
+ client_id_to_window_map_.erase(iter->second);
+ window_to_client_id_map_.erase(iter);
return true;
}
void WindowTree::RemoveFromKnown(const ServerWindow* window,
- std::vector<ServerWindow*>* local_windows) {
- if (window->id().client_id == id_) {
- if (local_windows)
- local_windows->push_back(GetWindow(window->id()));
+ std::vector<ServerWindow*>* created_windows) {
+ // TODO(sky): const_cast here is a bit ick.
+ if (created_windows_.count(const_cast<ServerWindow*>(window))) {
+ if (created_windows)
+ created_windows->push_back(const_cast<ServerWindow*>(window));
return;
}
RemoveFromMaps(window);
- const ServerWindow::Windows& children = window->children();
- for (ServerWindow* child : children)
- RemoveFromKnown(child, local_windows);
+ for (ServerWindow* child : window->children())
+ RemoveFromKnown(child, created_windows);
}
void WindowTree::RemoveRoot(ServerWindow* window, RemoveRootReason reason) {
DCHECK(roots_.count(window) > 0);
roots_.erase(window);
- if (window->id().client_id == id_) {
+ if (window->owning_tree_id() == id_) {
// This client created the window. If this client is the window manager and
// display roots are manually created, then |window| is a display root and
// needs be cleaned.
@@ -1351,19 +1324,19 @@ void WindowTree::RemoveRoot(ServerWindow* window, RemoveRootReason reason) {
window_server_->OnTreeMessagedClient(id_);
}
- // This client no longer knows about the window. Unparent any windows that
- // were parented to windows in the root.
- std::vector<ServerWindow*> local_windows;
- RemoveFromKnown(window, &local_windows);
- for (size_t i = 0; i < local_windows.size(); ++i)
- local_windows[i]->parent()->Remove(local_windows[i]);
+ // This client no longer knows about |window|. Unparent any windows created
+ // by this client that were parented to descendants of |window|.
+ std::vector<ServerWindow*> created_windows;
+ RemoveFromKnown(window, &created_windows);
+ for (ServerWindow* created_window : created_windows)
+ created_window->parent()->Remove(created_window);
if (reason == RemoveRootReason::UNEMBED) {
// Notify the owner of the window it no longer has a client embedded in it.
// Owner is null in the case of the windowmanager unembedding itself from
// a root.
WindowTree* owning_tree =
- window_server_->GetTreeWithId(window->id().client_id);
+ window_server_->GetTreeWithId(window->owning_tree_id());
if (owning_tree) {
DCHECK(owning_tree && owning_tree != this);
owning_tree->client()->OnEmbeddedAppDisconnected(
@@ -1441,26 +1414,25 @@ void WindowTree::NotifyDrawnStateChanged(const ServerWindow* window,
}
void WindowTree::DestroyWindows() {
- if (created_window_map_.empty())
+ if (created_windows_.empty())
return;
Operation op(this, window_server_, OperationType::DELETE_WINDOW);
// If we get here from the destructor we're not going to get
// ProcessWindowDeleted(). Copy the map and delete from the copy so that we
- // don't have to worry about whether |created_window_map_| changes or not.
- std::unordered_map<WindowId, ServerWindow*, WindowIdHash>
- created_window_map_copy;
- created_window_map_.swap(created_window_map_copy);
+ // don't have to worry about whether |created_windows_| changes or not.
+ std::set<ServerWindow*> created_windows_copy;
+ created_windows_.swap(created_windows_copy);
// A sibling can be a transient parent of another window so we detach windows
// from their transient parents to avoid double deletes.
- for (auto& pair : created_window_map_copy) {
- ServerWindow* transient_parent = pair.second->transient_parent();
+ for (ServerWindow* window : created_windows_copy) {
+ ServerWindow* transient_parent = window->transient_parent();
if (transient_parent)
- transient_parent->RemoveTransientWindow(pair.second);
+ transient_parent->RemoveTransientWindow(window);
}
- for (auto& window_pair : created_window_map_copy)
- delete window_pair.second;
+ for (ServerWindow* window : created_windows_copy)
+ delete window;
}
bool WindowTree::CanEmbed(const ClientWindowId& window_id) const {
@@ -1520,8 +1492,7 @@ void WindowTree::DispatchInputEventImpl(ServerWindow* target,
event_location.display_id);
WindowManagerDisplayRoot* event_display_root = nullptr;
if (display && window_manager_state_) {
- event_display_root = display->GetWindowManagerDisplayRootForUser(
- window_manager_state_->user_id());
+ event_display_root = display->window_manager_display_root();
}
ServerWindow* display_root_window =
event_display_root ? event_display_root->GetClientVisibleRoot() : nullptr;
@@ -1546,10 +1517,12 @@ bool WindowTree::EventMatchesPointerWatcher(const ui::Event& event) const {
}
ClientWindowId WindowTree::MakeClientWindowId(Id transport_window_id) const {
- if (!HiWord(transport_window_id))
+ // If the client didn't specify the id portion of the window_id use the id of
+ // the client.
+ if (!ClientIdFromTransportId(transport_window_id))
return ClientWindowId(id_, transport_window_id);
- return ClientWindowId(HiWord(transport_window_id),
- LoWord(transport_window_id));
+ return ClientWindowId(ClientIdFromTransportId(transport_window_id),
+ ClientWindowIdFromTransportId(transport_window_id));
}
mojom::WindowTreeClientPtr
@@ -1572,7 +1545,8 @@ WindowTree::GetAndRemoveScheduledEmbedWindowTreeClient(
if (roots_.size() != 1)
return nullptr;
const ServerWindow* root = *roots_.begin();
- WindowTree* owning_tree = window_server_->GetTreeWithId(root->id().client_id);
+ WindowTree* owning_tree =
+ window_server_->GetTreeWithId(root->owning_tree_id());
if (!owning_tree)
return nullptr;
DCHECK_NE(this, owning_tree);
@@ -1609,9 +1583,8 @@ void WindowTree::NewTopLevelWindow(
: *(display_manager()->displays().begin());
// TODO(sky): move checks to accesspolicy.
WindowManagerDisplayRoot* display_root =
- display && user_id_ != InvalidUserId()
- ? display->GetWindowManagerDisplayRootForUser(user_id_)
- : nullptr;
+ display && !is_for_embedding_ ? display->window_manager_display_root()
+ : nullptr;
if (!display_root ||
display_root->window_manager_state()->window_tree() == this ||
!IsValidIdForNewWindow(client_window_id)) {
@@ -1942,6 +1915,14 @@ void WindowTree::OnWindowInputEventAck(uint32_t event_id,
if (GetDisplay(target)) {
DispatchInputEventImpl(target, *event, event_location,
std::move(callback));
+ } else {
+ // If the window is no longer valid (or not in a display), then there is
+ // no point in dispatching to the client, but we need to run the callback
+ // so that WindowManagerState isn't still waiting for an ack. We only
+ // need run the last callback as they should all target the same
+ // WindowManagerState and WindowManagerState is at most waiting on one
+ // ack.
+ std::move(callback).Run(mojom::EventResult::UNHANDLED);
}
}
}
@@ -2270,9 +2251,8 @@ void WindowTree::GetWindowManagerClient(
void WindowTree::GetCursorLocationMemory(
const GetCursorLocationMemoryCallback& callback) {
- callback.Run(display_manager()
- ->GetCursorLocationManager(user_id_)
- ->GetCursorLocationMemory());
+ callback.Run(
+ display_manager()->cursor_location_manager()->GetCursorLocationMemory());
}
void WindowTree::PerformDragDrop(
@@ -2479,7 +2459,7 @@ void WindowTree::SetExtendedHitRegionForChildren(
DVLOG(1) << "SetExtendedHitRegionForChildren failed (invalid window id)";
return;
}
- if (window->id().client_id != id_) {
+ if (window->owning_tree_id() != id_) {
DVLOG(1) << "SetExtendedHitRegionForChildren failed (supplied window that "
<< "client does not own)";
return;
@@ -2550,7 +2530,7 @@ void WindowTree::WmResponse(uint32_t change_id, bool response) {
window_server_->GetCurrentMoveLoopChangeId() == change_id) {
ServerWindow* window = window_server_->GetCurrentMoveLoopWindow();
- if (window->id().client_id != id_) {
+ if (window->owning_tree_id() != id_) {
window_server_->WindowManagerSentBogusMessage();
window = nullptr;
} else {
@@ -2599,8 +2579,7 @@ void WindowTree::WmSetFrameDecorationValues(
window_manager_state_->SetFrameDecorationValues(std::move(values));
}
-void WindowTree::WmSetNonClientCursor(uint32_t window_id,
- ui::CursorData cursor) {
+void WindowTree::WmSetNonClientCursor(Id window_id, ui::CursorData cursor) {
DCHECK(window_manager_state_);
ServerWindow* window = GetWindowByClientId(MakeClientWindowId(window_id));
if (!window) {
@@ -2670,7 +2649,7 @@ void WindowTree::OnWmCreatedTopLevelWindow(uint32_t change_id,
Id transport_window_id) {
ServerWindow* window =
GetWindowByClientId(MakeClientWindowId(transport_window_id));
- if (window && window->id().client_id != id_) {
+ if (window && window->owning_tree_id() != id_) {
DVLOG(1) << "OnWmCreatedTopLevelWindow failed (invalid window id)";
window_server_->WindowManagerSentBogusMessage();
window = nullptr;
@@ -2718,19 +2697,18 @@ bool WindowTree::IsWindowCreatedByWindowManager(
return false;
return display_root->window_manager_state()->window_tree()->id() ==
- window->id().client_id;
+ window->owning_tree_id();
}
bool WindowTree::ShouldInterceptEventsForAccessPolicy(
const ServerWindow* window) const {
- // Indicates the tree was created as the result of an Embed().
- if (user_id_.empty())
+ if (is_for_embedding_)
return false;
while (window) {
// Find the first window created by this client. If there is an embedding,
// it'll be here.
- if (window->id().client_id == id_) {
+ if (window->owning_tree_id() == id_) {
// embedded_tree->embedder_intercepts_events() indicates Embed() was
// called with kEmbedFlagEmbedderInterceptsEvents. In this case the
// embedder needs to see the window so that it knows the event is
@@ -2787,10 +2765,6 @@ void WindowTree::OnDragCompleted(bool success, uint32_t action_taken) {
client()->OnPerformDragDropCompleted(change_id, success, action_taken);
}
-ServerWindow* WindowTree::GetWindowById(const WindowId& id) {
- return GetWindow(id);
-}
-
DragTargetConnection* WindowTree::GetDragTargetForWindow(
const ServerWindow* window) {
if (!window)
@@ -2798,7 +2772,7 @@ DragTargetConnection* WindowTree::GetDragTargetForWindow(
DragTargetConnection* connection = window_server_->GetTreeWithRoot(window);
if (connection)
return connection;
- return window_server_->GetTreeWithId(window->id().client_id);
+ return window_server_->GetTreeWithId(window->owning_tree_id());
}
void WindowTree::PerformOnDragDropStart(
diff --git a/chromium/services/ui/ws/window_tree.h b/chromium/services/ui/ws/window_tree.h
index fe3a1d647f8..fb9cb611952 100644
--- a/chromium/services/ui/ws/window_tree.h
+++ b/chromium/services/ui/ws/window_tree.h
@@ -25,7 +25,6 @@
#include "services/ui/ws/drag_source.h"
#include "services/ui/ws/drag_target_connection.h"
#include "services/ui/ws/ids.h"
-#include "services/ui/ws/user_id.h"
#include "services/ui/ws/window_tree_binding.h"
#include "services/viz/public/interfaces/compositing/surface_id.mojom.h"
#include "ui/gfx/native_widget_types.h"
@@ -77,7 +76,7 @@ class WindowTree : public mojom::WindowTree,
public DragTargetConnection {
public:
WindowTree(WindowServer* window_server,
- const UserId& user_id,
+ bool is_for_embedding,
ServerWindow* root,
std::unique_ptr<AccessPolicy> access_policy);
~WindowTree() override;
@@ -106,17 +105,10 @@ class WindowTree : public mojom::WindowTree,
can_change_root_window_visibility_ = value;
}
- const UserId& user_id() const { return user_id_; }
+ bool is_for_embedding() const { return is_for_embedding_; }
mojom::WindowTreeClient* client() { return binding_->client(); }
- // Returns the Window with the specified id.
- ServerWindow* GetWindow(const WindowId& id) {
- return const_cast<ServerWindow*>(
- const_cast<const WindowTree*>(this)->GetWindow(id));
- }
- const ServerWindow* GetWindow(const WindowId& id) const;
-
// Returns the Window with the specified client id *only* if known to this
// client, returns null if not known.
ServerWindow* GetWindowByClientId(const ClientWindowId& id) {
@@ -350,8 +342,6 @@ class WindowTree : public mojom::WindowTree,
// Returns true if |id| is a valid WindowId for a new window.
bool IsValidIdForNewWindow(const ClientWindowId& id) const;
- WindowId GenerateNewWindowId();
-
// These functions return true if the corresponding mojom function is allowed
// for this tree.
bool CanReorderWindow(const ServerWindow* window,
@@ -367,15 +357,18 @@ class WindowTree : public mojom::WindowTree,
void GetUnknownWindowsFrom(const ServerWindow* window,
std::vector<const ServerWindow*>* windows);
+ void AddToMaps(const ServerWindow* window,
+ const ClientWindowId& client_window_id);
+
// Removes |window| from the appropriate maps. If |window| is known to this
// client true is returned.
bool RemoveFromMaps(const ServerWindow* window);
// Removes |window| and all its descendants from the necessary maps. This
// does not recurse through windows that were created by this tree. All
- // windows owned by this tree are added to |local_windows|.
+ // windows created by this tree are added to |created_windows|.
void RemoveFromKnown(const ServerWindow* window,
- std::vector<ServerWindow*>* local_windows);
+ std::vector<ServerWindow*>* created_windows);
// Removes a root from set of roots of this tree. This does not remove
// the window from the window tree, only from the set of roots.
@@ -603,7 +596,7 @@ class WindowTree : public mojom::WindowTree,
void WmRequestClose(Id transport_window_id) override;
void WmSetFrameDecorationValues(
mojom::FrameDecorationValuesPtr values) override;
- void WmSetNonClientCursor(uint32_t window_id, ui::CursorData cursor) override;
+ void WmSetNonClientCursor(Id window_id, ui::CursorData cursor) override;
void WmLockCursor() override;
void WmUnlockCursor() override;
void WmSetCursorVisible(bool visible) override;
@@ -636,7 +629,6 @@ class WindowTree : public mojom::WindowTree,
// DragSource:
void OnDragMoved(const gfx::Point& location) override;
void OnDragCompleted(bool success, uint32_t action_taken) override;
- ServerWindow* GetWindowById(const WindowId& id) override;
DragTargetConnection* GetDragTargetForWindow(
const ServerWindow* window) override;
@@ -667,14 +659,13 @@ class WindowTree : public mojom::WindowTree,
WindowServer* window_server_;
- UserId user_id_;
+ // True if this WindowTree was created by way of Embed().
+ bool is_for_embedding_;
// Id of this tree as assigned by WindowServer.
const ClientSpecificId id_;
std::string name_;
- ClientSpecificId next_window_id_;
-
std::unique_ptr<WindowTreeBinding> binding_;
std::unique_ptr<ui::ws::AccessPolicy> access_policy_;
@@ -684,15 +675,13 @@ class WindowTree : public mojom::WindowTree,
std::set<const ServerWindow*> roots_;
// The windows created by this tree. This tree owns these objects.
- std::unordered_map<WindowId, ServerWindow*, WindowIdHash> created_window_map_;
-
- // The client is allowed to assign ids. These two maps providing the mapping
- // from the ids native to the server (WindowId) to those understood by the
- // client (ClientWindowId).
- std::unordered_map<ClientWindowId, WindowId, ClientWindowIdHash>
- client_id_to_window_id_map_;
- std::unordered_map<WindowId, ClientWindowId, WindowIdHash>
- window_id_to_client_id_map_;
+ std::set<ServerWindow*> created_windows_;
+
+ // The client is allowed to assign ids.
+ std::unordered_map<ClientWindowId, const ServerWindow*, ClientWindowIdHash>
+ client_id_to_window_map_;
+ std::unordered_map<const ServerWindow*, ClientWindowId>
+ window_to_client_id_map_;
// Id passed to the client and expected to be supplied back to
// OnWindowInputEventAck() or OnAcceleratorAck().
diff --git a/chromium/services/ui/ws/window_tree_client_unittest.cc b/chromium/services/ui/ws/window_tree_client_unittest.cc
index 25446266157..7aa07941a90 100644
--- a/chromium/services/ui/ws/window_tree_client_unittest.cc
+++ b/chromium/services/ui/ws/window_tree_client_unittest.cc
@@ -16,6 +16,7 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service_test.h"
+#include "services/ui/common/util.h"
#include "services/ui/public/interfaces/constants.mojom.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "services/ui/public/interfaces/window_tree_host_factory.mojom.h"
@@ -39,7 +40,8 @@ namespace {
// Creates an id used for transport from the specified parameters.
Id BuildWindowId(ClientSpecificId client_id,
ClientSpecificId window_id) {
- return (client_id << 16) | window_id;
+ const Id tmp = client_id;
+ return (tmp << 32) | window_id;
}
// Callback function from WindowTree functions.
@@ -131,8 +133,10 @@ void GetWindowTree(WindowTree* tree,
const Id kNullParentId = 0;
std::string IdToString(Id id) {
- return (id == kNullParentId) ? "null" : base::StringPrintf(
- "%d,%d", HiWord(id), LoWord(id));
+ return (id == kNullParentId)
+ ? "null"
+ : base::StringPrintf("%d,%d", ClientIdFromTransportId(id),
+ ClientWindowIdFromTransportId(id));
}
std::string WindowParentToString(Id window, Id parent) {
@@ -349,15 +353,13 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
tracker()->OnWindowTransformChanged(window_id);
}
void OnClientAreaChanged(
- uint32_t window_id,
+ Id window_id,
const gfx::Insets& new_client_area,
const std::vector<gfx::Rect>& new_additional_client_areas) override {}
- void OnTransientWindowAdded(uint32_t window_id,
- uint32_t transient_window_id) override {
+ void OnTransientWindowAdded(Id window_id, Id transient_window_id) override {
tracker()->OnTransientWindowAdded(window_id, transient_window_id);
}
- void OnTransientWindowRemoved(uint32_t window_id,
- uint32_t transient_window_id) override {
+ void OnTransientWindowRemoved(Id window_id, Id transient_window_id) override {
tracker()->OnTransientWindowRemoved(window_id, transient_window_id);
}
void OnWindowHierarchyChanged(Id window,
@@ -375,15 +377,15 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
void OnWindowDeleted(Id window) override {
tracker()->OnWindowDeleted(window);
}
- void OnWindowVisibilityChanged(uint32_t window, bool visible) override {
+ void OnWindowVisibilityChanged(Id window, bool visible) override {
tracker()->OnWindowVisibilityChanged(window, visible);
}
- void OnWindowOpacityChanged(uint32_t window,
+ void OnWindowOpacityChanged(Id window,
float old_opacity,
float new_opacity) override {
tracker()->OnWindowOpacityChanged(window, new_opacity);
}
- void OnWindowParentDrawnStateChanged(uint32_t window, bool drawn) override {
+ void OnWindowParentDrawnStateChanged(Id window, bool drawn) override {
tracker()->OnWindowParentDrawnStateChanged(window, drawn);
}
void OnWindowInputEvent(
@@ -402,18 +404,17 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
// may come in at random points.
}
void OnPointerEventObserved(std::unique_ptr<ui::Event>,
- uint32_t window_id,
+ Id window_id,
int64_t display_id) override {}
void OnWindowSharedPropertyChanged(
- uint32_t window,
+ Id window,
const std::string& name,
const base::Optional<std::vector<uint8_t>>& new_data) override {
tracker_.OnWindowSharedPropertyChanged(window, name, new_data);
}
// TODO(sky): add testing coverage.
- void OnWindowFocused(uint32_t focused_window_id) override {}
- void OnWindowCursorChanged(uint32_t window_id,
- ui::CursorData cursor) override {
+ void OnWindowFocused(Id focused_window_id) override {}
+ void OnWindowCursorChanged(Id window_id, ui::CursorData cursor) override {
tracker_.OnWindowCursorChanged(window_id, cursor);
}
@@ -428,22 +429,22 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
tracker_.OnWindowSurfaceChanged(window_id, surface_info);
}
- void OnDragEnter(uint32_t window,
+ void OnDragEnter(Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
const OnDragEnterCallback& callback) override {
NOTIMPLEMENTED();
}
- void OnDragOver(uint32_t window,
+ void OnDragOver(Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
const OnDragOverCallback& callback) override {
NOTIMPLEMENTED();
}
- void OnDragLeave(uint32_t window) override { NOTIMPLEMENTED(); }
- void OnCompleteDrop(uint32_t window,
+ void OnDragLeave(Id window) override { NOTIMPLEMENTED(); }
+ void OnCompleteDrop(Id window,
uint32_t key_state,
const gfx::Point& position,
uint32_t effect_bitmask,
@@ -451,7 +452,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
NOTIMPLEMENTED();
}
- void OnPerformDragDropCompleted(uint32_t window,
+ void OnPerformDragDropCompleted(uint32_t change_id,
bool success,
uint32_t action_taken) override {
NOTIMPLEMENTED();
@@ -465,7 +466,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
change_completed_run_loop_->Quit();
}
}
- void RequestClose(uint32_t window_id) override {}
+ void RequestClose(Id window_id) override {}
void GetWindowManager(mojo::AssociatedInterfaceRequest<mojom::WindowManager>
internal) override {
window_manager_binding_ =
@@ -491,19 +492,19 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
NOTIMPLEMENTED();
}
void WmSetBounds(uint32_t change_id,
- uint32_t window_id,
+ Id window_id,
const gfx::Rect& bounds) override {
window_manager_client_->WmResponse(change_id, false);
}
void WmSetProperty(
uint32_t change_id,
- uint32_t window_id,
+ Id window_id,
const std::string& name,
const base::Optional<std::vector<uint8_t>>& value) override {
window_manager_client_->WmResponse(change_id, false);
}
- void WmSetModalType(uint32_t window_id, ui::ModalType type) override {}
- void WmSetCanFocus(uint32_t window_id, bool can_focus) override {}
+ void WmSetModalType(Id window_id, ui::ModalType type) override {}
+ void WmSetCanFocus(Id window_id, bool can_focus) override {}
void WmCreateTopLevelWindow(
uint32_t change_id,
const viz::FrameSinkId& frame_sink_id,
@@ -525,22 +526,20 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
}
void WmDestroyDragImage() override {}
void WmPerformMoveLoop(uint32_t change_id,
- uint32_t window_id,
+ Id window_id,
mojom::MoveLoopSource source,
const gfx::Point& cursor_location) override {
NOTIMPLEMENTED();
}
- void WmCancelMoveLoop(uint32_t window_id) override { NOTIMPLEMENTED(); }
- void WmDeactivateWindow(uint32_t window_id) override { NOTIMPLEMENTED(); }
- void WmStackAbove(uint32_t change_id, uint32_t above_id,
- uint32_t below_id) override {
+ void WmCancelMoveLoop(uint32_t change_id) override { NOTIMPLEMENTED(); }
+ void WmDeactivateWindow(Id window_id) override { NOTIMPLEMENTED(); }
+ void WmStackAbove(uint32_t change_id, Id above_id, Id below_id) override {
NOTIMPLEMENTED();
}
- void WmStackAtTop(uint32_t change_id, uint32_t window_id) override {
+ void WmStackAtTop(uint32_t change_id, Id window_id) override {
NOTIMPLEMENTED();
}
- void WmPerformWmAction(uint32_t window_id,
- const std::string& action) override {
+ void WmPerformWmAction(Id window_id, const std::string& action) override {
NOTIMPLEMENTED();
}
void OnAccelerator(uint32_t ack_id,
@@ -549,9 +548,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
NOTIMPLEMENTED();
}
void OnCursorTouchVisibleChanged(bool enabled) override { NOTIMPLEMENTED(); }
- void OnEventBlockedByModalWindow(uint32_t window_id) override {
- NOTIMPLEMENTED();
- }
+ void OnEventBlockedByModalWindow(Id window_id) override { NOTIMPLEMENTED(); }
TestChangeTracker tracker_;
@@ -662,12 +659,14 @@ class WindowTreeClientTest : public WindowServerServiceTestBase {
if (create_initial_window) {
// window_1_1 is created by wt_client1() so its client_id part should be
// client_id_1() in wt_client2.
- EXPECT_EQ("[" +
- WindowParentToString(
- BuildWindowId(client_id_1(), LoWord(window_1_1)),
- kNullParentId) +
- "]",
- ChangeWindowDescription(*changes2()));
+ EXPECT_EQ(
+ "[" +
+ WindowParentToString(
+ BuildWindowId(client_id_1(),
+ ClientWindowIdFromTransportId(window_1_1)),
+ kNullParentId) +
+ "]",
+ ChangeWindowDescription(*changes2()));
}
}
@@ -796,7 +795,8 @@ TEST_F(WindowTreeClientTest, WindowsRemovedWhenEmbedding) {
ASSERT_EQ(1u, changes2()->size());
ASSERT_EQ(1u, (*changes2())[0].windows.size());
// window_1_1 has a client_id part of client_id_1 in wt2.
- Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ Id window11_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_1));
EXPECT_EQ("[" + WindowParentToString(window11_in_wt2, kNullParentId) + "]",
ChangeWindowDescription(*changes2()));
@@ -891,7 +891,8 @@ TEST_F(WindowTreeClientTest, CantAccessChildrenOfEmbeddedWindow) {
GetWindowTree(wt1(), window_1_1, &windows);
ASSERT_EQ(3u, windows.size());
// window_1_1 is created by wt1() so client_id part would be 0 in wt1().
- EXPECT_EQ(WindowParentToString(LoWord(window_1_1), kNullParentId),
+ EXPECT_EQ(WindowParentToString(ClientWindowIdFromTransportId(window_1_1),
+ kNullParentId),
windows[0].ToString());
// NOTE: we expect a match of WindowParentToString(window_2_2, window_1_1),
// but the ids are in the id space of client2, which is not the same as
@@ -927,11 +928,12 @@ TEST_F(WindowTreeClientTest, CantModifyChildrenOfEmbeddedWindow) {
ASSERT_TRUE(window_3_1);
// window_2_1 should have a client_id of client_id_2 in wt_client3.
ASSERT_TRUE(wt_client3()->AddWindow(
- BuildWindowId(client_id_2(), LoWord(window_2_1)), window_3_1));
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_1)),
+ window_3_1));
// Client 2 shouldn't be able to remove window 3.
ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(
- BuildWindowId(client_id_3(), LoWord(window_3_1))));
+ BuildWindowId(client_id_3(), ClientWindowIdFromTransportId(window_3_1))));
}
// Verifies client gets a valid id.
@@ -1032,7 +1034,8 @@ TEST_F(WindowTreeClientTest, WindowHierarchyChangedWindows) {
changes2()->clear();
// window_1_1 has a client_id part of client_id_1 in wt2.
- Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ Id window11_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_1));
// client_id_1(),1->client_id_1(),2->client_id_1(),11
{
@@ -1102,8 +1105,9 @@ TEST_F(WindowTreeClientTest, WindowHierarchyChangedAddingKnownToUnknown) {
ASSERT_TRUE(window_2_21);
// window_1_1 has a client_id part of 0 in wt1, while window_2_2 has that of
// client_id_2.
- Id window11_in_wt1 = LoWord(window_1_1);
- Id window22_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_2));
+ Id window11_in_wt1 = ClientWindowIdFromTransportId(window_1_1);
+ Id window22_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_2));
// Set up the hierarchy.
ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
@@ -1171,11 +1175,16 @@ TEST_F(WindowTreeClientTest, ReorderWindow) {
wt_client2()->AddWindow(BuildWindowId(client_id_1(), 1), window_2_1));
// window_2_* has client_id part of client_id_2 in wt1.
- Id window22_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_2));
- Id window23_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_3));
- Id window26_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_6));
- Id window27_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_7));
- Id window28_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_8));
+ Id window22_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_2));
+ Id window23_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_3));
+ Id window26_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_6));
+ Id window27_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_7));
+ Id window28_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_8));
{
changes1()->clear();
@@ -1229,17 +1238,18 @@ TEST_F(WindowTreeClientTest, DeleteWindow) {
ASSERT_TRUE(window_2_1);
// window_2_1 is not created by wt1 so its client_id part is client_id_2,
// while window_1_1 would have 0 for the client_id part.
- Id window21_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_1));
+ Id window21_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_1));
// Make 2 a child of 1.
{
changes1()->clear();
ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ(
- "HierarchyChanged window=" + IdToString(window21_in_wt1) +
- " old_parent=null new_parent=" + IdToString(LoWord(window_1_1)),
- SingleChangeToDescription(*changes1()));
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window21_in_wt1) +
+ " old_parent=null new_parent=" +
+ IdToString(ClientWindowIdFromTransportId(window_1_1)),
+ SingleChangeToDescription(*changes1()));
}
// Delete 2.
@@ -1264,9 +1274,9 @@ TEST_F(WindowTreeClientTest, DeleteRoot) {
wt_client1_->WaitForChangeCount(1);
// window_1_1 should have client_id of 0 in wt_client1 because it's created
// by wt_client1.
- EXPECT_EQ(
- "OnEmbeddedAppDisconnected window=" + IdToString(LoWord(window_1_1)),
- SingleChangeToDescription(*changes1()));
+ EXPECT_EQ("OnEmbeddedAppDisconnected window=" +
+ IdToString(ClientWindowIdFromTransportId(window_1_1)),
+ SingleChangeToDescription(*changes1()));
// Create a new window and try adding to |window_1_1| from client 2, should
// fail as client 2 no longer knows about |window_1_1|.
@@ -1309,8 +1319,9 @@ TEST_F(WindowTreeClientTest, ReuseDeletedWindowId) {
ASSERT_TRUE(window_2_1);
// wt1 created window_1_1 but not window_2_1.
- Id window11_in_wt1 = LoWord(window_1_1);
- Id window21_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_1));
+ Id window11_in_wt1 = ClientWindowIdFromTransportId(window_1_1);
+ Id window21_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_1));
// Add 2 to 1.
{
@@ -1337,7 +1348,8 @@ TEST_F(WindowTreeClientTest, ReuseDeletedWindowId) {
// Create 2 again, and add it back to 1. Should get the same notification.
window_2_1 = wt_client2()->NewWindow(2);
- window21_in_wt1 = BuildWindowId(HiWord(window21_in_wt1), LoWord(window_2_1));
+ window21_in_wt1 = BuildWindowId(ClientIdFromTransportId(window21_in_wt1),
+ ClientWindowIdFromTransportId(window_2_1));
ASSERT_TRUE(window_2_1);
{
changes1()->clear();
@@ -1373,10 +1385,12 @@ TEST_F(WindowTreeClientTest, GetWindowTree) {
ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
// wt1 created window_1_1 and window_1_11, but not window_2_1 and window_2_2.
- Id window11_in_wt1 = LoWord(window_1_1);
- Id window111_in_wt1 = LoWord(window_1_11);
- Id window21_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_1));
- Id window22_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_2));
+ Id window11_in_wt1 = ClientWindowIdFromTransportId(window_1_1);
+ Id window111_in_wt1 = ClientWindowIdFromTransportId(window_1_11);
+ Id window21_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_1));
+ Id window22_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_2));
// Verifies GetWindowTree() on the root. The root client sees all.
{
@@ -1437,7 +1451,8 @@ TEST_F(WindowTreeClientTest, SetWindowBounds) {
wt_client2_->WaitForChangeCount(1);
// window_1_1 has a client_id part of client_id_1 in wt2.
- Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ Id window11_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_1));
EXPECT_EQ("BoundsChanged window=" + IdToString(window11_in_wt2) +
" old_bounds=0,0 0x0 new_bounds=0,0 100x100 local_surface_id=" +
local_surface_id.ToString(),
@@ -1537,7 +1552,8 @@ TEST_F(WindowTreeClientTest, CantGetWindowTreeOfOtherRoots) {
ASSERT_TRUE(windows.empty());
// Should get window 1 if asked for.
- Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ Id window11_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_1));
GetWindowTree(wt2(), window11_in_wt2, &windows);
ASSERT_EQ(1u, windows.size());
EXPECT_EQ(WindowParentToString(window11_in_wt2, kNullParentId),
@@ -1588,8 +1604,9 @@ TEST_F(WindowTreeClientTest, EmbedWithSameWindowId2) {
ASSERT_TRUE(wt_client3()->AddWindow(embedded_window_1_1_wt3, window_3_1));
// wt1 created window_1_1 but not window_3_1.
- Id window11_in_wt1 = LoWord(window_1_1);
- Id window31_in_wt1 = BuildWindowId(client_id_3(), LoWord(window_3_1));
+ Id window11_in_wt1 = ClientWindowIdFromTransportId(window_1_1);
+ Id window31_in_wt1 =
+ BuildWindowId(client_id_3(), ClientWindowIdFromTransportId(window_3_1));
// Client 1 should have been told about the add (it owns the window).
{
@@ -1761,7 +1778,8 @@ TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications) {
ASSERT_TRUE(window_2_1);
ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, true));
// window_1_2 has a client_id part of client_id_1 in wt2.
- Id window12_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_2));
+ Id window12_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_2));
ASSERT_TRUE(wt_client2()->AddWindow(window12_in_wt2, window_2_1));
ASSERT_TRUE(wt_client1()->WaitForAllMessages());
@@ -1810,10 +1828,12 @@ TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications) {
ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, false));
{
wt_client1_->WaitForChangeCount(1);
- EXPECT_EQ("VisibilityChanged window=" +
- IdToString(BuildWindowId(client_id_2(), LoWord(window_2_1))) +
- " visible=false",
- SingleChangeToDescription(*changes1()));
+ EXPECT_EQ(
+ "VisibilityChanged window=" +
+ IdToString(BuildWindowId(
+ client_id_2(), ClientWindowIdFromTransportId(window_2_1))) +
+ " visible=false",
+ SingleChangeToDescription(*changes1()));
}
changes2()->clear();
@@ -1854,7 +1874,8 @@ TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications2) {
// Establish the second client at client_id_1(),2.
ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
// window_1_2 has a client_id part of client_id_1 in wt2.
- Id window12_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_2));
+ Id window12_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_2));
EXPECT_EQ("OnEmbed drawn=true", SingleChangeToDescription2(*changes2()));
changes2()->clear();
@@ -1885,7 +1906,8 @@ TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications3) {
// fixed.
ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
// window_1_2 has a client_id part of client_id_1 in wt2.
- Id window12_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_2));
+ Id window12_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_2));
EXPECT_EQ("OnEmbed drawn=false", SingleChangeToDescription2(*changes2()));
changes2()->clear();
@@ -1921,7 +1943,8 @@ TEST_F(WindowTreeClientTest, SetOpacityNotifications) {
Id window_2_1 = wt_client2()->NewWindow(1);
ASSERT_TRUE(window_2_1);
// window_1_1 has a client_id part of client_id_1 in wt2.
- Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ Id window11_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_1));
ASSERT_TRUE(wt_client2()->AddWindow(window11_in_wt2, window_2_1));
ASSERT_TRUE(wt_client1()->WaitForAllMessages());
@@ -1966,7 +1989,8 @@ TEST_F(WindowTreeClientTest, SetWindowProperty) {
std::vector<uint8_t> one(1, '1');
ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", &one));
// window_1_1 has a client_id part of client_id_1 in wt2.
- Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ Id window11_in_wt2 =
+ BuildWindowId(client_id_1(), ClientWindowIdFromTransportId(window_1_1));
{
wt_client2_->WaitForChangeCount(1);
EXPECT_EQ("PropertyChanged window=" + IdToString(window11_in_wt2) +
@@ -2043,7 +2067,8 @@ TEST_F(WindowTreeClientTest, OnParentOfEmbedDisconnects) {
wt_client3_->WaitForChangeCount(1);
// window_2_2 has a client_id part of client_id_2 in wt3.
EXPECT_EQ("WindowDeleted window=" +
- IdToString(BuildWindowId(client_id_2(), LoWord(window_2_2))),
+ IdToString(BuildWindowId(
+ client_id_2(), ClientWindowIdFromTransportId(window_2_2))),
SingleChangeToDescription(*changes3()));
}
@@ -2057,9 +2082,9 @@ TEST_F(WindowTreeClientTest, DontCleanMapOnDestroy) {
wt_client2_.reset();
wt_client1_->WaitForChangeCount(1);
// window_1_1 is created by wt1 so client_id part would be 0.
- EXPECT_EQ(
- "OnEmbeddedAppDisconnected window=" + IdToString(LoWord(window_1_1)),
- SingleChangeToDescription(*changes1()));
+ EXPECT_EQ("OnEmbeddedAppDisconnected window=" +
+ IdToString(ClientWindowIdFromTransportId(window_1_1)),
+ SingleChangeToDescription(*changes1()));
std::vector<TestWindow> windows;
GetWindowTree(wt1(), window_1_1, &windows);
EXPECT_FALSE(windows.empty());
@@ -2159,7 +2184,8 @@ TEST_F(WindowTreeClientTest, EmbedFailsFromOtherClient) {
ASSERT_TRUE(window_3_3);
// window_2_1 should have client_id of client_id_2 in wt_client3.
ASSERT_TRUE(wt_client3()->AddWindow(
- BuildWindowId(client_id_2(), LoWord(window_2_1)), window_3_3));
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_1)),
+ window_3_3));
// 2 should not be able to embed in window_3_3 as window_3_3 was not created
// by
@@ -2181,7 +2207,8 @@ TEST_F(WindowTreeClientTest, EmbedFromOtherClient) {
// Establish a third client in window_2_1. window_2_1 has a client_id of
// client_id_2 for other clients.
ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(
- wt1(), BuildWindowId(client_id_2(), LoWord(window_2_1))));
+ wt1(),
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_1))));
ASSERT_TRUE(wt_client2()->WaitForAllMessages());
EXPECT_EQ(std::string(), SingleChangeToDescription(*changes2()));
@@ -2227,9 +2254,12 @@ TEST_F(WindowTreeClientTest, TransientWindowTracksTransientParentLifetime) {
Id window_2_3 = wt_client2()->NewWindow(3);
ASSERT_TRUE(window_2_1);
// window_2_* has a client_id part of client_id_2 in wt1.
- Id window21_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_1));
- Id window22_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_2));
- Id window23_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_3));
+ Id window21_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_1));
+ Id window22_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_2));
+ Id window23_in_wt1 =
+ BuildWindowId(client_id_2(), ClientWindowIdFromTransportId(window_2_3));
// root -> window_1_1 -> window_2_1
// root -> window_1_1 -> window_2_2
@@ -2446,7 +2476,8 @@ TEST_F(WindowTreeClientTest, SurfaceIdPropagation) {
changes2()->back().surface_id.frame_sink_id();
// FrameSinkId is based on window's ClientWindowId.
EXPECT_NE(0u, frame_sink_id2.client_id());
- EXPECT_EQ(LoWord(window_2_101), frame_sink_id2.sink_id());
+ EXPECT_EQ(ClientWindowIdFromTransportId(window_2_101),
+ frame_sink_id2.sink_id());
}
// Verifies when an unknown window with a known child is added to a hierarchy
diff --git a/chromium/services/ui/ws/window_tree_factory.cc b/chromium/services/ui/ws/window_tree_factory.cc
index ea43c401ebd..0021fe46000 100644
--- a/chromium/services/ui/ws/window_tree_factory.cc
+++ b/chromium/services/ui/ws/window_tree_factory.cc
@@ -14,10 +14,8 @@ namespace ui {
namespace ws {
WindowTreeFactory::WindowTreeFactory(WindowServer* window_server,
- const UserId& user_id,
const std::string& client_name)
: window_server_(window_server),
- user_id_(user_id),
client_name_(client_name) {}
WindowTreeFactory::~WindowTreeFactory() {}
@@ -25,8 +23,9 @@ WindowTreeFactory::~WindowTreeFactory() {}
void WindowTreeFactory::CreateWindowTree(
mojo::InterfaceRequest<mojom::WindowTree> tree_request,
mojom::WindowTreeClientPtr client) {
+ const bool is_for_embedding = false;
std::unique_ptr<ws::WindowTree> service(
- new ws::WindowTree(window_server_, user_id_, nullptr,
+ new ws::WindowTree(window_server_, is_for_embedding, nullptr,
base::WrapUnique(new DefaultAccessPolicy)));
std::unique_ptr<ws::DefaultWindowTreeBinding> binding(
new ws::DefaultWindowTreeBinding(service.get(), window_server_,
diff --git a/chromium/services/ui/ws/window_tree_factory.h b/chromium/services/ui/ws/window_tree_factory.h
index 879de90cd99..66f114fddd0 100644
--- a/chromium/services/ui/ws/window_tree_factory.h
+++ b/chromium/services/ui/ws/window_tree_factory.h
@@ -7,7 +7,6 @@
#include "base/macros.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
-#include "services/ui/ws/user_id.h"
namespace ui {
namespace ws {
@@ -17,7 +16,6 @@ class WindowServer;
class WindowTreeFactory : public ui::mojom::WindowTreeFactory {
public:
WindowTreeFactory(WindowServer* window_server,
- const UserId& user_id,
const std::string& client_name);
~WindowTreeFactory() override;
@@ -27,7 +25,6 @@ class WindowTreeFactory : public ui::mojom::WindowTreeFactory {
mojom::WindowTreeClientPtr client) override;
WindowServer* window_server_;
- const UserId user_id_;
const std::string client_name_;
DISALLOW_COPY_AND_ASSIGN(WindowTreeFactory);
diff --git a/chromium/services/ui/ws/window_tree_host_factory.cc b/chromium/services/ui/ws/window_tree_host_factory.cc
index 1efbf9b5a42..4675098830d 100644
--- a/chromium/services/ui/ws/window_tree_host_factory.cc
+++ b/chromium/services/ui/ws/window_tree_host_factory.cc
@@ -12,9 +12,8 @@
namespace ui {
namespace ws {
-WindowTreeHostFactory::WindowTreeHostFactory(WindowServer* window_server,
- const UserId& user_id)
- : window_server_(window_server), user_id_(user_id) {}
+WindowTreeHostFactory::WindowTreeHostFactory(WindowServer* window_server)
+ : window_server_(window_server) {}
WindowTreeHostFactory::~WindowTreeHostFactory() {}
@@ -28,9 +27,8 @@ void WindowTreeHostFactory::CreateWindowTreeHost(
mojom::WindowTreeClientPtr tree_client) {
Display* ws_display = new Display(window_server_);
- std::unique_ptr<DisplayBindingImpl> display_binding(
- new DisplayBindingImpl(std::move(host), ws_display, user_id_,
- std::move(tree_client), window_server_));
+ std::unique_ptr<DisplayBindingImpl> display_binding(new DisplayBindingImpl(
+ std::move(host), ws_display, std::move(tree_client), window_server_));
// Provide an initial size for the WindowTreeHost.
display::ViewportMetrics metrics;
diff --git a/chromium/services/ui/ws/window_tree_host_factory.h b/chromium/services/ui/ws/window_tree_host_factory.h
index d50046d73ab..de23bde565a 100644
--- a/chromium/services/ui/ws/window_tree_host_factory.h
+++ b/chromium/services/ui/ws/window_tree_host_factory.h
@@ -9,7 +9,6 @@
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/ui/public/interfaces/window_tree_host_factory.mojom.h"
-#include "services/ui/ws/user_id.h"
namespace ui {
namespace ws {
@@ -18,7 +17,7 @@ class WindowServer;
class WindowTreeHostFactory : public mojom::WindowTreeHostFactory {
public:
- WindowTreeHostFactory(WindowServer* window_server, const UserId& user_id);
+ explicit WindowTreeHostFactory(WindowServer* window_server);
~WindowTreeHostFactory() override;
void AddBinding(mojom::WindowTreeHostFactoryRequest request);
@@ -29,7 +28,6 @@ class WindowTreeHostFactory : public mojom::WindowTreeHostFactory {
mojom::WindowTreeClientPtr tree_client) override;
WindowServer* window_server_;
- const UserId user_id_;
mojo::BindingSet<mojom::WindowTreeHostFactory> bindings_;
DISALLOW_COPY_AND_ASSIGN(WindowTreeHostFactory);
diff --git a/chromium/services/ui/ws/window_tree_unittest.cc b/chromium/services/ui/ws/window_tree_unittest.cc
index a677af9c9dc..28a492cf098 100644
--- a/chromium/services/ui/ws/window_tree_unittest.cc
+++ b/chromium/services/ui/ws/window_tree_unittest.cc
@@ -13,7 +13,7 @@
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
+#include "services/service_manager/public/mojom/connector.mojom.h"
#include "services/ui/common/task_runner_test_base.h"
#include "services/ui/common/types.h"
#include "services/ui/common/util.h"
@@ -45,7 +45,6 @@ namespace ws {
namespace test {
namespace {
-const UserId kTestUserId1 = "2";
const std::string kNextWindowClientIdString =
std::to_string(kWindowManagerClientId + 1);
@@ -99,7 +98,7 @@ ui::PointerEvent CreateMouseUpEvent(int x, int y) {
}
ServerWindow* GetCaptureWindow(Display* display) {
- return display->GetActiveWindowManagerDisplayRoot()
+ return display->window_manager_display_root()
->window_manager_state()
->capture_window();
}
@@ -110,7 +109,7 @@ class TestMoveLoopWindowManager : public TestWindowManager {
~TestMoveLoopWindowManager() override {}
void WmPerformMoveLoop(uint32_t change_id,
- uint32_t window_id,
+ Id window_id,
mojom::MoveLoopSource source,
const gfx::Point& cursor_location) override {
static_cast<mojom::WindowManagerClient*>(tree_)->WmResponse(
@@ -126,9 +125,9 @@ class TestMoveLoopWindowManager : public TestWindowManager {
// This creates a WindowTree similar to how connecting via WindowTreeFactory
// creates a tree.
WindowTree* CreateTreeViaFactory(WindowServer* window_server,
- const UserId& user_id,
TestWindowTreeBinding** binding) {
- WindowTree* tree = new WindowTree(window_server, user_id, nullptr,
+ const bool is_for_embedding = false;
+ WindowTree* tree = new WindowTree(window_server, is_for_embedding, nullptr,
std::make_unique<DefaultAccessPolicy>());
*binding = new TestWindowTreeBinding(tree);
window_server->AddTree(base::WrapUnique(tree), base::WrapUnique(*binding),
@@ -180,7 +179,7 @@ class WindowTreeTest : public testing::Test {
void AckPreviousEvent() {
WindowManagerStateTestApi test_api(
- display()->GetActiveWindowManagerDisplayRoot()->window_manager_state());
+ display()->window_manager_display_root()->window_manager_state());
while (test_api.tree_awaiting_input_ack()) {
WindowTreeTestApi(test_api.tree_awaiting_input_ack())
.AckOldestEvent(mojom::EventResult::HANDLED);
@@ -199,9 +198,8 @@ class WindowTreeTest : public testing::Test {
// Creates a new tree as the specified user. This does what creation via
// a WindowTreeFactory does.
- WindowTree* CreateNewTree(const UserId& user_id,
- TestWindowTreeBinding** binding) {
- return CreateTreeViaFactory(window_server(), user_id, binding);
+ WindowTree* CreateNewTree(TestWindowTreeBinding** binding) {
+ return CreateTreeViaFactory(window_server(), binding);
}
TestWindowServerDelegate* test_window_server_delegate() {
@@ -290,7 +288,7 @@ TEST_F(WindowTreeTest, BasicInputEventTarget) {
// embed_client created this window that is receiving the event, so client_id
// part would be reset to 0 before sending back to clients.
EXPECT_EQ("InputEvent window=0," + std::to_string(kEmbedTreeWindowId) +
- " event_action=16",
+ " event_action=" + std::to_string(ui::ET_POINTER_DOWN),
ChangesToDescription1(*embed_client->tracker()->changes())[0]);
}
@@ -305,7 +303,7 @@ TEST_F(WindowTreeTest, EventDispatcherMouseCursorSourceWindowResetOnRemove) {
DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
WindowManagerState* wms =
- display()->GetActiveWindowManagerDisplayRoot()->window_manager_state();
+ display()->window_manager_display_root()->window_manager_state();
EXPECT_EQ(window, wms->event_dispatcher()->mouse_cursor_source_window());
window->parent()->Remove(window);
@@ -354,7 +352,8 @@ TEST_F(WindowTreeTest, StartPointerWatcher) {
// Pointer-down events are sent to the client.
DispatchEventAndAckImmediately(pointer_down);
ASSERT_EQ(1u, client->tracker()->changes()->size());
- EXPECT_EQ("PointerWatcherEvent event_action=16 window=null",
+ EXPECT_EQ("PointerWatcherEvent event_action=" +
+ std::to_string(ui::ET_POINTER_DOWN) + " window=null",
ChangesToDescription1(*client->tracker()->changes())[0]);
client->tracker()->changes()->clear();
@@ -364,7 +363,8 @@ TEST_F(WindowTreeTest, StartPointerWatcher) {
// Pointer-wheel events are sent to the client.
DispatchEventAndAckImmediately(pointer_wheel);
ASSERT_EQ(1u, client->tracker()->changes()->size());
- EXPECT_EQ("PointerWatcherEvent event_action=22 window=null",
+ EXPECT_EQ("PointerWatcherEvent event_action=" +
+ std::to_string(ui::ET_POINTER_WHEEL_CHANGED) + " window=null",
ChangesToDescription1(*client->tracker()->changes())[0]);
client->tracker()->changes()->clear();
@@ -381,7 +381,8 @@ TEST_F(WindowTreeTest, StartPointerWatcher) {
// Pointer-wheel events are sent to the client.
DispatchEventAndAckImmediately(pointer_wheel);
ASSERT_EQ(1u, client->tracker()->changes()->size());
- EXPECT_EQ("PointerWatcherEvent event_action=22 window=null",
+ EXPECT_EQ("PointerWatcherEvent event_action=" +
+ std::to_string(ui::ET_POINTER_WHEEL_CHANGED) + " window=null",
ChangesToDescription1(*client->tracker()->changes())[0]);
}
@@ -401,7 +402,8 @@ TEST_F(WindowTreeTest, PointerWatcherGetsWindow) {
ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
EXPECT_EQ(
- "PointerWatcherEvent event_action=16 window=" +
+ "PointerWatcherEvent event_action=" +
+ std::to_string(ui::ET_POINTER_DOWN) + " window=" +
ClientWindowIdToString(ClientWindowIdForWindow(wm_tree(), window)),
ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
}
@@ -446,34 +448,15 @@ TEST_F(WindowTreeTest, StartPointerWatcherSendsOnce) {
// clients that created this window is receiving the event, so client_id part
// would be reset to 0 before sending back to clients.
EXPECT_EQ("InputEvent window=0," + std::to_string(kEmbedTreeWindowId) +
- " event_action=18 matches_pointer_watcher",
+ " event_action=" + std::to_string(ui::ET_POINTER_UP) +
+ " matches_pointer_watcher",
SingleChangeToDescription(*client->tracker()->changes()));
}
-// Tests that events generated by user A are not watched by pointer watchers
-// for user B.
-TEST_F(WindowTreeTest, StartPointerWatcherWrongUser) {
- // Embed a window tree belonging to a different user.
- TestWindowTreeBinding* other_binding;
- WindowTree* other_tree = CreateNewTree("other_user", &other_binding);
- other_binding->client()->tracker()->changes()->clear();
-
- // Set pointer watchers on both the wm tree and the other user's tree.
- WindowTreeTestApi(wm_tree()).StartPointerWatcher(false);
- WindowTreeTestApi(other_tree).StartPointerWatcher(false);
-
- // An event is watched by the wm tree, but not by the other user's tree.
- DispatchEventAndAckImmediately(CreatePointerUpEvent(5, 5));
- ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
- EXPECT_EQ("PointerWatcherEvent event_action=18 window=null",
- SingleChangeToDescription(*wm_client()->tracker()->changes()));
- ASSERT_EQ(0u, other_binding->client()->tracker()->changes()->size());
-}
-
// Tests that a pointer watcher cannot watch keystrokes.
TEST_F(WindowTreeTest, StartPointerWatcherKeyEventsDisallowed) {
TestWindowTreeBinding* other_binding;
- WindowTree* other_tree = CreateNewTree("other_user", &other_binding);
+ WindowTree* other_tree = CreateNewTree(&other_binding);
other_binding->client()->tracker()->changes()->clear();
WindowTreeTestApi(other_tree).StartPointerWatcher(false);
@@ -481,7 +464,7 @@ TEST_F(WindowTreeTest, StartPointerWatcherKeyEventsDisallowed) {
DispatchEventAndAckImmediately(key_pressed);
EXPECT_EQ(0u, other_binding->client()->tracker()->changes()->size());
EXPECT_EQ("InputEvent window=" + std::to_string(kWindowServerClientId) +
- ",3 event_action=7",
+ ",3 event_action=" + std::to_string(ui::ET_KEY_PRESSED),
SingleChangeToDescription(*wm_client()->tracker()->changes()));
WindowTreeTestApi(wm_tree()).StartPointerWatcher(false);
@@ -494,7 +477,7 @@ TEST_F(WindowTreeTest, KeyEventSentToWindowManagerWhenNothingFocused) {
ui::KeyEvent key_pressed(ui::ET_KEY_PRESSED, ui::VKEY_A, ui::EF_NONE);
DispatchEventAndAckImmediately(key_pressed);
EXPECT_EQ("InputEvent window=" + std::to_string(kWindowServerClientId) +
- ",3 event_action=7",
+ ",3 event_action=" + std::to_string(ui::ET_KEY_PRESSED),
SingleChangeToDescription(*wm_client()->tracker()->changes()));
}
@@ -669,7 +652,7 @@ TEST_F(WindowTreeTest, EventAck) {
DispatchEventWithoutAck(CreateMouseMoveEvent(21, 22));
ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
EXPECT_EQ("InputEvent window=" + std::to_string(kWindowServerClientId) +
- ",3 event_action=17",
+ ",3 event_action=" + std::to_string(ui::ET_POINTER_MOVED),
ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
wm_client()->tracker()->changes()->clear();
@@ -681,10 +664,57 @@ TEST_F(WindowTreeTest, EventAck) {
AckPreviousEvent();
ASSERT_EQ(1u, wm_client()->tracker()->changes()->size());
EXPECT_EQ("InputEvent window=" + std::to_string(kWindowServerClientId) +
- ",3 event_action=17",
+ ",3 event_action=" + std::to_string(ui::ET_POINTER_MOVED),
ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
}
+TEST_F(WindowTreeTest, RemoveWindowFromParentWithQueuedEvent) {
+ TestWindowTreeClient* embed_client = nullptr;
+ WindowTree* tree = nullptr;
+ ServerWindow* window = nullptr;
+ EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
+
+ window->SetBounds(gfx::Rect(0, 0, 100, 100));
+ window->set_is_activation_parent(true);
+ ClientWindowId w1_id;
+ ServerWindow* w1 =
+ NewWindowInTreeWithParent(tree, window, &w1_id, gfx::Rect(0, 0, 20, 20));
+ ASSERT_TRUE(w1);
+ ClientWindowId w2_id;
+ ServerWindow* w2 =
+ NewWindowInTreeWithParent(tree, window, &w2_id, gfx::Rect(25, 0, 20, 20));
+ ASSERT_TRUE(w2);
+
+ DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
+
+ // This moves between |w1| and |w2|, which results in two events (move and
+ // enter).
+ DispatchEventWithoutAck(CreateMouseMoveEvent(27, 5));
+
+ // There should be an event in flight for the move.
+ EXPECT_TRUE(WindowTreeTestApi(tree).HasEventInFlight());
+
+ // Simulate the client taking too long.
+ WindowManagerStateTestApi wm_state_test_api(
+ wm_tree()->window_manager_state());
+ wm_state_test_api.OnEventAckTimeout(tree->id());
+
+ // There should be an event queued (for the enter).
+ EXPECT_EQ(1u, WindowTreeTestApi(tree).event_queue_size());
+
+ // Remove the window from the hierarchy, which should make it so the client
+ // doesn't get the queued event.
+ w2->parent()->Remove(w2);
+
+ // Ack the in flight event, which should trigger processing the queued event.
+ // Because |w2| was removed, the event should not be dispatched to the client
+ // and WindowManagerState should no longer be waiting (because there are no
+ // inflight events).
+ WindowTreeTestApi(tree).AckOldestEvent();
+ EXPECT_FALSE(WindowTreeTestApi(tree).HasEventInFlight());
+ EXPECT_EQ(nullptr, wm_state_test_api.tree_awaiting_input_ack());
+}
+
// Establish client, call Embed() in WM, make sure to get FrameSinkId.
TEST_F(WindowTreeTest, Embed) {
const ClientWindowId embed_window_id =
@@ -746,7 +776,7 @@ TEST_F(WindowTreeTest, ModalTypeSystemToModalTypeNone) {
EXPECT_TRUE(wm_tree()->AddWindow(wm_root_id, test_window_id));
EXPECT_TRUE(wm_tree()->SetModalType(test_window_id, MODAL_TYPE_SYSTEM));
WindowManagerState* wms =
- display()->GetActiveWindowManagerDisplayRoot()->window_manager_state();
+ display()->window_manager_display_root()->window_manager_state();
ModalWindowControllerTestApi modal_window_controller_test_api(
EventDispatcherTestApi(wms->event_dispatcher())
.modal_window_controller());
@@ -766,7 +796,7 @@ TEST_F(WindowTreeTest, ModalTypeSystemUnparentedThenParented) {
const ClientWindowId wm_root_id = FirstRootId(wm_tree());
EXPECT_TRUE(wm_tree()->SetModalType(test_window_id, MODAL_TYPE_SYSTEM));
WindowManagerState* wms =
- display()->GetActiveWindowManagerDisplayRoot()->window_manager_state();
+ display()->window_manager_display_root()->window_manager_state();
ModalWindowControllerTestApi modal_window_controller_test_api(
EventDispatcherTestApi(wms->event_dispatcher())
.modal_window_controller());
@@ -787,7 +817,7 @@ TEST_F(WindowTreeTest, NewTopLevelWindow) {
set_window_manager_internal(wm_tree(), &wm_internal);
TestWindowTreeBinding* child_binding;
- WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
+ WindowTree* child_tree = CreateNewTree(&child_binding);
child_binding->client()->tracker()->changes()->clear();
child_binding->client()->set_record_on_change_completed(true);
@@ -1211,29 +1241,24 @@ TEST_F(WindowTreeTest, SetOpacityFailsOnUnknownWindow) {
ServerWindow* window = nullptr;
EXPECT_NO_FATAL_FAILURE(SetupEventTargeting(&embed_client, &tree, &window));
- TestServerWindowDelegate delegate(window_server()->GetVizHostProxy());
- WindowId window_id(42, 1337);
- ServerWindow unknown_window(&delegate, window_id);
- const float new_opacity = 0.5f;
- ASSERT_NE(new_opacity, unknown_window.opacity());
+ const ClientWindowId root_id = FirstRootId(tree);
EXPECT_FALSE(tree->SetWindowOpacity(
- ClientWindowId(window_id.client_id, window_id.window_id), new_opacity));
- EXPECT_NE(new_opacity, unknown_window.opacity());
+ ClientWindowId(root_id.client_id(), root_id.sink_id() + 10), .5f));
}
TEST_F(WindowTreeTest, SetCaptureTargetsRightConnection) {
ServerWindow* window = window_event_targeting_helper_.CreatePrimaryTree(
gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 50, 50));
WindowTree* owning_tree =
- window_server()->GetTreeWithId(window->id().client_id);
+ window_server()->GetTreeWithId(window->owning_tree_id());
WindowTree* embed_tree = window_server()->GetTreeWithRoot(window);
ASSERT_NE(owning_tree, embed_tree);
ASSERT_TRUE(
owning_tree->SetCapture(ClientWindowIdForWindow(owning_tree, window)));
DispatchEventWithoutAck(CreateMouseMoveEvent(21, 22));
WindowManagerStateTestApi wm_state_test_api(
- display()->GetActiveWindowManagerDisplayRoot()->window_manager_state());
+ display()->window_manager_display_root()->window_manager_state());
EXPECT_EQ(owning_tree, wm_state_test_api.tree_awaiting_input_ack());
AckPreviousEvent();
@@ -1249,7 +1274,7 @@ TEST_F(WindowTreeTest, ValidMoveLoopWithWM) {
set_window_manager_internal(wm_tree(), &wm_internal);
TestWindowTreeBinding* child_binding;
- WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
+ WindowTree* child_tree = CreateNewTree(&child_binding);
child_binding->client()->tracker()->changes()->clear();
child_binding->client()->set_record_on_change_completed(true);
@@ -1300,7 +1325,7 @@ TEST_F(WindowTreeTest, MoveLoopAckOKByWM) {
set_window_manager_internal(wm_tree(), &wm_internal);
TestWindowTreeBinding* child_binding;
- WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
+ WindowTree* child_tree = CreateNewTree(&child_binding);
child_binding->client()->tracker()->changes()->clear();
child_binding->client()->set_record_on_change_completed(true);
@@ -1361,7 +1386,7 @@ TEST_F(WindowTreeTest, WindowManagerCantMoveLoop) {
set_window_manager_internal(wm_tree(), &wm_internal);
TestWindowTreeBinding* child_binding;
- WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
+ WindowTree* child_tree = CreateNewTree(&child_binding);
child_binding->client()->tracker()->changes()->clear();
child_binding->client()->set_record_on_change_completed(true);
@@ -1410,7 +1435,7 @@ TEST_F(WindowTreeTest, RevertWindowBoundsOnMoveLoopFailure) {
set_window_manager_internal(wm_tree(), &wm_internal);
TestWindowTreeBinding* child_binding;
- WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
+ WindowTree* child_tree = CreateNewTree(&child_binding);
child_binding->client()->tracker()->changes()->clear();
child_binding->client()->set_record_on_change_completed(true);
@@ -1508,7 +1533,7 @@ TEST_F(WindowTreeTest, CaptureNotifiesWm) {
gfx::Rect(0, 0, 100, 100), gfx::Rect(0, 0, 50, 50));
TestWindowTreeClient* embed_client = last_window_tree_client();
WindowTree* owning_tree =
- window_server()->GetTreeWithId(window->id().client_id);
+ window_server()->GetTreeWithId(window->owning_tree_id());
WindowTree* embed_tree = window_server()->GetTreeWithRoot(window);
ASSERT_NE(owning_tree, embed_tree);
@@ -1558,7 +1583,7 @@ TEST_F(WindowTreeTest, SetModalTypeForwardedToWindowManager) {
set_window_manager_internal(wm_tree(), &wm_internal);
TestWindowTreeBinding* child_binding = nullptr;
- WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
+ WindowTree* child_tree = CreateNewTree(&child_binding);
// Create a new top level window.
std::unordered_map<std::string, std::vector<uint8_t>> properties;
@@ -1649,11 +1674,9 @@ TEST_F(WindowTreeShutdownTest, DontSendMessagesDuringShutdown) {
WindowServer* window_server = ws_test_helper.window_server();
TestScreenManager screen_manager;
screen_manager.Init(window_server->display_manager());
- window_server->user_id_tracker()->AddUserId(kTestUserId1);
screen_manager.AddDisplay();
- AddWindowManager(window_server, kTestUserId1);
- window_server->user_id_tracker()->SetActiveUserId(kTestUserId1);
+ AddWindowManager(window_server);
TestWindowTreeBinding* test_binding =
ws_test_helper.window_server_delegate()->last_binding();
ASSERT_TRUE(test_binding);
@@ -1690,7 +1713,6 @@ class WindowTreeManualDisplayTest : public TaskRunnerTestBase {
void SetUp() override {
TaskRunnerTestBase::SetUp();
screen_manager_.Init(window_server()->display_manager());
- window_server()->user_id_tracker()->AddUserId(kTestUserId1);
}
private:
@@ -1702,11 +1724,10 @@ class WindowTreeManualDisplayTest : public TaskRunnerTestBase {
TEST_F(WindowTreeManualDisplayTest, ClientCreatesDisplayRoot) {
const bool automatically_create_display_roots = false;
- AddWindowManager(window_server(), kTestUserId1,
- automatically_create_display_roots);
+ AddWindowManager(window_server(), automatically_create_display_roots);
WindowManagerState* window_manager_state =
- window_server()->GetWindowManagerStateForUser(kTestUserId1);
+ window_server()->GetWindowManagerState();
ASSERT_TRUE(window_manager_state);
WindowTree* window_manager_tree = window_manager_state->window_tree();
EXPECT_TRUE(window_manager_tree->roots().empty());
@@ -1752,11 +1773,10 @@ TEST_F(WindowTreeManualDisplayTest, ClientCreatesDisplayRoot) {
TEST_F(WindowTreeManualDisplayTest, MoveDisplayRootToNewDisplay) {
const bool automatically_create_display_roots = false;
- AddWindowManager(window_server(), kTestUserId1,
- automatically_create_display_roots);
+ AddWindowManager(window_server(), automatically_create_display_roots);
WindowManagerState* window_manager_state =
- window_server()->GetWindowManagerStateForUser(kTestUserId1);
+ window_server()->GetWindowManagerState();
ASSERT_TRUE(window_manager_state);
WindowTree* window_manager_tree = window_manager_state->window_tree();
EXPECT_TRUE(window_manager_tree->roots().empty());
@@ -1785,7 +1805,8 @@ TEST_F(WindowTreeManualDisplayTest, MoveDisplayRootToNewDisplay) {
.ProcessSetDisplayRoot(display1, metrics, is_primary_display,
display_root_id));
ASSERT_TRUE(display_root->parent());
- const WindowId display1_parent_id = display_root->parent()->id();
+ const viz::FrameSinkId display1_parent_id =
+ display_root->parent()->frame_sink_id();
EXPECT_TRUE(window_server_delegate()
->last_binding()
->client()
@@ -1802,7 +1823,7 @@ TEST_F(WindowTreeManualDisplayTest, MoveDisplayRootToNewDisplay) {
.ProcessSetDisplayRoot(display2, metrics, is_primary_display,
display_root_id));
ASSERT_TRUE(display_root->parent());
- EXPECT_NE(display1_parent_id, display_root->parent()->id());
+ EXPECT_NE(display1_parent_id, display_root->parent()->frame_sink_id());
EXPECT_TRUE(window_server_delegate()
->last_binding()
->client()
@@ -1828,13 +1849,12 @@ TEST_F(WindowTreeManualDisplayTest, MoveDisplayRootToNewDisplay) {
TEST_F(WindowTreeManualDisplayTest,
DisplayManagerObserverNotifiedWithManualRoots) {
const bool automatically_create_display_roots = false;
- AddWindowManager(window_server(), kTestUserId1,
- automatically_create_display_roots);
+ AddWindowManager(window_server(), automatically_create_display_roots);
TestDisplayManagerObserver display_manager_observer;
DisplayManager* display_manager = window_server()->display_manager();
UserDisplayManager* user_display_manager =
- display_manager->GetUserDisplayManager(kTestUserId1);
+ display_manager->GetUserDisplayManager();
ASSERT_TRUE(user_display_manager);
user_display_manager->AddObserver(display_manager_observer.GetPtr());
@@ -1847,7 +1867,7 @@ TEST_F(WindowTreeManualDisplayTest,
// Set frame decorations, again observer should not be notified.
WindowManagerState* window_manager_state =
- window_server()->GetWindowManagerStateForUser(kTestUserId1);
+ window_server()->GetWindowManagerState();
ASSERT_TRUE(window_manager_state);
WindowTree* window_manager_tree = window_manager_state->window_tree();
window_manager_state->SetFrameDecorationValues(
@@ -1996,11 +2016,10 @@ TEST_F(WindowTreeManualDisplayTest,
TEST_F(WindowTreeManualDisplayTest, SwapDisplayRoots) {
const bool automatically_create_display_roots = false;
- AddWindowManager(window_server(), kTestUserId1,
- automatically_create_display_roots);
+ AddWindowManager(window_server(), automatically_create_display_roots);
WindowManagerState* window_manager_state =
- window_server()->GetWindowManagerStateForUser(kTestUserId1);
+ window_server()->GetWindowManagerState();
ASSERT_TRUE(window_manager_state);
WindowTree* window_manager_tree = window_manager_state->window_tree();
window_manager_state->SetFrameDecorationValues(
@@ -2081,7 +2100,7 @@ TEST_F(WindowTreeTest, PerformWmAction) {
set_window_manager_internal(wm_tree(), &wm_internal);
TestWindowTreeBinding* child_binding = nullptr;
- WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
+ WindowTree* child_tree = CreateNewTree(&child_binding);
// Create a new top level window.
std::unordered_map<std::string, std::vector<uint8_t>> properties;
@@ -2130,9 +2149,9 @@ TEST_F(WindowTreeTest, EmbedderInterceptsEventsSeesWindowsInEmbeddedClients) {
// Embed a new client in |w1|.
TestWindowTreeBinding* embed_binding1 =
test_window_server_delegate()->Embed(wm_tree(), w1);
- // Set the user-id to a non-empty string, this way
- // kEmbedFlagEmbedderInterceptsEvents is honored.
- WindowTreeTestApi(embed_binding1->tree()).set_user_id("x");
+ // Set the |is_for_embedding| to false, otherwise
+ // kEmbedFlagEmbedderInterceptsEvents is ignored
+ WindowTreeTestApi(embed_binding1->tree()).set_is_for_embedding(false);
ASSERT_TRUE(embed_binding1);
// Create |w2| (in the embedded tree).
@@ -2183,7 +2202,7 @@ TEST_F(WindowTreeTest, EmbedderInterceptsEventsSeesWindowsInEmbeddedClients) {
// kEmbedFlagEmbedderInterceptsEvents).
EXPECT_EQ(1u, embed_binding1->client()->tracker()->changes()->size());
EXPECT_EQ("InputEvent window=" + ClientWindowIdToString(w4_in_tree1_id) +
- " event_action=16",
+ " event_action=" + std::to_string(ui::ET_POINTER_DOWN),
SingleChangeToDescription(
*embed_binding1->client()->tracker()->changes()));
}
diff --git a/chromium/services/ui/ws2/OWNERS b/chromium/services/ui/ws2/OWNERS
new file mode 100644
index 00000000000..f07a45eb6db
--- /dev/null
+++ b/chromium/services/ui/ws2/OWNERS
@@ -0,0 +1,4 @@
+# COMPONENT: Internals>MUS
+
+per-file test_manifest.json=set noparent
+per-file test_manifest.json=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/ui/ws2/ids.h b/chromium/services/ui/ws2/ids.h
new file mode 100644
index 00000000000..820710e8188
--- /dev/null
+++ b/chromium/services/ui/ws2/ids.h
@@ -0,0 +1,100 @@
+// 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.
+
+#ifndef SERVICES_UI_WS2_IDS_H_
+#define SERVICES_UI_WS2_IDS_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <tuple>
+
+#include "base/containers/hash_tables.h"
+#include "base/hash.h"
+#include "base/strings/stringprintf.h"
+#include "components/viz/common/surfaces/frame_sink_id.h"
+#include "services/ui/common/types.h"
+#include "services/ui/common/util.h"
+
+namespace ui {
+namespace ws {
+
+// A client id used to indicate no client. That is, no WindowTree ever gets this
+// id.
+const ClientSpecificId kInvalidClientId = 0;
+
+const Id kInvalidTransportId = 0;
+
+// A client id used to indicate WindowServer.
+const ClientSpecificId kWindowServerClientId = 1;
+
+// Every window has a unique id associated with it (WindowId). The id is a
+// combination of the id assigned to the client (the high order bits) and
+// a unique id for the window. Each client (WindowTree) refers to the window
+// by an id assigned by the client (ClientWindowId). To facilitate this
+// WindowTree maintains a mapping between WindowId and ClientWindowId.
+//
+// This model works when the client initiates creation of windows, which is
+// the typical use case. Embed roots and the WindowManager are special, they
+// get access to windows created by other clients. These clients see the
+// id assigned on the server. Such clients have to take care that they only
+// create windows using their client id. To do otherwise could result in
+// multiple windows having the same ClientWindowId. WindowTree enforces
+// that embed roots use the client id in creating the window id to avoid
+// possible conflicts.
+
+// Used for ids assigned by the client.
+using ClientWindowId = viz::FrameSinkId;
+
+struct WindowId {
+ constexpr WindowId(ClientSpecificId client_id, ClientSpecificId window_id)
+ : client_id(client_id), window_id(window_id) {}
+ constexpr WindowId() : client_id(0), window_id(0) {}
+
+ bool operator==(const WindowId& other) const {
+ return other.client_id == client_id && other.window_id == window_id;
+ }
+
+ bool operator!=(const WindowId& other) const { return !(*this == other); }
+
+ bool operator<(const WindowId& other) const {
+ return std::tie(client_id, window_id) <
+ std::tie(other.client_id, other.window_id);
+ }
+
+ std::string ToString() const {
+ return base::StringPrintf("%u:%u", client_id, window_id);
+ }
+
+ ClientSpecificId client_id;
+ ClientSpecificId window_id;
+};
+
+inline WindowId WindowIdFromTransportId(Id id) {
+ return WindowId(HiWord(id), LoWord(id));
+}
+
+// Returns a WindowId that is reserved to indicate no window. That is, no window
+// will ever be created with this id.
+inline WindowId InvalidWindowId() {
+ return WindowId(kInvalidClientId, 0);
+}
+
+// Returns a root window id with a given index offset.
+inline WindowId RootWindowId(uint16_t index) {
+ return WindowId(kWindowServerClientId, 2 + index);
+}
+
+using ClientWindowIdHash = viz::FrameSinkIdHash;
+
+struct WindowIdHash {
+ size_t operator()(const WindowId& id) const {
+ return (id.client_id << 16) | id.window_id;
+ }
+};
+
+} // namespace ws
+} // namespace ui
+
+#endif // SERVICES_UI_WS2_IDS_H_
diff --git a/chromium/services/ui/ws2/test_change_tracker.cc b/chromium/services/ui/ws2/test_change_tracker.cc
new file mode 100644
index 00000000000..fb2518a327f
--- /dev/null
+++ b/chromium/services/ui/ws2/test_change_tracker.cc
@@ -0,0 +1,503 @@
+// 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/test_change_tracker.h"
+
+#include <stddef.h>
+
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "mojo/public/cpp/bindings/map.h"
+#include "services/ui/common/util.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/gfx/geometry/point_conversions.h"
+
+namespace ui {
+
+namespace ws {
+
+std::string WindowIdToString(Id id) {
+ return (id == 0) ? "null"
+ : base::StringPrintf("%d,%d", HiWord(id), LoWord(id));
+}
+
+namespace {
+
+std::string DirectionToString(mojom::OrderDirection direction) {
+ return direction == mojom::OrderDirection::ABOVE ? "above" : "below";
+}
+
+enum class ChangeDescriptionType {
+ ONE,
+ TWO,
+ // Includes display id and location of events.
+ THREE,
+};
+
+std::string ChangeToDescription(const Change& change,
+ ChangeDescriptionType type) {
+ switch (change.type) {
+ case CHANGE_TYPE_EMBED:
+ if (type == ChangeDescriptionType::ONE)
+ return "OnEmbed";
+ return base::StringPrintf("OnEmbed drawn=%s",
+ change.bool_value ? "true" : "false");
+
+ case CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED:
+ return base::StringPrintf("OnEmbeddedAppDisconnected window=%s",
+ WindowIdToString(change.window_id).c_str());
+
+ case CHANGE_TYPE_UNEMBED:
+ return base::StringPrintf("OnUnembed window=%s",
+ WindowIdToString(change.window_id).c_str());
+
+ case CHANGE_TYPE_CAPTURE_CHANGED:
+ return base::StringPrintf("OnCaptureChanged new_window=%s old_window=%s",
+ WindowIdToString(change.window_id).c_str(),
+ WindowIdToString(change.window_id2).c_str());
+
+ case CHANGE_TYPE_FRAME_SINK_ID_ALLOCATED:
+ return base::StringPrintf("OnFrameSinkIdAllocated window=%s %s",
+ WindowIdToString(change.window_id).c_str(),
+ change.frame_sink_id.ToString().c_str());
+
+ case CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW:
+ return base::StringPrintf("AddTransientWindow parent = %s child = %s",
+ WindowIdToString(change.window_id).c_str(),
+ WindowIdToString(change.window_id2).c_str());
+
+ case CHANGE_TYPE_NODE_BOUNDS_CHANGED:
+ return base::StringPrintf(
+ "BoundsChanged window=%s old_bounds=%s new_bounds=%s "
+ "local_surface_id=%s",
+ WindowIdToString(change.window_id).c_str(),
+ change.bounds.ToString().c_str(), change.bounds2.ToString().c_str(),
+ change.local_surface_id ? change.local_surface_id->ToString().c_str()
+ : "(none)");
+
+ case CHANGE_TYPE_NODE_HIERARCHY_CHANGED:
+ return base::StringPrintf(
+ "HierarchyChanged window=%s old_parent=%s new_parent=%s",
+ WindowIdToString(change.window_id).c_str(),
+ WindowIdToString(change.window_id2).c_str(),
+ WindowIdToString(change.window_id3).c_str());
+
+ case CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT:
+ return base::StringPrintf(
+ "RemoveTransientWindowFromParent parent = %s child = %s",
+ WindowIdToString(change.window_id).c_str(),
+ WindowIdToString(change.window_id2).c_str());
+
+ case CHANGE_TYPE_NODE_REORDERED:
+ return base::StringPrintf("Reordered window=%s relative=%s direction=%s",
+ WindowIdToString(change.window_id).c_str(),
+ WindowIdToString(change.window_id2).c_str(),
+ DirectionToString(change.direction).c_str());
+
+ case CHANGE_TYPE_NODE_DELETED:
+ return base::StringPrintf("WindowDeleted window=%s",
+ WindowIdToString(change.window_id).c_str());
+
+ case CHANGE_TYPE_NODE_VISIBILITY_CHANGED:
+ return base::StringPrintf("VisibilityChanged window=%s visible=%s",
+ WindowIdToString(change.window_id).c_str(),
+ change.bool_value ? "true" : "false");
+
+ case CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED:
+ return base::StringPrintf("DrawnStateChanged window=%s drawn=%s",
+ WindowIdToString(change.window_id).c_str(),
+ change.bool_value ? "true" : "false");
+
+ case CHANGE_TYPE_INPUT_EVENT: {
+ std::string result = base::StringPrintf(
+ "InputEvent window=%s event_action=%d",
+ WindowIdToString(change.window_id).c_str(), change.event_action);
+ if (change.matches_pointer_watcher)
+ result += " matches_pointer_watcher";
+ return result;
+ }
+
+ case CHANGE_TYPE_POINTER_WATCHER_EVENT:
+ return base::StringPrintf("PointerWatcherEvent event_action=%d window=%s",
+ change.event_action,
+ WindowIdToString(change.window_id).c_str());
+
+ case CHANGE_TYPE_PROPERTY_CHANGED:
+ return base::StringPrintf("PropertyChanged window=%s key=%s value=%s",
+ WindowIdToString(change.window_id).c_str(),
+ change.property_key.c_str(),
+ change.property_value.c_str());
+
+ case CHANGE_TYPE_FOCUSED:
+ return base::StringPrintf("Focused id=%s",
+ WindowIdToString(change.window_id).c_str());
+
+ case CHANGE_TYPE_CURSOR_CHANGED:
+ return base::StringPrintf("CursorChanged id=%s cursor_type=%d",
+ WindowIdToString(change.window_id).c_str(),
+ static_cast<int>(change.cursor_type));
+ case CHANGE_TYPE_ON_CHANGE_COMPLETED:
+ return base::StringPrintf("ChangeCompleted id=%d sucess=%s",
+ change.change_id,
+ change.bool_value ? "true" : "false");
+
+ case CHANGE_TYPE_ON_TOP_LEVEL_CREATED:
+ return base::StringPrintf("TopLevelCreated id=%d window_id=%s drawn=%s",
+ change.change_id,
+ WindowIdToString(change.window_id).c_str(),
+ change.bool_value ? "true" : "false");
+ case CHANGE_TYPE_OPACITY:
+ return base::StringPrintf("OpacityChanged window_id=%s opacity=%.2f",
+ WindowIdToString(change.window_id).c_str(),
+ change.float_value);
+ case CHANGE_TYPE_SURFACE_CHANGED:
+ return base::StringPrintf("SurfaceCreated window_id=%s surface_id=%s",
+ WindowIdToString(change.window_id).c_str(),
+ change.surface_id.ToString().c_str());
+ case CHANGE_TYPE_TRANSFORM_CHANGED:
+ return base::StringPrintf("TransformChanged window_id=%s",
+ WindowIdToString(change.window_id).c_str());
+ }
+ return std::string();
+}
+
+std::string SingleChangeToDescriptionImpl(const std::vector<Change>& changes,
+ ChangeDescriptionType change_type) {
+ std::string result;
+ for (auto& change : changes) {
+ if (!result.empty())
+ result += "\n";
+ result += ChangeToDescription(change, change_type);
+ }
+ return result;
+}
+
+} // namespace
+
+std::vector<std::string> ChangesToDescription1(
+ const std::vector<Change>& changes) {
+ std::vector<std::string> strings(changes.size());
+ for (size_t i = 0; i < changes.size(); ++i)
+ strings[i] = ChangeToDescription(changes[i], ChangeDescriptionType::ONE);
+ return strings;
+}
+
+std::string SingleChangeToDescription(const std::vector<Change>& changes) {
+ return SingleChangeToDescriptionImpl(changes, ChangeDescriptionType::ONE);
+}
+
+std::string SingleChangeToDescription2(const std::vector<Change>& changes) {
+ return SingleChangeToDescriptionImpl(changes, ChangeDescriptionType::TWO);
+}
+
+std::string SingleWindowDescription(const std::vector<TestWindow>& windows) {
+ if (windows.empty())
+ return "no windows";
+ std::string result;
+ for (const TestWindow& window : windows)
+ result += window.ToString();
+ return result;
+}
+
+std::string ChangeWindowDescription(const std::vector<Change>& changes) {
+ if (changes.size() != 1)
+ return std::string();
+ std::vector<std::string> window_strings(changes[0].windows.size());
+ for (size_t i = 0; i < changes[0].windows.size(); ++i)
+ window_strings[i] = "[" + changes[0].windows[i].ToString() + "]";
+ return base::JoinString(window_strings, ",");
+}
+
+TestWindow WindowDataToTestWindow(const mojom::WindowDataPtr& data) {
+ TestWindow window;
+ window.parent_id = data->parent_id;
+ window.window_id = data->window_id;
+ window.visible = data->visible;
+ window.properties = mojo::UnorderedMapToMap(data->properties);
+ return window;
+}
+
+void WindowDatasToTestWindows(const std::vector<mojom::WindowDataPtr>& data,
+ std::vector<TestWindow>* test_windows) {
+ for (size_t i = 0; i < data.size(); ++i)
+ test_windows->push_back(WindowDataToTestWindow(data[i]));
+}
+
+Change::Change()
+ : type(CHANGE_TYPE_EMBED),
+ window_id(0),
+ window_id2(0),
+ window_id3(0),
+ event_action(0),
+ matches_pointer_watcher(false),
+ direction(mojom::OrderDirection::ABOVE),
+ bool_value(false),
+ float_value(0.f),
+ cursor_type(ui::CursorType::kNull),
+ change_id(0u),
+ display_id(0) {}
+
+Change::Change(const Change& other) = default;
+
+Change::~Change() {}
+
+TestChangeTracker::TestChangeTracker() : delegate_(NULL) {}
+
+TestChangeTracker::~TestChangeTracker() {}
+
+void TestChangeTracker::OnEmbed(mojom::WindowDataPtr root, bool drawn) {
+ Change change;
+ change.type = CHANGE_TYPE_EMBED;
+ change.bool_value = drawn;
+ change.windows.push_back(WindowDataToTestWindow(root));
+ AddChange(change);
+}
+
+void TestChangeTracker::OnEmbeddedAppDisconnected(Id window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED;
+ change.window_id = window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowBoundsChanged(
+ Id window_id,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id) {
+ Change change;
+ change.type = CHANGE_TYPE_NODE_BOUNDS_CHANGED;
+ change.window_id = window_id;
+ change.bounds = old_bounds;
+ change.bounds2 = new_bounds;
+ change.local_surface_id = local_surface_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowTransformChanged(Id window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_TRANSFORM_CHANGED;
+ change.window_id = window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnUnembed(Id window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_UNEMBED;
+ change.window_id = window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnTransientWindowAdded(Id window_id,
+ Id transient_window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW;
+ change.window_id = window_id;
+ change.window_id2 = transient_window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnTransientWindowRemoved(Id window_id,
+ Id transient_window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT;
+ change.window_id = window_id;
+ change.window_id2 = transient_window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnCaptureChanged(Id new_capture_window_id,
+ Id old_capture_window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_CAPTURE_CHANGED;
+ change.window_id = new_capture_window_id;
+ change.window_id2 = old_capture_window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnFrameSinkIdAllocated(
+ Id window_id,
+ const viz::FrameSinkId& frame_sink_id) {
+ Change change;
+ change.type = CHANGE_TYPE_FRAME_SINK_ID_ALLOCATED;
+ change.window_id = window_id;
+ change.frame_sink_id = frame_sink_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowHierarchyChanged(
+ Id window_id,
+ Id old_parent_id,
+ Id new_parent_id,
+ std::vector<mojom::WindowDataPtr> windows) {
+ Change change;
+ change.type = CHANGE_TYPE_NODE_HIERARCHY_CHANGED;
+ change.window_id = window_id;
+ change.window_id2 = old_parent_id;
+ change.window_id3 = new_parent_id;
+ WindowDatasToTestWindows(windows, &change.windows);
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowReordered(Id window_id,
+ Id relative_window_id,
+ mojom::OrderDirection direction) {
+ Change change;
+ change.type = CHANGE_TYPE_NODE_REORDERED;
+ change.window_id = window_id;
+ change.window_id2 = relative_window_id;
+ change.direction = direction;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowDeleted(Id window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_NODE_DELETED;
+ change.window_id = window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowVisibilityChanged(Id window_id, bool visible) {
+ Change change;
+ change.type = CHANGE_TYPE_NODE_VISIBILITY_CHANGED;
+ change.window_id = window_id;
+ change.bool_value = visible;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowOpacityChanged(Id window_id, float opacity) {
+ Change change;
+ change.type = CHANGE_TYPE_OPACITY;
+ change.window_id = window_id;
+ change.float_value = opacity;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowParentDrawnStateChanged(Id window_id,
+ bool drawn) {
+ Change change;
+ change.type = CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED;
+ change.window_id = window_id;
+ change.bool_value = drawn;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowInputEvent(
+ Id window_id,
+ const ui::Event& event,
+ int64_t display_id,
+ const gfx::PointF& event_location_in_screen_pixel_layout,
+ bool matches_pointer_watcher) {
+ Change change;
+ change.type = CHANGE_TYPE_INPUT_EVENT;
+ change.window_id = window_id;
+ change.event_action = static_cast<int32_t>(event.type());
+ change.matches_pointer_watcher = matches_pointer_watcher;
+ change.display_id = display_id;
+ if (event.IsLocatedEvent())
+ change.location1 = event.AsLocatedEvent()->root_location();
+ change.location2 = event_location_in_screen_pixel_layout;
+ if (event.IsKeyEvent() && event.AsKeyEvent()->properties())
+ change.key_event_properties = *event.AsKeyEvent()->properties();
+ AddChange(change);
+}
+
+void TestChangeTracker::OnPointerEventObserved(const ui::Event& event,
+ uint32_t window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_POINTER_WATCHER_EVENT;
+ change.event_action = static_cast<int32_t>(event.type());
+ change.window_id = window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowSharedPropertyChanged(
+ Id window_id,
+ const std::string& name,
+ const base::Optional<std::vector<uint8_t>>& data) {
+ Change change;
+ change.type = CHANGE_TYPE_PROPERTY_CHANGED;
+ change.window_id = window_id;
+ change.property_key = name;
+ if (!data)
+ change.property_value = "NULL";
+ else
+ change.property_value.assign(data->begin(), data->end());
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowFocused(Id window_id) {
+ Change change;
+ change.type = CHANGE_TYPE_FOCUSED;
+ change.window_id = window_id;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowCursorChanged(Id window_id,
+ const ui::CursorData& cursor) {
+ Change change;
+ change.type = CHANGE_TYPE_CURSOR_CHANGED;
+ change.window_id = window_id;
+ change.cursor_type = cursor.cursor_type();
+ AddChange(change);
+}
+
+void TestChangeTracker::OnChangeCompleted(uint32_t change_id, bool success) {
+ Change change;
+ change.type = CHANGE_TYPE_ON_CHANGE_COMPLETED;
+ change.change_id = change_id;
+ change.bool_value = success;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnTopLevelCreated(uint32_t change_id,
+ mojom::WindowDataPtr window_data,
+ bool drawn) {
+ Change change;
+ change.type = CHANGE_TYPE_ON_TOP_LEVEL_CREATED;
+ change.change_id = change_id;
+ change.window_id = window_data->window_id;
+ change.bool_value = drawn;
+ AddChange(change);
+}
+
+void TestChangeTracker::OnWindowSurfaceChanged(
+ Id window_id,
+ const viz::SurfaceInfo& surface_info) {
+ Change change;
+ change.type = CHANGE_TYPE_SURFACE_CHANGED;
+ change.window_id = window_id;
+ change.surface_id = surface_info.id();
+ change.frame_size = surface_info.size_in_pixels();
+ change.device_scale_factor = surface_info.device_scale_factor();
+ AddChange(change);
+}
+
+void TestChangeTracker::AddChange(const Change& change) {
+ changes_.push_back(change);
+ if (delegate_)
+ delegate_->OnChangeAdded();
+}
+
+TestWindow::TestWindow() {}
+
+TestWindow::TestWindow(const TestWindow& other) = default;
+
+TestWindow::~TestWindow() {}
+
+std::string TestWindow::ToString() const {
+ return base::StringPrintf("window=%s parent=%s",
+ WindowIdToString(window_id).c_str(),
+ WindowIdToString(parent_id).c_str());
+}
+
+std::string TestWindow::ToString2() const {
+ return base::StringPrintf(
+ "window=%s parent=%s visible=%s", WindowIdToString(window_id).c_str(),
+ WindowIdToString(parent_id).c_str(), visible ? "true" : "false");
+}
+
+} // namespace ws
+
+} // namespace ui
diff --git a/chromium/services/ui/ws2/test_change_tracker.h b/chromium/services/ui/ws2/test_change_tracker.h
new file mode 100644
index 00000000000..3d8a8ab371a
--- /dev/null
+++ b/chromium/services/ui/ws2/test_change_tracker.h
@@ -0,0 +1,210 @@
+// 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.
+
+#ifndef SERVICES_UI_WS2_TEST_CHANGE_TRACKER_H_
+#define SERVICES_UI_WS2_TEST_CHANGE_TRACKER_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "base/macros.h"
+#include "services/ui/common/types.h"
+#include "services/ui/public/interfaces/window_tree.mojom.h"
+#include "ui/gfx/geometry/mojo/geometry.mojom.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace ui {
+
+namespace ws {
+
+enum ChangeType {
+ CHANGE_TYPE_CAPTURE_CHANGED,
+ CHANGE_TYPE_FRAME_SINK_ID_ALLOCATED,
+ CHANGE_TYPE_EMBED,
+ CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED,
+ CHANGE_TYPE_UNEMBED,
+ // TODO(sky): nuke NODE.
+ CHANGE_TYPE_NODE_ADD_TRANSIENT_WINDOW,
+ CHANGE_TYPE_NODE_BOUNDS_CHANGED,
+ CHANGE_TYPE_NODE_HIERARCHY_CHANGED,
+ CHANGE_TYPE_NODE_REMOVE_TRANSIENT_WINDOW_FROM_PARENT,
+ CHANGE_TYPE_NODE_REORDERED,
+ CHANGE_TYPE_NODE_VISIBILITY_CHANGED,
+ CHANGE_TYPE_NODE_DRAWN_STATE_CHANGED,
+ CHANGE_TYPE_NODE_DELETED,
+ CHANGE_TYPE_INPUT_EVENT,
+ CHANGE_TYPE_POINTER_WATCHER_EVENT,
+ CHANGE_TYPE_PROPERTY_CHANGED,
+ CHANGE_TYPE_FOCUSED,
+ CHANGE_TYPE_CURSOR_CHANGED,
+ CHANGE_TYPE_ON_CHANGE_COMPLETED,
+ CHANGE_TYPE_ON_TOP_LEVEL_CREATED,
+ CHANGE_TYPE_OPACITY,
+ CHANGE_TYPE_SURFACE_CHANGED,
+ CHANGE_TYPE_TRANSFORM_CHANGED,
+};
+
+// TODO(sky): consider nuking and converting directly to WindowData.
+struct TestWindow {
+ TestWindow();
+ TestWindow(const TestWindow& other);
+ ~TestWindow();
+
+ // Returns a string description of this.
+ std::string ToString() const;
+
+ // Returns a string description that includes visible and drawn.
+ std::string ToString2() const;
+
+ Id parent_id;
+ Id window_id;
+ bool visible;
+ std::map<std::string, std::vector<uint8_t>> properties;
+};
+
+// Tracks a call to WindowTreeClient. See the individual functions for the
+// fields that are used.
+struct Change {
+ Change();
+ Change(const Change& other);
+ ~Change();
+
+ ChangeType type;
+ std::vector<TestWindow> windows;
+ Id window_id;
+ Id window_id2;
+ Id window_id3;
+ gfx::Rect bounds;
+ gfx::Rect bounds2;
+ viz::FrameSinkId frame_sink_id;
+ base::Optional<viz::LocalSurfaceId> local_surface_id;
+ int32_t event_action;
+ bool matches_pointer_watcher;
+ std::string embed_url;
+ mojom::OrderDirection direction;
+ bool bool_value;
+ float float_value;
+ std::string property_key;
+ std::string property_value;
+ ui::CursorType cursor_type;
+ uint32_t change_id;
+ viz::SurfaceId surface_id;
+ gfx::Size frame_size;
+ float device_scale_factor;
+ gfx::Transform transform;
+ // Set in OnWindowInputEvent() if the event is a KeyEvent.
+ std::unordered_map<std::string, std::vector<uint8_t>> key_event_properties;
+ int64_t display_id;
+ gfx::Point location1;
+ gfx::PointF location2;
+};
+
+// Converts Changes to string descriptions.
+std::vector<std::string> ChangesToDescription1(
+ const std::vector<Change>& changes);
+
+// Convenience for returning the description of the first item in |changes|.
+// Returns an empty string if |changes| has something other than one entry.
+std::string SingleChangeToDescription(const std::vector<Change>& changes);
+std::string SingleChangeToDescription2(const std::vector<Change>& changes);
+
+// Convenience for returning the description of the first item in |windows|.
+// Returns an empty string if |windows| has something other than one entry.
+std::string SingleWindowDescription(const std::vector<TestWindow>& windows);
+
+// Returns a string description of |changes[0].windows|. Returns an empty string
+// if change.size() != 1.
+std::string ChangeWindowDescription(const std::vector<Change>& changes);
+
+// Converts WindowDatas to TestWindows.
+void WindowDatasToTestWindows(const std::vector<mojom::WindowDataPtr>& data,
+ std::vector<TestWindow>* test_windows);
+
+// TestChangeTracker is used to record WindowTreeClient functions. It notifies
+// a delegate any time a change is added.
+class TestChangeTracker {
+ public:
+ // Used to notify the delegate when a change is added. A change corresponds to
+ // a single WindowTreeClient function.
+ class Delegate {
+ public:
+ virtual void OnChangeAdded() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ TestChangeTracker();
+ ~TestChangeTracker();
+
+ void set_delegate(Delegate* delegate) { delegate_ = delegate; }
+
+ std::vector<Change>* changes() { return &changes_; }
+
+ // Each of these functions generate a Change. There is one per
+ // WindowTreeClient function.
+ void OnEmbed(mojom::WindowDataPtr root, bool drawn);
+ void OnEmbeddedAppDisconnected(Id window_id);
+ void OnUnembed(Id window_id);
+ void OnCaptureChanged(Id new_capture_window_id, Id old_capture_window_id);
+ void OnFrameSinkIdAllocated(Id window_id,
+ const viz::FrameSinkId& frame_sink_id);
+ void OnTransientWindowAdded(Id window_id, Id transient_window_id);
+ void OnTransientWindowRemoved(Id window_id, Id transient_window_id);
+ void OnWindowBoundsChanged(
+ Id window_id,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id);
+ void OnWindowTransformChanged(Id window_id);
+ void OnWindowHierarchyChanged(Id window_id,
+ Id old_parent_id,
+ Id new_parent_id,
+ std::vector<mojom::WindowDataPtr> windows);
+ void OnWindowReordered(Id window_id,
+ Id relative_window_id,
+ mojom::OrderDirection direction);
+ void OnWindowDeleted(Id window_id);
+ void OnWindowVisibilityChanged(Id window_id, bool visible);
+ void OnWindowOpacityChanged(Id window_id, float opacity);
+ void OnWindowParentDrawnStateChanged(Id window_id, bool drawn);
+ void OnWindowInputEvent(
+ Id window_id,
+ const ui::Event& event,
+ int64_t display_id,
+ const gfx::PointF& event_location_in_screen_pixel_layout,
+ bool matches_pointer_watcher);
+ void OnPointerEventObserved(const ui::Event& event,
+ uint32_t window_id);
+ void OnWindowSharedPropertyChanged(
+ Id window_id,
+ const std::string& name,
+ const base::Optional<std::vector<uint8_t>>& data);
+ void OnWindowFocused(Id window_id);
+ void OnWindowCursorChanged(Id window_id, const ui::CursorData& cursor);
+ void OnChangeCompleted(uint32_t change_id, bool success);
+ void OnTopLevelCreated(uint32_t change_id,
+ mojom::WindowDataPtr window_data,
+ bool drawn);
+ void OnWindowSurfaceChanged(Id window_id,
+ const viz::SurfaceInfo& surface_info);
+
+ private:
+ void AddChange(const Change& change);
+
+ Delegate* delegate_;
+ std::vector<Change> changes_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestChangeTracker);
+};
+
+} // namespace ws
+
+} // namespace ui
+
+#endif // SERVICES_UI_WS2_TEST_CHANGE_TRACKER_H_
diff --git a/chromium/services/ui/ws2/test_manifest.json b/chromium/services/ui/ws2/test_manifest.json
new file mode 100644
index 00000000000..71ffecbc5c2
--- /dev/null
+++ b/chromium/services/ui/ws2/test_manifest.json
@@ -0,0 +1,22 @@
+{
+ "name": "ui_service_unittests",
+ "display_name": "Mus Window Server Unittests",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "ui:window_tree_client": [
+ "ui::mojom::WindowTreeClient"
+ ]
+ },
+ "requires": {
+ "*": [ "app" ],
+ "ui_service_unittests": [ "ui:window_tree_client" ],
+ "ui": [
+ "window_manager",
+ "window_tree_host_factory"
+ ],
+ "viz": [ "viz_host" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/ui/ws2/window_tree_client_unittest.cc b/chromium/services/ui/ws2/window_tree_client_unittest.cc
new file mode 100644
index 00000000000..2f16ed877e8
--- /dev/null
+++ b/chromium/services/ui/ws2/window_tree_client_unittest.cc
@@ -0,0 +1,2525 @@
+// 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 <stddef.h>
+#include <stdint.h>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "components/viz/common/surfaces/parent_local_surface_id_allocator.h"
+#include "mojo/public/cpp/bindings/associated_binding.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/service_test.h"
+#include "services/ui/public/interfaces/constants.mojom.h"
+#include "services/ui/public/interfaces/window_tree.mojom.h"
+#include "services/ui/public/interfaces/window_tree_host_factory.mojom.h"
+#include "services/ui/ws/ids.h"
+#include "services/ui/ws/test_change_tracker.h"
+#include "services/ui/ws/window_server_service_test_base.h"
+#include "ui/base/cursor/cursor.h"
+
+using mojo::InterfaceRequest;
+using service_manager::Service;
+using ui::mojom::WindowDataPtr;
+using ui::mojom::WindowTree;
+using ui::mojom::WindowTreeClient;
+
+namespace ui {
+namespace ws {
+namespace test {
+
+namespace {
+
+// Creates an id used for transport from the specified parameters.
+Id BuildWindowId(ClientSpecificId client_id,
+ ClientSpecificId window_id) {
+ return (client_id << 16) | window_id;
+}
+
+// Callback function from WindowTree functions.
+// ----------------------------------
+
+void WindowTreeResultCallback(base::RunLoop* run_loop,
+ std::vector<TestWindow>* windows,
+ std::vector<WindowDataPtr> results) {
+ WindowDatasToTestWindows(results, windows);
+ run_loop->Quit();
+}
+
+void EmbedCallbackImpl(base::RunLoop* run_loop,
+ bool* result_cache,
+ bool result) {
+ *result_cache = result;
+ run_loop->Quit();
+}
+
+void ScheduleEmbedCallbackImpl(base::RunLoop* run_loop,
+ base::UnguessableToken* resulting_token,
+ const base::UnguessableToken& token) {
+ *resulting_token = token;
+ run_loop->Quit();
+}
+
+// -----------------------------------------------------------------------------
+
+bool EmbedUrl(service_manager::Connector* connector,
+ WindowTree* tree,
+ const std::string& url,
+ Id root_id) {
+ bool result = false;
+ base::RunLoop run_loop;
+ {
+ mojom::WindowTreeClientPtr client;
+ connector->BindInterface(url, &client);
+ const uint32_t embed_flags = 0;
+ tree->Embed(root_id, std::move(client), embed_flags,
+ base::Bind(&EmbedCallbackImpl, &run_loop, &result));
+ }
+ run_loop.Run();
+ return result;
+}
+
+bool Embed(WindowTree* tree, Id root_id, mojom::WindowTreeClientPtr client) {
+ bool result = false;
+ base::RunLoop run_loop;
+ {
+ const uint32_t embed_flags = 0;
+ tree->Embed(root_id, std::move(client), embed_flags,
+ base::Bind(&EmbedCallbackImpl, &run_loop, &result));
+ }
+ run_loop.Run();
+ return result;
+}
+
+bool EmbedUsingToken(WindowTree* tree,
+ Id root_id,
+ const base::UnguessableToken& token) {
+ bool result = false;
+ base::RunLoop run_loop;
+ const uint32_t embed_flags = 0;
+ tree->EmbedUsingToken(root_id, token, embed_flags,
+ base::Bind(&EmbedCallbackImpl, &run_loop, &result));
+ run_loop.Run();
+ return result;
+}
+
+void ScheduleEmbed(WindowTree* tree,
+ mojom::WindowTreeClientPtr client,
+ base::UnguessableToken* token) {
+ base::RunLoop run_loop;
+ tree->ScheduleEmbed(std::move(client),
+ base::Bind(&ScheduleEmbedCallbackImpl, &run_loop, token));
+ run_loop.Run();
+}
+
+void GetWindowTree(WindowTree* tree,
+ Id window_id,
+ std::vector<TestWindow>* windows) {
+ base::RunLoop run_loop;
+ tree->GetWindowTree(
+ window_id, base::Bind(&WindowTreeResultCallback, &run_loop, windows));
+ run_loop.Run();
+}
+
+// Utility functions -----------------------------------------------------------
+
+const Id kNullParentId = 0;
+std::string IdToString(Id id) {
+ return (id == kNullParentId) ? "null" : base::StringPrintf(
+ "%d,%d", HiWord(id), LoWord(id));
+}
+
+std::string WindowParentToString(Id window, Id parent) {
+ return base::StringPrintf("window=%s parent=%s", IdToString(window).c_str(),
+ IdToString(parent).c_str());
+}
+
+// -----------------------------------------------------------------------------
+
+// A WindowTreeClient implementation that logs all changes to a tracker.
+class TestWindowTreeClient : public mojom::WindowTreeClient,
+ public TestChangeTracker::Delegate,
+ public mojom::WindowManager {
+ public:
+ TestWindowTreeClient()
+ : binding_(this),
+ root_window_id_(0),
+ // Start with a random large number so tests can use lower ids if they
+ // want.
+ next_change_id_(10000),
+ waiting_change_id_(0),
+ on_change_completed_result_(false),
+ track_root_bounds_changes_(false) {
+ tracker_.set_delegate(this);
+ }
+
+ void Bind(mojo::InterfaceRequest<mojom::WindowTreeClient> request) {
+ binding_.Bind(std::move(request));
+ }
+
+ mojom::WindowTree* tree() { return tree_.get(); }
+ TestChangeTracker* tracker() { return &tracker_; }
+ Id root_window_id() const { return root_window_id_; }
+
+ // Sets whether changes to the bounds of the root should be tracked. Normally
+ // they are ignored (as during startup we often times get random size
+ // changes).
+ void set_track_root_bounds_changes(bool value) {
+ track_root_bounds_changes_ = value;
+ }
+
+ // Runs a nested MessageLoop until |count| changes (calls to
+ // WindowTreeClient functions) have been received.
+ void WaitForChangeCount(size_t count) {
+ if (tracker_.changes()->size() >= count)
+ return;
+
+ ASSERT_TRUE(wait_state_.get() == nullptr);
+ wait_state_ = std::make_unique<WaitState>();
+ wait_state_->change_count = count;
+ wait_state_->run_loop.Run();
+ wait_state_.reset();
+ }
+
+ uint32_t GetAndAdvanceChangeId() { return next_change_id_++; }
+
+ // Runs a nested MessageLoop until OnEmbed() has been encountered.
+ void WaitForOnEmbed() {
+ if (tree_)
+ return;
+ embed_run_loop_ = std::make_unique<base::RunLoop>();
+ embed_run_loop_->Run();
+ embed_run_loop_.reset();
+ }
+
+ bool WaitForChangeCompleted(uint32_t id) {
+ waiting_change_id_ = id;
+ change_completed_run_loop_ = std::make_unique<base::RunLoop>();
+ change_completed_run_loop_->Run();
+ return on_change_completed_result_;
+ }
+
+ bool DeleteWindow(Id id) {
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->DeleteWindow(change_id, id);
+ return WaitForChangeCompleted(change_id);
+ }
+
+ bool AddWindow(Id parent, Id child) {
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->AddWindow(change_id, parent, child);
+ return WaitForChangeCompleted(change_id);
+ }
+
+ bool RemoveWindowFromParent(Id window_id) {
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->RemoveWindowFromParent(change_id, window_id);
+ return WaitForChangeCompleted(change_id);
+ }
+
+ bool ReorderWindow(Id window_id,
+ Id relative_window_id,
+ mojom::OrderDirection direction) {
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->ReorderWindow(change_id, window_id, relative_window_id, direction);
+ return WaitForChangeCompleted(change_id);
+ }
+
+ // Waits for all messages to be received by |ws|. This is done by attempting
+ // to set opacity on an embed/invalid window. 1.0f is the default opacity
+ // value. When we get the response we know all messages have been processed.
+ bool WaitForAllMessages() { return !SetWindowOpacity(0, 1.0f); }
+
+ Id NewWindow(ClientSpecificId window_id) {
+ return NewWindowWithCompleteId(window_id);
+ }
+
+ // Generally you want NewWindow(), but use this if you need to test given
+ // a complete window id (NewWindow() ors with the client id).
+ Id NewWindowWithCompleteId(Id id) {
+ std::unordered_map<std::string, std::vector<uint8_t>> properties;
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->NewWindow(change_id, id, std::move(properties));
+ return WaitForChangeCompleted(change_id) ? id : 0;
+ }
+
+ bool SetWindowProperty(Id window_id,
+ const std::string& name,
+ const std::vector<uint8_t>* data) {
+ base::Optional<std::vector<uint8_t>> mojo_data;
+ if (data)
+ mojo_data.emplace(*data);
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->SetWindowProperty(change_id, window_id, name, mojo_data);
+ return WaitForChangeCompleted(change_id);
+ }
+
+ bool SetCursor(Id window_id, const ui::CursorData& cursor) {
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->SetCursor(change_id, window_id, cursor);
+ return WaitForChangeCompleted(change_id);
+ }
+
+ bool SetWindowVisibility(Id window_id, bool visible) {
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->SetWindowVisibility(change_id, window_id, visible);
+ return WaitForChangeCompleted(change_id);
+ }
+
+ bool SetWindowOpacity(Id window_id, float opacity) {
+ const uint32_t change_id = GetAndAdvanceChangeId();
+ tree()->SetWindowOpacity(change_id, window_id, opacity);
+ return WaitForChangeCompleted(change_id);
+ }
+
+ private:
+ // Used when running a nested MessageLoop.
+ struct WaitState {
+ WaitState() : change_count(0) {}
+
+ // Number of changes waiting for.
+ size_t change_count;
+ base::RunLoop run_loop;
+ };
+
+ // TestChangeTracker::Delegate:
+ void OnChangeAdded() override {
+ if (wait_state_.get() &&
+ tracker_.changes()->size() >= wait_state_->change_count) {
+ wait_state_->run_loop.Quit();
+ }
+ }
+
+ // WindowTreeClient:
+ void OnEmbed(
+ WindowDataPtr root,
+ mojom::WindowTreePtr tree,
+ int64_t display_id,
+ Id focused_window_id,
+ bool drawn,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id) override {
+ // TODO(sky): add coverage of |focused_window_id|.
+ ASSERT_TRUE(root);
+ root_window_id_ = root->window_id;
+ tree_ = std::move(tree);
+ tracker()->OnEmbed(std::move(root), drawn);
+ if (embed_run_loop_)
+ embed_run_loop_->Quit();
+ }
+ void OnEmbeddedAppDisconnected(Id window_id) override {
+ tracker()->OnEmbeddedAppDisconnected(window_id);
+ }
+ void OnUnembed(Id window_id) override { tracker()->OnUnembed(window_id); }
+ void OnCaptureChanged(Id new_capture_window_id,
+ Id old_capture_window_id) override {
+ tracker()->OnCaptureChanged(new_capture_window_id, old_capture_window_id);
+ }
+ void OnFrameSinkIdAllocated(Id window_id,
+ const viz::FrameSinkId& frame_sink_id) override {}
+ void OnTopLevelCreated(
+ uint32_t change_id,
+ mojom::WindowDataPtr data,
+ int64_t display_id,
+ bool drawn,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id) override {
+ tracker()->OnTopLevelCreated(change_id, std::move(data), drawn);
+ }
+ void OnWindowBoundsChanged(
+ Id window_id,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id) override {
+ // The bounds of the root may change during startup on Android at random
+ // times. As this doesn't matter, and shouldn't impact test exepctations,
+ // it is ignored.
+ if (window_id == root_window_id_ && !track_root_bounds_changes_)
+ return;
+ tracker()->OnWindowBoundsChanged(window_id, old_bounds, new_bounds,
+ local_surface_id);
+ }
+ void OnWindowTransformChanged(Id window_id,
+ const gfx::Transform& old_transform,
+ const gfx::Transform& new_transform) override {
+ tracker()->OnWindowTransformChanged(window_id);
+ }
+ void OnClientAreaChanged(
+ uint32_t window_id,
+ const gfx::Insets& new_client_area,
+ const std::vector<gfx::Rect>& new_additional_client_areas) override {}
+ void OnTransientWindowAdded(uint32_t window_id,
+ uint32_t transient_window_id) override {
+ tracker()->OnTransientWindowAdded(window_id, transient_window_id);
+ }
+ void OnTransientWindowRemoved(uint32_t window_id,
+ uint32_t transient_window_id) override {
+ tracker()->OnTransientWindowRemoved(window_id, transient_window_id);
+ }
+ void OnWindowHierarchyChanged(Id window,
+ Id old_parent,
+ Id new_parent,
+ std::vector<WindowDataPtr> windows) override {
+ tracker()->OnWindowHierarchyChanged(window, old_parent, new_parent,
+ std::move(windows));
+ }
+ void OnWindowReordered(Id window_id,
+ Id relative_window_id,
+ mojom::OrderDirection direction) override {
+ tracker()->OnWindowReordered(window_id, relative_window_id, direction);
+ }
+ void OnWindowDeleted(Id window) override {
+ tracker()->OnWindowDeleted(window);
+ }
+ void OnWindowVisibilityChanged(uint32_t window, bool visible) override {
+ tracker()->OnWindowVisibilityChanged(window, visible);
+ }
+ void OnWindowOpacityChanged(uint32_t window,
+ float old_opacity,
+ float new_opacity) override {
+ tracker()->OnWindowOpacityChanged(window, new_opacity);
+ }
+ void OnWindowParentDrawnStateChanged(uint32_t window, bool drawn) override {
+ tracker()->OnWindowParentDrawnStateChanged(window, drawn);
+ }
+ void OnWindowInputEvent(
+ uint32_t event_id,
+ Id window_id,
+ int64_t display_id,
+ Id display_root_window_id,
+ const gfx::PointF& event_location_in_screen_pixel_layout,
+ std::unique_ptr<ui::Event> event,
+ bool matches_pointer_watcher) override {
+ // Ack input events to clear the state on the server. These can be received
+ // during test startup. X11Window::DispatchEvent sends a synthetic move
+ // event to notify of entry.
+ tree()->OnWindowInputEventAck(event_id, mojom::EventResult::HANDLED);
+ // Don't log input events as none of the tests care about them and they
+ // may come in at random points.
+ }
+ void OnPointerEventObserved(std::unique_ptr<ui::Event>,
+ uint32_t window_id,
+ int64_t display_id) override {}
+ void OnWindowSharedPropertyChanged(
+ uint32_t window,
+ const std::string& name,
+ const base::Optional<std::vector<uint8_t>>& new_data) override {
+ tracker_.OnWindowSharedPropertyChanged(window, name, new_data);
+ }
+ // TODO(sky): add testing coverage.
+ void OnWindowFocused(uint32_t focused_window_id) override {}
+ void OnWindowCursorChanged(uint32_t window_id,
+ ui::CursorData cursor) override {
+ tracker_.OnWindowCursorChanged(window_id, cursor);
+ }
+
+ void OnDragDropStart(
+ const std::unordered_map<std::string, std::vector<uint8_t>>& drag_data)
+ override {
+ NOTIMPLEMENTED();
+ }
+
+ void OnWindowSurfaceChanged(Id window_id,
+ const viz::SurfaceInfo& surface_info) override {
+ tracker_.OnWindowSurfaceChanged(window_id, surface_info);
+ }
+
+ void OnDragEnter(uint32_t window,
+ uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect_bitmask,
+ const OnDragEnterCallback& callback) override {
+ NOTIMPLEMENTED();
+ }
+ void OnDragOver(uint32_t window,
+ uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect_bitmask,
+ const OnDragOverCallback& callback) override {
+ NOTIMPLEMENTED();
+ }
+ void OnDragLeave(uint32_t window) override { NOTIMPLEMENTED(); }
+ void OnCompleteDrop(uint32_t window,
+ uint32_t key_state,
+ const gfx::Point& position,
+ uint32_t effect_bitmask,
+ const OnCompleteDropCallback& callback) override {
+ NOTIMPLEMENTED();
+ }
+
+ void OnPerformDragDropCompleted(uint32_t change_id,
+ bool success,
+ uint32_t action_taken) override {
+ NOTIMPLEMENTED();
+ }
+
+ void OnDragDropDone() override { NOTIMPLEMENTED(); }
+
+ void OnChangeCompleted(uint32_t change_id, bool success) override {
+ if (waiting_change_id_ == change_id && change_completed_run_loop_) {
+ on_change_completed_result_ = success;
+ change_completed_run_loop_->Quit();
+ }
+ }
+ void RequestClose(uint32_t window_id) override {}
+ void GetWindowManager(mojo::AssociatedInterfaceRequest<mojom::WindowManager>
+ internal) override {
+ window_manager_binding_ =
+ std::make_unique<mojo::AssociatedBinding<mojom::WindowManager>>(
+ this, std::move(internal));
+ tree_->GetWindowManagerClient(MakeRequest(&window_manager_client_));
+ }
+
+ // mojom::WindowManager:
+ void OnConnect() override {}
+ void WmOnAcceleratedWidgetForDisplay(
+ int64_t display,
+ gpu::SurfaceHandle surface_handle) override {}
+ void WmNewDisplayAdded(
+ const display::Display& display,
+ mojom::WindowDataPtr root_data,
+ bool drawn,
+ const base::Optional<viz::LocalSurfaceId>& local_surface_id) override {
+ NOTIMPLEMENTED();
+ }
+ void WmDisplayRemoved(int64_t display_id) override { NOTIMPLEMENTED(); }
+ void WmDisplayModified(const display::Display& display) override {
+ NOTIMPLEMENTED();
+ }
+ void WmSetBounds(uint32_t change_id,
+ uint32_t window_id,
+ const gfx::Rect& bounds) override {
+ window_manager_client_->WmResponse(change_id, false);
+ }
+ void WmSetProperty(
+ uint32_t change_id,
+ uint32_t window_id,
+ const std::string& name,
+ const base::Optional<std::vector<uint8_t>>& value) override {
+ window_manager_client_->WmResponse(change_id, false);
+ }
+ void WmSetModalType(uint32_t window_id, ui::ModalType type) override {}
+ void WmSetCanFocus(uint32_t window_id, bool can_focus) override {}
+ void WmCreateTopLevelWindow(
+ uint32_t change_id,
+ const viz::FrameSinkId& frame_sink_id,
+ const std::unordered_map<std::string, std::vector<uint8_t>>& properties)
+ override {
+ NOTIMPLEMENTED();
+ }
+ void WmClientJankinessChanged(ClientSpecificId client_id,
+ bool janky) override {
+ NOTIMPLEMENTED();
+ }
+ void WmBuildDragImage(const gfx::Point& screen_location,
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ ui::mojom::PointerKind source) override {}
+ void WmMoveDragImage(const gfx::Point& screen_location,
+ const WmMoveDragImageCallback& callback) override {
+ callback.Run();
+ }
+ void WmDestroyDragImage() override {}
+ void WmPerformMoveLoop(uint32_t change_id,
+ uint32_t window_id,
+ mojom::MoveLoopSource source,
+ const gfx::Point& cursor_location) override {
+ NOTIMPLEMENTED();
+ }
+ void WmCancelMoveLoop(uint32_t change_id) override { NOTIMPLEMENTED(); }
+ void WmDeactivateWindow(uint32_t window_id) override { NOTIMPLEMENTED(); }
+ void WmStackAbove(uint32_t change_id, uint32_t above_id,
+ uint32_t below_id) override {
+ NOTIMPLEMENTED();
+ }
+ void WmStackAtTop(uint32_t change_id, uint32_t window_id) override {
+ NOTIMPLEMENTED();
+ }
+ void WmPerformWmAction(uint32_t window_id,
+ const std::string& action) override {
+ NOTIMPLEMENTED();
+ }
+ void OnAccelerator(uint32_t ack_id,
+ uint32_t accelerator_id,
+ std::unique_ptr<ui::Event> event) override {
+ NOTIMPLEMENTED();
+ }
+ void OnCursorTouchVisibleChanged(bool enabled) override { NOTIMPLEMENTED(); }
+ void OnEventBlockedByModalWindow(uint32_t window_id) override {
+ NOTIMPLEMENTED();
+ }
+
+ TestChangeTracker tracker_;
+
+ mojom::WindowTreePtr tree_;
+
+ // If non-null we're waiting for OnEmbed() using this RunLoop.
+ std::unique_ptr<base::RunLoop> embed_run_loop_;
+
+ // If non-null we're waiting for a certain number of change notifications to
+ // be encountered.
+ std::unique_ptr<WaitState> wait_state_;
+
+ mojo::Binding<WindowTreeClient> binding_;
+ Id root_window_id_;
+ uint32_t next_change_id_;
+ uint32_t waiting_change_id_;
+ bool on_change_completed_result_;
+ bool track_root_bounds_changes_;
+ std::unique_ptr<base::RunLoop> change_completed_run_loop_;
+
+ std::unique_ptr<mojo::AssociatedBinding<mojom::WindowManager>>
+ window_manager_binding_;
+ mojom::WindowManagerClientAssociatedPtr window_manager_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestWindowTreeClient);
+};
+
+// -----------------------------------------------------------------------------
+
+// InterfaceFactory for vending TestWindowTreeClients.
+class WindowTreeClientFactory {
+ public:
+ WindowTreeClientFactory() {}
+ ~WindowTreeClientFactory() {}
+
+ // Runs a nested MessageLoop until a new instance has been created.
+ std::unique_ptr<TestWindowTreeClient> WaitForInstance() {
+ if (!client_impl_.get()) {
+ DCHECK(!run_loop_);
+ run_loop_ = std::make_unique<base::RunLoop>();
+ run_loop_->Run();
+ run_loop_.reset();
+ }
+ return std::move(client_impl_);
+ }
+
+ void BindWindowTreeClientRequest(
+ mojom::WindowTreeClientRequest request) {
+ client_impl_ = std::make_unique<TestWindowTreeClient>();
+ client_impl_->Bind(std::move(request));
+ if (run_loop_.get())
+ run_loop_->Quit();
+ }
+
+ private:
+ std::unique_ptr<TestWindowTreeClient> client_impl_;
+ std::unique_ptr<base::RunLoop> run_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeClientFactory);
+};
+
+} // namespace
+
+class WindowTreeClientTest : public WindowServerServiceTestBase {
+ public:
+ WindowTreeClientTest() : root_window_id_(0) {}
+
+ ~WindowTreeClientTest() override {}
+
+ protected:
+ // Returns the changes from the various clients.
+ std::vector<Change>* changes1() { return wt_client1_->tracker()->changes(); }
+ std::vector<Change>* changes2() { return wt_client2_->tracker()->changes(); }
+ std::vector<Change>* changes3() { return wt_client3_->tracker()->changes(); }
+
+ // Various clients. |wt1()|, being the first client, has special permissions
+ // (it's treated as the window manager).
+ WindowTree* wt1() { return wt_client1_->tree(); }
+ WindowTree* wt2() { return wt_client2_->tree(); }
+ WindowTree* wt3() { return wt_client3_->tree(); }
+
+ TestWindowTreeClient* wt_client1() { return wt_client1_.get(); }
+ TestWindowTreeClient* wt_client2() { return wt_client2_.get(); }
+ TestWindowTreeClient* wt_client3() { return wt_client3_.get(); }
+
+ Id root_window_id() const { return root_window_id_; }
+
+ int client_id_1() const { return client_id_1_; }
+ int client_id_2() const { return client_id_2_; }
+ int client_id_3() const { return client_id_3_; }
+
+ void EstablishSecondClientWithRoot(Id root_id) {
+ ASSERT_TRUE(wt_client2_.get() == nullptr);
+ wt_client2_ = EstablishClientViaEmbed(wt1(), root_id);
+ ASSERT_GT(client_id_2_, 0);
+ ASSERT_TRUE(wt_client2_.get() != nullptr);
+ }
+
+ void EstablishSecondClient(bool create_initial_window) {
+ Id window_1_1 = 0;
+ if (create_initial_window) {
+ window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+ }
+ ASSERT_NO_FATAL_FAILURE(
+ EstablishSecondClientWithRoot(BuildWindowId(client_id_1(), 1)));
+
+ if (create_initial_window) {
+ // window_1_1 is created by wt_client1() so its client_id part should be
+ // client_id_1() in wt_client2.
+ EXPECT_EQ("[" +
+ WindowParentToString(
+ BuildWindowId(client_id_1(), LoWord(window_1_1)),
+ kNullParentId) +
+ "]",
+ ChangeWindowDescription(*changes2()));
+ }
+ }
+
+ void EstablishThirdClient(WindowTree* owner, Id root_id) {
+ ASSERT_TRUE(wt_client3_.get() == nullptr);
+ wt_client3_ = EstablishClientViaEmbed(owner, root_id);
+ ASSERT_TRUE(wt_client3_.get() != nullptr);
+ }
+
+ std::unique_ptr<TestWindowTreeClient> WaitForWindowTreeClient() {
+ return client_factory_->WaitForInstance();
+ }
+
+ // Establishes a new client by way of Embed() on the specified WindowTree.
+ std::unique_ptr<TestWindowTreeClient> EstablishClientViaEmbed(
+ WindowTree* owner,
+ Id root_id) {
+ return EstablishClientViaEmbedWithPolicyBitmask(owner, root_id);
+ }
+
+ std::unique_ptr<TestWindowTreeClient>
+ EstablishClientViaEmbedWithPolicyBitmask(WindowTree* owner, Id root_id) {
+ if (!EmbedUrl(connector(), owner, test_name(), root_id)) {
+ ADD_FAILURE() << "Embed() failed";
+ return nullptr;
+ }
+ std::unique_ptr<TestWindowTreeClient> client =
+ client_factory_->WaitForInstance();
+ if (!client.get()) {
+ ADD_FAILURE() << "WaitForInstance failed";
+ return nullptr;
+ }
+ client->WaitForOnEmbed();
+
+ // TODO(fsamuel): Currently the FrameSinkId maps directly to the server's
+ // window ID. This is likely bad from a security perspective and should be
+ // fixed.
+ EXPECT_EQ("OnEmbed",
+ SingleChangeToDescription(*client->tracker()->changes()));
+ return client;
+ }
+
+ // WindowServerServiceTestBase:
+ void OnBindInterface(const service_manager::BindSourceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
+ registry_.BindInterface(interface_name, std::move(interface_pipe));
+ }
+
+ void SetUp() override {
+ client_factory_ = std::make_unique<WindowTreeClientFactory>();
+ registry_.AddInterface(
+ base::Bind(&WindowTreeClientFactory::BindWindowTreeClientRequest,
+ base::Unretained(client_factory_.get())));
+
+ WindowServerServiceTestBase::SetUp();
+
+ mojom::WindowTreeHostFactoryPtr factory;
+ connector()->BindInterface(ui::mojom::kServiceName, &factory);
+
+ mojom::WindowTreeClientPtr tree_client_ptr;
+ wt_client1_ = std::make_unique<TestWindowTreeClient>();
+ wt_client1_->Bind(MakeRequest(&tree_client_ptr));
+
+ factory->CreateWindowTreeHost(MakeRequest(&host_),
+ std::move(tree_client_ptr));
+
+ // Next we should get an embed call on the "window manager" client.
+ wt_client1_->WaitForOnEmbed();
+
+ ASSERT_EQ(1u, changes1()->size());
+ EXPECT_EQ(CHANGE_TYPE_EMBED, (*changes1())[0].type);
+ ASSERT_FALSE((*changes1())[0].windows.empty());
+ root_window_id_ = (*changes1())[0].windows[0].window_id;
+ ASSERT_EQ(root_window_id_, wt_client1_->root_window_id());
+ changes1()->clear();
+ }
+
+ void TearDown() override {
+ // Destroy these before the message loop is destroyed (happens in
+ // WindowServerServiceTestBase::TearDown).
+ wt_client1_.reset();
+ wt_client2_.reset();
+ wt_client3_.reset();
+ client_factory_.reset();
+ WindowServerServiceTestBase::TearDown();
+ }
+
+ std::unique_ptr<TestWindowTreeClient> wt_client1_;
+ std::unique_ptr<TestWindowTreeClient> wt_client2_;
+ std::unique_ptr<TestWindowTreeClient> wt_client3_;
+
+ mojom::WindowTreeHostPtr host_;
+
+ private:
+ std::unique_ptr<WindowTreeClientFactory> client_factory_;
+ int client_id_1_ = kWindowServerClientId + 1;
+ int client_id_2_ = client_id_1_ + 1;
+ int client_id_3_ = client_id_2_ + 1;
+ Id root_window_id_;
+ service_manager::BinderRegistry registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeClientTest);
+};
+
+// Verifies two clients get different ids.
+TEST_F(WindowTreeClientTest, TwoClientsGetDifferentClientIds) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+
+ ASSERT_EQ(1u, changes2()->size());
+ ASSERT_NE(client_id_1(), client_id_2());
+}
+
+// Verifies when Embed() is invoked any child windows are removed.
+TEST_F(WindowTreeClientTest, WindowsRemovedWhenEmbedding) {
+ // Two windows 1 and 2. 2 is parented to 1.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_2);
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+ ASSERT_EQ(1u, changes2()->size());
+ ASSERT_EQ(1u, (*changes2())[0].windows.size());
+ // window_1_1 has a client_id part of client_id_1 in wt2.
+ Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ EXPECT_EQ("[" + WindowParentToString(window11_in_wt2, kNullParentId) + "]",
+ ChangeWindowDescription(*changes2()));
+
+ // Embed() removed window 2.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), window_1_2, &windows);
+ EXPECT_EQ(WindowParentToString(window_1_2, kNullParentId),
+ SingleWindowDescription(windows));
+ }
+
+ // ws2 should not see window 2.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt2(), window11_in_wt2, &windows);
+ EXPECT_EQ(WindowParentToString(window11_in_wt2, kNullParentId),
+ SingleWindowDescription(windows));
+ }
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt2(), window_1_2, &windows);
+ EXPECT_TRUE(windows.empty());
+ }
+
+ // Windows 3 and 4 in client 2.
+ Id window_2_3 = wt_client2()->NewWindow(3);
+ Id window_2_4 = wt_client2()->NewWindow(4);
+ ASSERT_TRUE(window_2_3);
+ ASSERT_TRUE(window_2_4);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_3, window_2_4));
+
+ // Client 3 rooted at 2.
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_3));
+
+ // Window 4 should no longer have a parent.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt2(), window_2_3, &windows);
+ EXPECT_EQ(WindowParentToString(window_2_3, kNullParentId),
+ SingleWindowDescription(windows));
+
+ windows.clear();
+ GetWindowTree(wt2(), window_2_4, &windows);
+ EXPECT_EQ(WindowParentToString(window_2_4, kNullParentId),
+ SingleWindowDescription(windows));
+ }
+
+ // And window 4 should not be visible to client 3.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt3(), window_2_3, &windows);
+ EXPECT_EQ("no windows", SingleWindowDescription(windows));
+ }
+}
+
+// Verifies once Embed() has been invoked the parent client can't see any
+// children.
+TEST_F(WindowTreeClientTest, CantAccessChildrenOfEmbeddedWindow) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ Id window_2_2 = wt_client2()->NewWindow(2);
+ ASSERT_TRUE(window_2_2);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
+
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_2));
+
+ Id window_3_3 = wt_client3()->NewWindow(3);
+ ASSERT_TRUE(window_3_3);
+ ASSERT_TRUE(
+ wt_client3()->AddWindow(wt_client3()->root_window_id(), window_3_3));
+
+ // Even though 3 is a child of 2 client 2 can't see 3 as it's from a
+ // different client.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt2(), window_2_2, &windows);
+ EXPECT_EQ(WindowParentToString(window_2_2, window_1_1),
+ SingleWindowDescription(windows));
+ }
+
+ // Client 2 shouldn't be able to get window 3 at all.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt2(), window_3_3, &windows);
+ EXPECT_TRUE(windows.empty());
+ }
+
+ // Client 1 should be able to see it all (its the root).
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), window_1_1, &windows);
+ ASSERT_EQ(3u, windows.size());
+ // window_1_1 is created by wt1() so client_id part would be 0 in wt1().
+ EXPECT_EQ(WindowParentToString(LoWord(window_1_1), kNullParentId),
+ windows[0].ToString());
+ // NOTE: we expect a match of WindowParentToString(window_2_2, window_1_1),
+ // but the ids are in the id space of client2, which is not the same as
+ // the id space of wt1().
+ EXPECT_EQ("window=" + std::to_string(client_id_2()) + ",2 parent=0,1",
+ windows[1].ToString());
+ // Same thing here, we really want to test for
+ // WindowParentToString(window_3_3, window_2_2).
+ EXPECT_EQ("window=" + std::to_string(client_id_3()) +
+ ",3 parent=" + std::to_string(client_id_2()) + ",2",
+ windows[2].ToString());
+ }
+}
+
+// Verifies once Embed() has been invoked the parent can't mutate the children.
+TEST_F(WindowTreeClientTest, CantModifyChildrenOfEmbeddedWindow) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1));
+
+ Id window_2_2 = wt_client2()->NewWindow(2);
+ ASSERT_TRUE(window_2_2);
+ // Client 2 shouldn't be able to add anything to the window anymore.
+ ASSERT_FALSE(wt_client2()->AddWindow(window_2_1, window_2_2));
+
+ // Create window 3 in client 3 and add it to window 3.
+ Id window_3_1 = wt_client3()->NewWindow(1);
+ ASSERT_TRUE(window_3_1);
+ // window_2_1 should have a client_id of client_id_2 in wt_client3.
+ ASSERT_TRUE(wt_client3()->AddWindow(
+ BuildWindowId(client_id_2(), LoWord(window_2_1)), window_3_1));
+
+ // Client 2 shouldn't be able to remove window 3.
+ ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(
+ BuildWindowId(client_id_3(), LoWord(window_3_1))));
+}
+
+// Verifies client gets a valid id.
+TEST_F(WindowTreeClientTest, NewWindow) {
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+ EXPECT_TRUE(changes1()->empty());
+
+ // Can't create a window with the same id.
+ ASSERT_EQ(0u, wt_client1()->NewWindowWithCompleteId(window_1_1));
+ EXPECT_TRUE(changes1()->empty());
+
+ // Can't create a window with a bogus client id.
+ ASSERT_EQ(0u, wt_client1()->NewWindowWithCompleteId(
+ BuildWindowId(client_id_1() + 1, 1)));
+ EXPECT_TRUE(changes1()->empty());
+}
+
+// Verifies AddWindow fails when window is already in position.
+TEST_F(WindowTreeClientTest, AddWindowWithNoChange) {
+ // Create the embed point now so that the ids line up.
+ ASSERT_TRUE(wt_client1()->NewWindow(1));
+ Id window_1_21 = wt_client1()->NewWindow(21);
+ Id window_1_31 = wt_client1()->NewWindow(31);
+ ASSERT_TRUE(window_1_21);
+ ASSERT_TRUE(window_1_31);
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+
+ // Make 3 a child of 2.
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_21, window_1_31));
+
+ // Try again, this should fail.
+ EXPECT_FALSE(wt_client1()->AddWindow(window_1_21, window_1_31));
+}
+
+// Verifies AddWindow fails when window is already in position.
+TEST_F(WindowTreeClientTest, AddAncestorFails) {
+ // Create the embed point now so that the ids line up.
+ ASSERT_TRUE(wt_client1()->NewWindow(1));
+ Id window_1_21 = wt_client1()->NewWindow(21);
+ Id window_1_31 = wt_client1()->NewWindow(31);
+ ASSERT_TRUE(window_1_21);
+ ASSERT_TRUE(window_1_31);
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+
+ // Make 3 a child of 2.
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_21, window_1_31));
+
+ // Try to make 2 a child of 3, this should fail since 2 is an ancestor of 3.
+ EXPECT_FALSE(wt_client1()->AddWindow(window_1_31, window_1_21));
+}
+
+// Verifies adding to root sends right notifications.
+TEST_F(WindowTreeClientTest, AddToRoot) {
+ // Create the embed point now so that the ids line up.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+ Id window_1_21 = wt_client1()->NewWindow(21);
+ Id window_1_31 = wt_client1()->NewWindow(31);
+ ASSERT_TRUE(window_1_21);
+ ASSERT_TRUE(window_1_31);
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+ changes2()->clear();
+
+ // Make 3 a child of 21.
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_21, window_1_31));
+
+ // Make 21 a child of 1.
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_21));
+
+ // Client 2 should not be told anything (because the window is from a
+ // different client). Create a window to ensure we got a response from
+ // the server.
+ ASSERT_TRUE(wt_client2()->NewWindow(100));
+ EXPECT_TRUE(changes2()->empty());
+}
+
+// Verifies HierarchyChanged is correctly sent for various adds/removes.
+TEST_F(WindowTreeClientTest, WindowHierarchyChangedWindows) {
+ // Create the embed point now so that the ids line up.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ // client_id_1(),2->client_id_1(),11.
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_2);
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
+ Id window_1_11 = wt_client1()->NewWindow(11);
+ ASSERT_TRUE(window_1_11);
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_11, true));
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_2, window_1_11));
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
+
+ ASSERT_TRUE(wt_client2()->WaitForAllMessages());
+ changes2()->clear();
+
+ // window_1_1 has a client_id part of client_id_1 in wt2.
+ Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+
+ // client_id_1(),1->client_id_1(),2->client_id_1(),11
+ {
+ // Client 2 should not get anything (client_id_1(),2 is from another
+ // client).
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
+ ASSERT_TRUE(wt_client2()->WaitForAllMessages());
+ EXPECT_TRUE(changes2()->empty());
+ }
+
+ // 0,1->client_id_1(),1->client_id_1(),2->client_id_1(),11.
+ {
+ // Client 2 is now connected to the root, so it should have gotten a drawn
+ // notification.
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ wt_client2_->WaitForChangeCount(1u);
+ EXPECT_EQ("DrawnStateChanged window=" + IdToString(window11_in_wt2) +
+ " drawn=true",
+ SingleChangeToDescription(*changes2()));
+ }
+
+ // client_id_1(),1->client_id_1(),2->client_id_1(),11.
+ {
+ // Client 2 is no longer connected to the root, should get drawn state
+ // changed.
+ changes2()->clear();
+ ASSERT_TRUE(wt_client1()->RemoveWindowFromParent(window_1_1));
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("DrawnStateChanged window=" + IdToString(window11_in_wt2) +
+ " drawn=false",
+ SingleChangeToDescription(*changes2()));
+ }
+
+ // client_id_1(),1->client_id_1(),2->client_id_1(),11->client_id_1(),111.
+ Id window_1_111 = wt_client1()->NewWindow(111);
+ ASSERT_TRUE(window_1_111);
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_111, true));
+ {
+ changes2()->clear();
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_11, window_1_111));
+ ASSERT_TRUE(wt_client2()->WaitForAllMessages());
+ EXPECT_TRUE(changes2()->empty());
+ }
+
+ // 0,1->client_id_1(),1->client_id_1(),2->client_id_1(),11->client_id_1(),111
+ {
+ changes2()->clear();
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("DrawnStateChanged window=" + IdToString(window11_in_wt2) +
+ " drawn=true",
+ SingleChangeToDescription(*changes2()));
+ }
+}
+
+TEST_F(WindowTreeClientTest, WindowHierarchyChangedAddingKnownToUnknown) {
+ // Create the following structure: root -> 1 -> 11 and 2->21 (2 has no
+ // parent).
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+
+ Id window_2_11 = wt_client2()->NewWindow(11);
+ Id window_2_2 = wt_client2()->NewWindow(2);
+ Id window_2_21 = wt_client2()->NewWindow(21);
+ ASSERT_TRUE(window_2_11);
+ ASSERT_TRUE(window_2_2);
+ ASSERT_TRUE(window_2_21);
+ // window_1_1 has a client_id part of 0 in wt1, while window_2_2 has that of
+ // client_id_2.
+ Id window11_in_wt1 = LoWord(window_1_1);
+ Id window22_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_2));
+
+ // Set up the hierarchy.
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_11));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_21));
+
+ // Remove 11, should result in a hierarchy change for the root.
+ {
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_11));
+
+ wt_client1_->WaitForChangeCount(1);
+ // client_id_2(),1 should be IdToString(window_2_11), but window_2_11 is in
+ // the id space of client2, not client1.
+ EXPECT_EQ("HierarchyChanged window=" + std::to_string(client_id_2()) +
+ ",11 old_parent=" + IdToString(window11_in_wt1) +
+ " new_parent=null",
+ SingleChangeToDescription(*changes1()));
+ }
+
+ // Add 2 to 1.
+ {
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window22_in_wt1) +
+ " old_parent=null new_parent=" + IdToString(window11_in_wt1),
+ SingleChangeToDescription(*changes1()));
+ // "window=client_id_2(),3 parent=client_id_2(),2]" should be,
+ // WindowParentToString(window_2_21, window_2_2), but isn't because of
+ // differing id spaces.
+ EXPECT_EQ("[" + WindowParentToString(window22_in_wt1, window11_in_wt1) +
+ "],[window=" + std::to_string(client_id_2()) +
+ ",21 parent=" + std::to_string(client_id_2()) + ",2]",
+ ChangeWindowDescription(*changes1()));
+ }
+}
+
+TEST_F(WindowTreeClientTest, ReorderWindow) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ Id window_2_2 = wt_client2()->NewWindow(2);
+ Id window_2_3 = wt_client2()->NewWindow(3);
+ Id window_1_4 = wt_client1()->NewWindow(4); // Peer to client_id_1(),1
+ Id window_1_5 = wt_client1()->NewWindow(5); // Peer to client_id_1(),1
+ Id window_2_6 = wt_client2()->NewWindow(6); // Child of client_id_1(),2.
+ Id window_2_7 = wt_client2()->NewWindow(7); // Unparented.
+ Id window_2_8 = wt_client2()->NewWindow(8); // Unparented.
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(window_2_2);
+ ASSERT_TRUE(window_2_3);
+ ASSERT_TRUE(window_1_4);
+ ASSERT_TRUE(window_1_5);
+ ASSERT_TRUE(window_2_6);
+ ASSERT_TRUE(window_2_7);
+ ASSERT_TRUE(window_2_8);
+
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_6));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_3));
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_4));
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_5));
+ ASSERT_TRUE(
+ wt_client2()->AddWindow(BuildWindowId(client_id_1(), 1), window_2_1));
+
+ // window_2_* has client_id part of client_id_2 in wt1.
+ Id window22_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_2));
+ Id window23_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_3));
+ Id window26_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_6));
+ Id window27_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_7));
+ Id window28_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_8));
+
+ {
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
+ mojom::OrderDirection::ABOVE));
+
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("Reordered window=" + IdToString(window22_in_wt1) + " relative=" +
+ IdToString(window23_in_wt1) + " direction=above",
+ SingleChangeToDescription(*changes1()));
+ }
+
+ {
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
+ mojom::OrderDirection::BELOW));
+
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("Reordered window=" + IdToString(window22_in_wt1) + " relative=" +
+ IdToString(window23_in_wt1) + " direction=below",
+ SingleChangeToDescription(*changes1()));
+ }
+
+ // view2 is already below view3.
+ EXPECT_FALSE(wt_client2()->ReorderWindow(window_2_2, window_2_3,
+ mojom::OrderDirection::BELOW));
+
+ // view4 & 5 are unknown to client 2.
+ EXPECT_FALSE(wt_client2()->ReorderWindow(window_1_4, window_1_5,
+ mojom::OrderDirection::ABOVE));
+
+ // view6 & view3 have different parents.
+ EXPECT_FALSE(wt_client1()->ReorderWindow(window23_in_wt1, window26_in_wt1,
+ mojom::OrderDirection::ABOVE));
+
+ // Non-existent window-ids
+ EXPECT_FALSE(wt_client1()->ReorderWindow(BuildWindowId(client_id_1(), 27),
+ BuildWindowId(client_id_1(), 28),
+ mojom::OrderDirection::ABOVE));
+
+ // view7 & view8 are un-parented.
+ EXPECT_FALSE(wt_client1()->ReorderWindow(window27_in_wt1, window28_in_wt1,
+ mojom::OrderDirection::ABOVE));
+}
+
+// Verifies DeleteWindow works.
+TEST_F(WindowTreeClientTest, DeleteWindow) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ // window_2_1 is not created by wt1 so its client_id part is client_id_2,
+ // while window_1_1 would have 0 for the client_id part.
+ Id window21_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_1));
+
+ // Make 2 a child of 1.
+ {
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ(
+ "HierarchyChanged window=" + IdToString(window21_in_wt1) +
+ " old_parent=null new_parent=" + IdToString(LoWord(window_1_1)),
+ SingleChangeToDescription(*changes1()));
+ }
+
+ // Delete 2.
+ {
+ changes1()->clear();
+ changes2()->clear();
+ ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
+ EXPECT_TRUE(changes2()->empty());
+
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("WindowDeleted window=" + IdToString(window21_in_wt1),
+ SingleChangeToDescription(*changes1()));
+ }
+}
+
+// Verifies DeleteWindow() on the root suceeds.
+TEST_F(WindowTreeClientTest, DeleteRoot) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ EXPECT_TRUE(wt_client2()->DeleteWindow(window_1_1));
+ // Client1 should get OnEmbeddedAppDisconnected().
+ wt_client1_->WaitForChangeCount(1);
+ // window_1_1 should have client_id of 0 in wt_client1 because it's created
+ // by wt_client1.
+ EXPECT_EQ(
+ "OnEmbeddedAppDisconnected window=" + IdToString(LoWord(window_1_1)),
+ SingleChangeToDescription(*changes1()));
+
+ // Create a new window and try adding to |window_1_1| from client 2, should
+ // fail as client 2 no longer knows about |window_1_1|.
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ EXPECT_FALSE(wt_client2()->AddWindow(window_1_1, window_2_1));
+}
+
+// Verifies DeleteWindow() on the root suceeds.
+TEST_F(WindowTreeClientTest, DeleteRootWithChildren) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+ changes2()->clear();
+ EXPECT_TRUE(wt_client2()->DeleteWindow(window_1_1));
+ // DeleteWindow() should not result in any calls to client 2.
+ EXPECT_TRUE(changes2()->empty());
+
+ // Create a new window parented to 2_1. Should work as 2_1 is still valid.
+ Id window_2_2 = wt_client2()->NewWindow(2);
+ ASSERT_TRUE(window_2_2);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2));
+}
+
+// Verifies DeleteWindow isn't allowed from a separate client.
+TEST_F(WindowTreeClientTest, DeleteWindowFromAnotherClientDisallowed) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ // This id is unknown, so deletion should fail.
+ EXPECT_FALSE(wt_client2()->DeleteWindow(BuildWindowId(client_id_1(), 2)));
+}
+
+// Verifies if a window was deleted and then reused that other clients are
+// properly notified.
+TEST_F(WindowTreeClientTest, ReuseDeletedWindowId) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+
+ // wt1 created window_1_1 but not window_2_1.
+ Id window11_in_wt1 = LoWord(window_1_1);
+ Id window21_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_1));
+
+ // Add 2 to 1.
+ {
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window21_in_wt1) +
+ " old_parent=null new_parent=" + IdToString(window11_in_wt1),
+ SingleChangeToDescription(*changes1()));
+ EXPECT_EQ(
+ "[" + WindowParentToString(window21_in_wt1, window11_in_wt1) + "]",
+ ChangeWindowDescription(*changes1()));
+ }
+
+ // Delete 2.
+ {
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
+
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("WindowDeleted window=" + IdToString(window21_in_wt1),
+ SingleChangeToDescription(*changes1()));
+ }
+
+ // Create 2 again, and add it back to 1. Should get the same notification.
+ window_2_1 = wt_client2()->NewWindow(2);
+ window21_in_wt1 = BuildWindowId(HiWord(window21_in_wt1), LoWord(window_2_1));
+ ASSERT_TRUE(window_2_1);
+ {
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window21_in_wt1) +
+ " old_parent=null new_parent=" + IdToString(window11_in_wt1),
+ SingleChangeToDescription(*changes1()));
+ EXPECT_EQ(
+ "[" + WindowParentToString(window21_in_wt1, window11_in_wt1) + "]",
+ ChangeWindowDescription(*changes1()));
+ }
+}
+
+// Assertions for GetWindowTree.
+TEST_F(WindowTreeClientTest, GetWindowTree) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+
+ // Create 11 in first client and make it a child of 1.
+ Id window_1_11 = wt_client1()->NewWindow(11);
+ ASSERT_TRUE(window_1_11);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_11));
+
+ // Create two windows in second client, 2 and 3, both children of 1.
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ Id window_2_2 = wt_client2()->NewWindow(2);
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(window_2_2);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
+
+ // wt1 created window_1_1 and window_1_11, but not window_2_1 and window_2_2.
+ Id window11_in_wt1 = LoWord(window_1_1);
+ Id window111_in_wt1 = LoWord(window_1_11);
+ Id window21_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_1));
+ Id window22_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_2));
+
+ // Verifies GetWindowTree() on the root. The root client sees all.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), root_window_id(), &windows);
+ ASSERT_EQ(5u, windows.size());
+ EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId),
+ windows[0].ToString());
+ EXPECT_EQ(WindowParentToString(window11_in_wt1, root_window_id()),
+ windows[1].ToString());
+ EXPECT_EQ(WindowParentToString(window111_in_wt1, window11_in_wt1),
+ windows[2].ToString());
+ EXPECT_EQ(WindowParentToString(window21_in_wt1, window11_in_wt1),
+ windows[3].ToString());
+ EXPECT_EQ(WindowParentToString(window22_in_wt1, window11_in_wt1),
+ windows[4].ToString());
+ }
+
+ // Verifies GetWindowTree() on the window client_id_1(),1 from wt2(). wt2()
+ // sees client_id_1(),1 as client_id_1(),1 is wt2()'s root and wt2() sees all
+ // the windows it created.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt2(), window_1_1, &windows);
+ ASSERT_EQ(3u, windows.size());
+ EXPECT_EQ(WindowParentToString(window_1_1, kNullParentId),
+ windows[0].ToString());
+ EXPECT_EQ(WindowParentToString(window_2_1, window_1_1),
+ windows[1].ToString());
+ EXPECT_EQ(WindowParentToString(window_2_2, window_1_1),
+ windows[2].ToString());
+ }
+
+ // Client 2 shouldn't be able to get the root tree.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt2(), root_window_id(), &windows);
+ ASSERT_EQ(0u, windows.size());
+ }
+}
+
+TEST_F(WindowTreeClientTest, SetWindowBounds) {
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+
+ changes2()->clear();
+
+ wt_client2_->set_track_root_bounds_changes(true);
+
+ viz::ParentLocalSurfaceIdAllocator allocator;
+ viz::LocalSurfaceId local_surface_id = allocator.GenerateId();
+ wt1()->SetWindowBounds(10, window_1_1, gfx::Rect(0, 0, 100, 100),
+ local_surface_id);
+ ASSERT_TRUE(wt_client1()->WaitForChangeCompleted(10));
+
+ wt_client2_->WaitForChangeCount(1);
+ // window_1_1 has a client_id part of client_id_1 in wt2.
+ Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ EXPECT_EQ("BoundsChanged window=" + IdToString(window11_in_wt2) +
+ " old_bounds=0,0 0x0 new_bounds=0,0 100x100 local_surface_id=" +
+ local_surface_id.ToString(),
+ SingleChangeToDescription(*changes2()));
+
+ // Should not be possible to change the bounds of a window created by another
+ // client.
+ wt2()->SetWindowBounds(11, window11_in_wt2, gfx::Rect(0, 0, 0, 0),
+ base::nullopt);
+ ASSERT_FALSE(wt_client2()->WaitForChangeCompleted(11));
+}
+
+// Verify AddWindow fails when trying to manipulate windows in other roots.
+TEST_F(WindowTreeClientTest, CantMoveWindowsFromOtherRoot) {
+ // Create 1 and 2 in the first client.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_1);
+ ASSERT_TRUE(window_1_2);
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+
+ // Try to move 2 to be a child of 1 from client 2. This should fail as 2
+ // should not be able to access 1.
+ ASSERT_FALSE(wt_client2()->AddWindow(window_1_1, window_1_2));
+
+ // Try to reparent 1 to the root. A client is not allowed to reparent its
+ // roots.
+ ASSERT_FALSE(wt_client2()->AddWindow(root_window_id(), window_1_1));
+}
+
+// Verify RemoveWindowFromParent fails for windows that are descendants of the
+// roots.
+TEST_F(WindowTreeClientTest, CantRemoveWindowsInOtherRoots) {
+ // Create 1 and 2 in the first client and parent both to the root.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_1);
+ ASSERT_TRUE(window_1_2);
+
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
+
+ // Establish the second client and give it the root 1.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+
+ // Client 2 should not be able to remove window 2 or 1 from its parent.
+ ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_1_2));
+ ASSERT_FALSE(wt_client2()->RemoveWindowFromParent(window_1_1));
+
+ // Create windows 10 and 11 in 2.
+ Id window_2_10 = wt_client2()->NewWindow(10);
+ Id window_2_11 = wt_client2()->NewWindow(11);
+ ASSERT_TRUE(window_2_10);
+ ASSERT_TRUE(window_2_11);
+
+ // Parent 11 to 10.
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_10, window_2_11));
+ // Remove 11 from 10.
+ ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_11));
+
+ // Verify nothing was actually removed.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), root_window_id(), &windows);
+ ASSERT_EQ(3u, windows.size());
+ EXPECT_EQ(WindowParentToString(root_window_id(), kNullParentId),
+ windows[0].ToString());
+ EXPECT_EQ(WindowParentToString(window_1_1, root_window_id()),
+ windows[1].ToString());
+ EXPECT_EQ(WindowParentToString(window_1_2, root_window_id()),
+ windows[2].ToString());
+ }
+}
+
+// Verify GetWindowTree fails for windows that are not descendants of the roots.
+TEST_F(WindowTreeClientTest, CantGetWindowTreeOfOtherRoots) {
+ // Create 1 and 2 in the first client and parent both to the root.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_1);
+ ASSERT_TRUE(window_1_2);
+
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+
+ std::vector<TestWindow> windows;
+
+ // Should get nothing for the root.
+ GetWindowTree(wt2(), root_window_id(), &windows);
+ ASSERT_TRUE(windows.empty());
+
+ // Should get nothing for window 2.
+ GetWindowTree(wt2(), window_1_2, &windows);
+ ASSERT_TRUE(windows.empty());
+
+ // Should get window 1 if asked for.
+ Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ GetWindowTree(wt2(), window11_in_wt2, &windows);
+ ASSERT_EQ(1u, windows.size());
+ EXPECT_EQ(WindowParentToString(window11_in_wt2, kNullParentId),
+ windows[0].ToString());
+}
+
+TEST_F(WindowTreeClientTest, EmbedWithSameWindowId) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ changes2()->clear();
+
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt1(), window_1_1));
+
+ // Client 2 should have been told of the unembed and delete.
+ {
+ wt_client2_->WaitForChangeCount(2);
+ EXPECT_EQ("OnUnembed window=" + IdToString(window_1_1),
+ ChangesToDescription1(*changes2())[0]);
+ EXPECT_EQ("WindowDeleted window=" + IdToString(window_1_1),
+ ChangesToDescription1(*changes2())[1]);
+ }
+
+ // Client 2 has no root. Verify it can't see window client_id_1(),1 anymore.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt2(), window_1_1, &windows);
+ EXPECT_TRUE(windows.empty());
+ }
+}
+
+TEST_F(WindowTreeClientTest, EmbedWithSameWindowId2) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ changes2()->clear();
+
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt1(), window_1_1));
+
+ // Client 2 should have been told about the unembed and delete.
+ wt_client2_->WaitForChangeCount(2);
+ changes2()->clear();
+
+ // Create a window in the third client and parent it to the root.
+ Id window_3_1 = wt_client3()->NewWindow(1);
+ ASSERT_TRUE(window_3_1);
+ // After EstablishThirdClient, window_1_1 should have a ClientWindowId of
+ // (client_id_2, 0).
+ Id embedded_window_1_1_wt3 = BuildWindowId(client_id_2(), 0);
+ ASSERT_TRUE(wt_client3()->AddWindow(embedded_window_1_1_wt3, window_3_1));
+
+ // wt1 created window_1_1 but not window_3_1.
+ Id window11_in_wt1 = LoWord(window_1_1);
+ Id window31_in_wt1 = BuildWindowId(client_id_3(), LoWord(window_3_1));
+
+ // Client 1 should have been told about the add (it owns the window).
+ {
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window31_in_wt1) +
+ " old_parent=null new_parent=" + IdToString(window11_in_wt1),
+ SingleChangeToDescription(*changes1()));
+ }
+
+ // Embed client_id_1(),1 again.
+ {
+ changes3()->clear();
+
+ // We should get a new client for the new embedding.
+ std::unique_ptr<TestWindowTreeClient> client4(
+ EstablishClientViaEmbed(wt1(), window_1_1));
+ Id embedded_window_1_1_wt4 = BuildWindowId(client_id_3(), 0);
+ ASSERT_TRUE(client4.get());
+ EXPECT_EQ("[" +
+ WindowParentToString(embedded_window_1_1_wt4, kNullParentId) +
+ "]",
+ ChangeWindowDescription(*client4->tracker()->changes()));
+
+ // And 3 should get an unembed and delete.
+ wt_client3_->WaitForChangeCount(2);
+ EXPECT_EQ("OnUnembed window=" + IdToString(embedded_window_1_1_wt3),
+ ChangesToDescription1(*changes3())[0]);
+ EXPECT_EQ("WindowDeleted window=" + IdToString(embedded_window_1_1_wt3),
+ ChangesToDescription1(*changes3())[1]);
+ }
+
+ // wt3() has no root. Verify it can't see window client_id_1(),1 anymore.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt3(), window_1_1, &windows);
+ EXPECT_TRUE(windows.empty());
+ }
+
+ // Verify client_id_3(),1 is no longer parented to client_id_1(),1. We have to
+ // do this from client_id_1(),1 as wt3() can no longer see client_id_1(),1.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), window_1_1, &windows);
+ ASSERT_EQ(1u, windows.size());
+ EXPECT_EQ(WindowParentToString(window11_in_wt1, kNullParentId),
+ windows[0].ToString());
+ }
+
+ // Verify wt3() can still see the window it created client_id_3(),1.
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt3(), window_3_1, &windows);
+ ASSERT_EQ(1u, windows.size());
+ EXPECT_EQ(WindowParentToString(window_3_1, kNullParentId),
+ windows[0].ToString());
+ }
+}
+
+// Assertions for SetWindowVisibility.
+TEST_F(WindowTreeClientTest, SetWindowVisibility) {
+ // Create 1 and 2 in the first client and parent both to the root.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_1);
+ ASSERT_TRUE(window_1_2);
+
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), root_window_id(), &windows);
+ ASSERT_EQ(2u, windows.size());
+ EXPECT_EQ(
+ WindowParentToString(root_window_id(), kNullParentId) + " visible=true",
+ windows[0].ToString2());
+ EXPECT_EQ(
+ WindowParentToString(window_1_1, root_window_id()) + " visible=false",
+ windows[1].ToString2());
+ }
+
+ // Show all the windows.
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), root_window_id(), &windows);
+ ASSERT_EQ(2u, windows.size());
+ EXPECT_EQ(
+ WindowParentToString(root_window_id(), kNullParentId) + " visible=true",
+ windows[0].ToString2());
+ EXPECT_EQ(
+ WindowParentToString(window_1_1, root_window_id()) + " visible=true",
+ windows[1].ToString2());
+ }
+
+ // Hide 1.
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, false));
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), window_1_1, &windows);
+ ASSERT_EQ(1u, windows.size());
+ EXPECT_EQ(
+ WindowParentToString(window_1_1, root_window_id()) + " visible=false",
+ windows[0].ToString2());
+ }
+
+ // Attach 2 to 1.
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), window_1_1, &windows);
+ ASSERT_EQ(2u, windows.size());
+ EXPECT_EQ(
+ WindowParentToString(window_1_1, root_window_id()) + " visible=false",
+ windows[0].ToString2());
+ EXPECT_EQ(WindowParentToString(window_1_2, window_1_1) + " visible=true",
+ windows[1].ToString2());
+ }
+
+ // Show 1.
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), window_1_1, &windows);
+ ASSERT_EQ(2u, windows.size());
+ EXPECT_EQ(
+ WindowParentToString(window_1_1, root_window_id()) + " visible=true",
+ windows[0].ToString2());
+ EXPECT_EQ(WindowParentToString(window_1_2, window_1_1) + " visible=true",
+ windows[1].ToString2());
+ }
+}
+
+// Test that we hear the cursor change in other clients.
+TEST_F(WindowTreeClientTest, SetCursor) {
+ // Get a second client to listen in.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ changes2()->clear();
+
+ ASSERT_TRUE(wt_client1()->SetCursor(window_1_1,
+ ui::CursorData(ui::CursorType::kIBeam)));
+ wt_client2_->WaitForChangeCount(1u);
+
+ EXPECT_EQ("CursorChanged id=" + IdToString(window_1_1) + " cursor_type=4",
+ SingleChangeToDescription(*changes2()));
+}
+
+// Assertions for SetWindowVisibility sending notifications.
+TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications) {
+ // Create client_id_1(),1 and client_id_1(),2. client_id_1(),2 is made a child
+ // of client_id_1(),1 and client_id_1(),1 a child of the root.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
+ // Setting to the same value should return true.
+ EXPECT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
+
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_2);
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
+
+ // Establish the second client at client_id_1(),2.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
+
+ // Add client_id_2(),3 as a child of client_id_1(),2.
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, true));
+ // window_1_2 has a client_id part of client_id_1 in wt2.
+ Id window12_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_2));
+ ASSERT_TRUE(wt_client2()->AddWindow(window12_in_wt2, window_2_1));
+ ASSERT_TRUE(wt_client1()->WaitForAllMessages());
+
+ changes2()->clear();
+ // Hide client_id_1(),2 from client 1. Client 2 should see this.
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, false));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("VisibilityChanged window=" + IdToString(window12_in_wt2) +
+ " visible=false",
+ SingleChangeToDescription(*changes2()));
+ }
+
+ changes1()->clear();
+ // Show client_id_1(),2 from client 2, client 1 should be notified.
+ ASSERT_TRUE(wt_client2()->SetWindowVisibility(window12_in_wt2, true));
+ {
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ(
+ "VisibilityChanged window=" + IdToString(window_1_2) + " visible=true",
+ SingleChangeToDescription(*changes1()));
+ }
+
+ changes2()->clear();
+ // Hide client_id_1(),1, client 2 should be told the draw state changed.
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, false));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("DrawnStateChanged window=" + IdToString(window12_in_wt2) +
+ " drawn=false",
+ SingleChangeToDescription(*changes2()));
+ }
+
+ changes2()->clear();
+ // Show client_id_1(),1 from client 1. Client 2 should see this.
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("DrawnStateChanged window=" + IdToString(window12_in_wt2) +
+ " drawn=true",
+ SingleChangeToDescription(*changes2()));
+ }
+
+ // Change visibility of client_id_2(),3, client 1 should see this.
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->SetWindowVisibility(window_2_1, false));
+ {
+ wt_client1_->WaitForChangeCount(1);
+ EXPECT_EQ("VisibilityChanged window=" +
+ IdToString(BuildWindowId(client_id_2(), LoWord(window_2_1))) +
+ " visible=false",
+ SingleChangeToDescription(*changes1()));
+ }
+
+ changes2()->clear();
+ // Remove client_id_1(),1 from the root, client 2 should see drawn state
+ // changed.
+ ASSERT_TRUE(wt_client1()->RemoveWindowFromParent(window_1_1));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("DrawnStateChanged window=" + IdToString(window12_in_wt2) +
+ " drawn=false",
+ SingleChangeToDescription(*changes2()));
+ }
+
+ changes2()->clear();
+ // Add client_id_1(),1 back to the root, client 2 should see drawn state
+ // changed.
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("DrawnStateChanged window=" + IdToString(window12_in_wt2) +
+ " drawn=true",
+ SingleChangeToDescription(*changes2()));
+ }
+}
+
+// Assertions for SetWindowVisibility sending notifications.
+TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications2) {
+ // Create client_id_1(),1 and client_id_1(),2. client_id_1(),2 is made a child
+ // of client_id_1(),1 and client_id_1(),1 a child of the root.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_2);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
+
+ // Establish the second client at client_id_1(),2.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
+ // window_1_2 has a client_id part of client_id_1 in wt2.
+ Id window12_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_2));
+ EXPECT_EQ("OnEmbed drawn=true", SingleChangeToDescription2(*changes2()));
+ changes2()->clear();
+
+ // Show client_id_1(),2 from client 1. Client 2 should see this.
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("VisibilityChanged window=" + IdToString(window12_in_wt2) +
+ " visible=true",
+ SingleChangeToDescription(*changes2()));
+ }
+}
+
+// Assertions for SetWindowVisibility sending notifications.
+TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications3) {
+ // Create client_id_1(),1 and client_id_1(),2. client_id_1(),2 is made a child
+ // of client_id_1(),1 and client_id_1(),1 a child of the root.
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_2);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
+
+ // Establish the second client at client_id_1(),2.
+ // TODO(fsamuel): Currently the FrameSinkId maps directly to the server's
+ // window ID. This is likely bad from a security perspective and should be
+ // fixed.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
+ // window_1_2 has a client_id part of client_id_1 in wt2.
+ Id window12_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_2));
+ EXPECT_EQ("OnEmbed drawn=false", SingleChangeToDescription2(*changes2()));
+ changes2()->clear();
+
+ // Show client_id_1(),1, drawn should be true for client_id_1(),2 (as that is
+ // all the child sees).
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_1, true));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("DrawnStateChanged window=" + IdToString(window12_in_wt2) +
+ " drawn=true",
+ SingleChangeToDescription(*changes2()));
+ }
+ changes2()->clear();
+
+ // Show client_id_1(),2, visible should be true.
+ ASSERT_TRUE(wt_client1()->SetWindowVisibility(window_1_2, true));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("VisibilityChanged window=" + IdToString(window12_in_wt2) +
+ " visible=true",
+ SingleChangeToDescription(*changes2()));
+ }
+}
+
+// Tests that when opacity is set on a window, that the calling client is not
+// notified, however children are. Also that setting the same opacity is
+// rejected and no on eis notifiyed.
+TEST_F(WindowTreeClientTest, SetOpacityNotifications) {
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_1));
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ // window_1_1 has a client_id part of client_id_1 in wt2.
+ Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ ASSERT_TRUE(wt_client2()->AddWindow(window11_in_wt2, window_2_1));
+ ASSERT_TRUE(wt_client1()->WaitForAllMessages());
+
+ changes1()->clear();
+ changes2()->clear();
+ // Change opacity, no notification for calling client.
+ ASSERT_TRUE(wt_client1()->SetWindowOpacity(window_1_1, 0.5f));
+ EXPECT_TRUE(changes1()->empty());
+ wt_client2()->WaitForChangeCount(1);
+ EXPECT_EQ("OpacityChanged window_id=" + IdToString(window11_in_wt2) +
+ " opacity=0.50",
+ SingleChangeToDescription(*changes2()));
+
+ changes2()->clear();
+ // Attempting to set the same opacity should succeed, but no notification as
+ // there was no actual change.
+ ASSERT_TRUE(wt_client1()->SetWindowOpacity(window_1_1, 0.5f));
+ EXPECT_TRUE(changes1()->empty());
+ wt_client2()->WaitForAllMessages();
+ EXPECT_TRUE(changes2()->empty());
+}
+
+TEST_F(WindowTreeClientTest, SetWindowProperty) {
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ ASSERT_TRUE(window_1_1);
+
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(false));
+ changes2()->clear();
+
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), root_window_id(), &windows);
+ ASSERT_EQ(2u, windows.size());
+ EXPECT_EQ(root_window_id(), windows[0].window_id);
+ EXPECT_EQ(window_1_1, windows[1].window_id);
+ ASSERT_EQ(0u, windows[1].properties.size());
+ }
+
+ // Set properties on 1.
+ changes2()->clear();
+ std::vector<uint8_t> one(1, '1');
+ ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", &one));
+ // window_1_1 has a client_id part of client_id_1 in wt2.
+ Id window11_in_wt2 = BuildWindowId(client_id_1(), LoWord(window_1_1));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("PropertyChanged window=" + IdToString(window11_in_wt2) +
+ " key=one value=1",
+ SingleChangeToDescription(*changes2()));
+ }
+
+ // Test that our properties exist in the window tree
+ {
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), window_1_1, &windows);
+ ASSERT_EQ(1u, windows.size());
+ ASSERT_EQ(1u, windows[0].properties.size());
+ EXPECT_EQ(one, windows[0].properties["one"]);
+ }
+
+ changes2()->clear();
+ // Set back to null.
+ ASSERT_TRUE(wt_client1()->SetWindowProperty(window_1_1, "one", NULL));
+ {
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("PropertyChanged window=" + IdToString(window11_in_wt2) +
+ " key=one value=NULL",
+ SingleChangeToDescription(*changes2()));
+ }
+}
+
+TEST_F(WindowTreeClientTest, OnEmbeddedAppDisconnected) {
+ // Create client 2 and 3.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+ changes2()->clear();
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1));
+
+ // Client 1 should get a hierarchy change for window_2_1.
+ wt_client1_->WaitForChangeCount(1);
+ changes1()->clear();
+
+ // Close client 3. Client 2 (which had previously embedded 3) should
+ // be notified of this.
+ wt_client3_.reset();
+ wt_client2_->WaitForChangeCount(1);
+ EXPECT_EQ("OnEmbeddedAppDisconnected window=" + IdToString(window_2_1),
+ SingleChangeToDescription(*changes2()));
+
+ // The closing is only interesting to the root that did the embedding. Other
+ // clients should not be notified of this.
+ wt_client1_->WaitForAllMessages();
+ EXPECT_TRUE(changes1()->empty());
+}
+
+// Verifies when the parent of an Embed() is destroyed the embedded app gets
+// a WindowDeleted (and doesn't trigger a DCHECK).
+TEST_F(WindowTreeClientTest, OnParentOfEmbedDisconnects) {
+ // Create client 2 and 3.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ Id window_2_2 = wt_client2()->NewWindow(2);
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(window_2_2);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_1, window_2_2));
+ changes2()->clear();
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_2));
+ changes3()->clear();
+
+ // Close client 2. Client 3 should get a delete (for its root).
+ wt_client2_.reset();
+ wt_client3_->WaitForChangeCount(1);
+ // window_2_2 has a client_id part of client_id_2 in wt3.
+ EXPECT_EQ("WindowDeleted window=" +
+ IdToString(BuildWindowId(client_id_2(), LoWord(window_2_2))),
+ SingleChangeToDescription(*changes3()));
+}
+
+// Verifies WindowTreeImpl doesn't incorrectly erase from its internal
+// map when a window from another client with the same window_id is removed.
+TEST_F(WindowTreeClientTest, DontCleanMapOnDestroy) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ ASSERT_TRUE(wt_client2()->NewWindow(1));
+ changes1()->clear();
+ wt_client2_.reset();
+ wt_client1_->WaitForChangeCount(1);
+ // window_1_1 is created by wt1 so client_id part would be 0.
+ EXPECT_EQ(
+ "OnEmbeddedAppDisconnected window=" + IdToString(LoWord(window_1_1)),
+ SingleChangeToDescription(*changes1()));
+ std::vector<TestWindow> windows;
+ GetWindowTree(wt1(), window_1_1, &windows);
+ EXPECT_FALSE(windows.empty());
+}
+
+// Verifies Embed() works when supplying a WindowTreeClient.
+TEST_F(WindowTreeClientTest, EmbedSupplyingWindowTreeClient) {
+ ASSERT_TRUE(wt_client1()->NewWindow(1));
+
+ TestWindowTreeClient client2;
+ mojom::WindowTreeClientPtr client2_ptr;
+ mojo::Binding<WindowTreeClient> client2_binding(
+ &client2, mojo::MakeRequest(&client2_ptr));
+ ASSERT_TRUE(Embed(wt1(), BuildWindowId(client_id_1(), 1),
+ std::move(client2_ptr)));
+ client2.WaitForOnEmbed();
+ EXPECT_EQ("OnEmbed",
+ SingleChangeToDescription(*client2.tracker()->changes()));
+}
+
+TEST_F(WindowTreeClientTest, EmbedUsingToken) {
+ // Embed client2.
+ ASSERT_TRUE(wt_client1()->NewWindow(1));
+ TestWindowTreeClient client2;
+ mojom::WindowTreeClientPtr client2_ptr;
+ mojo::Binding<WindowTreeClient> client2_binding(
+ &client2, mojo::MakeRequest(&client2_ptr));
+ ASSERT_TRUE(
+ Embed(wt1(), BuildWindowId(client_id_1(), 1), std::move(client2_ptr)));
+ client2.WaitForOnEmbed();
+ EXPECT_EQ("OnEmbed",
+ SingleChangeToDescription(*client2.tracker()->changes()));
+
+ // Schedule an embed of |client3| from wt1().
+ TestWindowTreeClient client3;
+ mojom::WindowTreeClientPtr client3_ptr;
+ mojo::Binding<WindowTreeClient> client3_binding(
+ &client3, mojo::MakeRequest(&client3_ptr));
+ base::UnguessableToken token;
+ ScheduleEmbed(wt1(), std::move(client3_ptr), &token);
+
+ // Have |client2| embed using the token scheduled above.
+ const Id window_id = client2.NewWindow(121);
+ ASSERT_TRUE(window_id);
+ ASSERT_TRUE(EmbedUsingToken(client2.tree(), BuildWindowId(client_id_2(), 121),
+ token));
+ client3.WaitForOnEmbed();
+ EXPECT_EQ("OnEmbed",
+ SingleChangeToDescription(*client3.tracker()->changes()));
+
+ // EmbedUsingToken() should fail when passed a token that was already used.
+ EXPECT_FALSE(EmbedUsingToken(client2.tree(),
+ BuildWindowId(client_id_2(), 121), token));
+
+ // EmbedUsingToken() should fail when passed a locally generated token.
+ EXPECT_FALSE(EmbedUsingToken(client2.tree(),
+ BuildWindowId(client_id_2(), 121),
+ base::UnguessableToken::Create()));
+}
+
+TEST_F(WindowTreeClientTest, EmbedUsingTokenFailsWithInvalidWindow) {
+ // Embed client2.
+ ASSERT_TRUE(wt_client1()->NewWindow(1));
+ TestWindowTreeClient client2;
+ mojom::WindowTreeClientPtr client2_ptr;
+ mojo::Binding<WindowTreeClient> client2_binding(
+ &client2, mojo::MakeRequest(&client2_ptr));
+ ASSERT_TRUE(
+ Embed(wt1(), BuildWindowId(client_id_1(), 1), std::move(client2_ptr)));
+ client2.WaitForOnEmbed();
+ EXPECT_EQ("OnEmbed",
+ SingleChangeToDescription(*client2.tracker()->changes()));
+
+ // Schedule an embed of |client3| from wt1().
+ TestWindowTreeClient client3;
+ mojom::WindowTreeClientPtr client3_ptr;
+ mojo::Binding<WindowTreeClient> client3_binding(
+ &client3, mojo::MakeRequest(&client3_ptr));
+ base::UnguessableToken token;
+ ScheduleEmbed(wt1(), std::move(client3_ptr), &token);
+
+ // This should fail as the window id does not identify a valid window.
+ EXPECT_FALSE(EmbedUsingToken(client2.tree(),
+ BuildWindowId(client_id_2(), 121), token));
+}
+
+TEST_F(WindowTreeClientTest, EmbedFailsFromOtherClient) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(wt2(), window_2_1));
+
+ Id window_3_3 = wt_client3()->NewWindow(3);
+ ASSERT_TRUE(window_3_3);
+ // window_2_1 should have client_id of client_id_2 in wt_client3.
+ ASSERT_TRUE(wt_client3()->AddWindow(
+ BuildWindowId(client_id_2(), LoWord(window_2_1)), window_3_3));
+
+ // 2 should not be able to embed in window_3_3 as window_3_3 was not created
+ // by
+ // 2.
+ EXPECT_FALSE(EmbedUrl(connector(), wt2(), test_name(), window_3_3));
+}
+
+// Verifies Embed() from window manager on another clients window works.
+TEST_F(WindowTreeClientTest, EmbedFromOtherClient) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ ASSERT_TRUE(window_2_1);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+
+ changes2()->clear();
+
+ // Establish a third client in window_2_1. window_2_1 has a client_id of
+ // client_id_2 for other clients.
+ ASSERT_NO_FATAL_FAILURE(EstablishThirdClient(
+ wt1(), BuildWindowId(client_id_2(), LoWord(window_2_1))));
+
+ ASSERT_TRUE(wt_client2()->WaitForAllMessages());
+ EXPECT_EQ(std::string(), SingleChangeToDescription(*changes2()));
+}
+
+TEST_F(WindowTreeClientTest, CantEmbedFromClientRoot) {
+ // Shouldn't be able to embed into the root.
+ ASSERT_FALSE(EmbedUrl(connector(), wt1(), test_name(), root_window_id()));
+
+ // Even though the call above failed a WindowTreeClient was obtained. We need
+ // to
+ // wait for it else we throw off the next connect.
+ WaitForWindowTreeClient();
+
+ // Don't allow a client to embed into its own root.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ EXPECT_FALSE(EmbedUrl(connector(), wt2(), test_name(),
+ BuildWindowId(client_id_1(), 1)));
+
+ // Need to wait for a WindowTreeClient for same reason as above.
+ WaitForWindowTreeClient();
+
+ Id window_1_2 = wt_client1()->NewWindow(2);
+ ASSERT_TRUE(window_1_2);
+ ASSERT_TRUE(
+ wt_client1()->AddWindow(BuildWindowId(client_id_1(), 1), window_1_2));
+ ASSERT_TRUE(wt_client3_.get() == nullptr);
+ wt_client3_ = EstablishClientViaEmbedWithPolicyBitmask(wt1(), window_1_2);
+ ASSERT_TRUE(wt_client3_.get() != nullptr);
+
+ // window_1_2 is ws3's root, so even though v3 is an embed root it should not
+ // be able to Embed into itself.
+ ASSERT_FALSE(EmbedUrl(connector(), wt3(), test_name(), window_1_2));
+}
+
+// Verifies that a transient window tracks its parent's lifetime.
+TEST_F(WindowTreeClientTest, TransientWindowTracksTransientParentLifetime) {
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClient(true));
+ Id window_1_1 = BuildWindowId(client_id_1(), 1);
+
+ Id window_2_1 = wt_client2()->NewWindow(1);
+ Id window_2_2 = wt_client2()->NewWindow(2);
+ Id window_2_3 = wt_client2()->NewWindow(3);
+ ASSERT_TRUE(window_2_1);
+ // window_2_* has a client_id part of client_id_2 in wt1.
+ Id window21_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_1));
+ Id window22_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_2));
+ Id window23_in_wt1 = BuildWindowId(client_id_2(), LoWord(window_2_3));
+
+ // root -> window_1_1 -> window_2_1
+ // root -> window_1_1 -> window_2_2
+ // root -> window_1_1 -> window_2_3
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_1));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_2));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_1, window_2_3));
+
+ // window_2_2 and window_2_3 now track the lifetime of window_2_1.
+ changes1()->clear();
+ wt2()->AddTransientWindow(10, window_2_1, window_2_2);
+ wt2()->AddTransientWindow(11, window_2_1, window_2_3);
+ wt_client1()->WaitForChangeCount(2);
+ EXPECT_EQ("AddTransientWindow parent = " + IdToString(window21_in_wt1) +
+ " child = " + IdToString(window22_in_wt1),
+ ChangesToDescription1(*changes1())[0]);
+ EXPECT_EQ("AddTransientWindow parent = " + IdToString(window21_in_wt1) +
+ " child = " + IdToString(window23_in_wt1),
+ ChangesToDescription1(*changes1())[1]);
+
+ changes1()->clear();
+ wt2()->RemoveTransientWindowFromParent(12, window_2_3);
+ wt_client1()->WaitForChangeCount(1);
+ EXPECT_EQ("RemoveTransientWindowFromParent parent = " +
+ IdToString(window21_in_wt1) +
+ " child = " + IdToString(window23_in_wt1),
+ SingleChangeToDescription(*changes1()));
+
+ changes1()->clear();
+ ASSERT_TRUE(wt_client2()->DeleteWindow(window_2_1));
+ wt_client1()->WaitForChangeCount(2);
+ EXPECT_EQ("WindowDeleted window=" + IdToString(window22_in_wt1),
+ ChangesToDescription1(*changes1())[0]);
+ EXPECT_EQ("WindowDeleted window=" + IdToString(window21_in_wt1),
+ ChangesToDescription1(*changes1())[1]);
+}
+
+TEST_F(WindowTreeClientTest, Ids) {
+ const Id window_1_100 = wt_client1()->NewWindow(100);
+ ASSERT_TRUE(window_1_100);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_100));
+
+ // Establish the second client at client_id_1(),100.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_100));
+
+ // client_id_1(),100 is the id in the wt_client1's id space. The new client
+ // should see client_id_2(),1 (the server id).
+ const Id window_1_100_in_ws2 = BuildWindowId(client_id_1(), 100);
+ EXPECT_EQ(window_1_100_in_ws2, wt_client2()->root_window_id());
+
+ // The first window created in the second client gets a server id of
+ // client_id_2(),1 regardless of the id the client uses.
+ const Id window_2_101 = wt_client2()->NewWindow(101);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_100_in_ws2, window_2_101));
+ const Id window_2_101_in_ws1 = BuildWindowId(client_id_2(), 101);
+ wt_client1()->WaitForChangeCount(1);
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101_in_ws1) +
+ " old_parent=null new_parent=" + IdToString(window_1_100),
+ SingleChangeToDescription(*changes1()));
+ changes1()->clear();
+
+ // Change the bounds of window_2_101 and make sure server gets it.
+ wt2()->SetWindowBounds(11, window_2_101, gfx::Rect(1, 2, 3, 4),
+ base::nullopt);
+ ASSERT_TRUE(wt_client2()->WaitForChangeCompleted(11));
+ wt_client1()->WaitForChangeCount(1);
+ EXPECT_EQ(
+ "BoundsChanged window=" + IdToString(window_2_101_in_ws1) +
+ " old_bounds=0,0 0x0 new_bounds=1,2 3x4 local_surface_id=(none)",
+ SingleChangeToDescription(*changes1()));
+ changes2()->clear();
+
+ // Remove 2_101 from wm, client1 should see the change.
+ wt1()->RemoveWindowFromParent(12, window_2_101_in_ws1);
+ ASSERT_TRUE(wt_client1()->WaitForChangeCompleted(12));
+ wt_client2()->WaitForChangeCount(1);
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101) +
+ " old_parent=" + IdToString(window_1_100_in_ws2) +
+ " new_parent=null",
+ SingleChangeToDescription(*changes2()));
+}
+
+// Tests that setting capture fails when no input event has occurred, and there
+// is no notification of lost capture.
+TEST_F(WindowTreeClientTest, ExplicitCaptureWithoutInput) {
+ Id window_1_1 = wt_client1()->NewWindow(1);
+
+ // Add the window to the root, so that they have a Display to handle input
+ // capture.
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ changes1()->clear();
+
+ // Since there has been no input, capture should not succeed. No lost capture
+ // message is expected.
+ wt1()->SetCapture(1, window_1_1);
+ wt_client1_->WaitForAllMessages();
+ EXPECT_TRUE(changes1()->empty());
+
+ // Since there is no window with capture, lost capture should not be notified.
+ wt1()->ReleaseCapture(3, window_1_1);
+ wt_client1_->WaitForAllMessages();
+ EXPECT_TRUE(changes1()->empty());
+}
+
+// TODO(jonross): Enable this once apptests can send input events to the server.
+// Enabling capture requires that the client be processing events.
+TEST_F(WindowTreeClientTest, DISABLED_ExplicitCapturePropagation) {
+ Id window_1_1 = wt_client1()->NewWindow(1);
+ Id window_1_2 = wt_client1()->NewWindow(2);
+
+ // Add the windows to the root, so that they have a Display to handle input
+ // capture.
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_1));
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_2));
+
+ changes1()->clear();
+ // Window 1 takes capture then Window 2 takes capture.
+ // Verify that window 1 has lost capture.
+ wt1()->SetCapture(1, window_1_1);
+ wt1()->SetCapture(2, window_1_2);
+ wt_client1_->WaitForChangeCount(1);
+
+ EXPECT_EQ("OnLostCapture window=" + IdToString(window_1_1),
+ SingleChangeToDescription(*changes1()));
+
+ changes1()->clear();
+ // Explicitly releasing capture should not notify of lost capture.
+ wt1()->ReleaseCapture(3, window_1_2);
+ wt_client1_->WaitForAllMessages();
+
+ EXPECT_TRUE(changes1()->empty());
+}
+
+TEST_F(WindowTreeClientTest, SurfaceIdPropagation) {
+ const Id window_1_100 = wt_client1()->NewWindow(100);
+ ASSERT_TRUE(window_1_100);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_100));
+
+ // Establish the second client at client_id_1(),100.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_100));
+ changes2()->clear();
+
+ // client_id_1(),100 is the id in the wt_client1's id space. The new client
+ // should see client_id_2(),1 (the server id).
+ const Id window_1_100_in_ws2 = BuildWindowId(client_id_1(), 100);
+ EXPECT_EQ(window_1_100_in_ws2, wt_client2()->root_window_id());
+
+ // Submit a CompositorFrame to window_1_100_in_ws2 (the embedded window in
+ // wt2) and make sure the server gets it.
+ {
+ viz::mojom::CompositorFrameSinkPtr surface_ptr;
+ viz::mojom::CompositorFrameSinkClientRequest client_request;
+ viz::mojom::CompositorFrameSinkClientPtr surface_client_ptr;
+ client_request = mojo::MakeRequest(&surface_client_ptr);
+ wt2()->AttachCompositorFrameSink(window_1_100_in_ws2,
+ mojo::MakeRequest(&surface_ptr),
+ std::move(surface_client_ptr));
+ viz::CompositorFrame compositor_frame;
+ std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
+ gfx::Rect frame_rect(0, 0, 100, 100);
+ render_pass->SetNew(1, frame_rect, frame_rect, gfx::Transform());
+ compositor_frame.render_pass_list.push_back(std::move(render_pass));
+ compositor_frame.metadata.device_scale_factor = 1.f;
+ compositor_frame.metadata.begin_frame_ack = viz::BeginFrameAck(0, 1, true);
+ viz::LocalSurfaceId local_surface_id(1, base::UnguessableToken::Create());
+ surface_ptr->SubmitCompositorFrame(local_surface_id,
+ std::move(compositor_frame), nullptr, 0);
+ }
+ // Make sure the parent connection gets the surface ID.
+ wt_client1()->WaitForChangeCount(1);
+ // Verify that the submitted frame is for |window_2_101|.
+ viz::FrameSinkId frame_sink_id =
+ changes1()->back().surface_id.frame_sink_id();
+ // FrameSinkId is based on window's ClientWindowId.
+ EXPECT_EQ(static_cast<size_t>(client_id_2()), frame_sink_id.client_id());
+ EXPECT_EQ(0u, frame_sink_id.sink_id());
+ changes1()->clear();
+
+ // The first window created in the second client gets a server id of
+ // client_id_2(),1 regardless of the id the client uses.
+ const Id window_2_101 = wt_client2()->NewWindow(101);
+ ASSERT_TRUE(wt_client2()->AddWindow(window_1_100_in_ws2, window_2_101));
+ const Id window_2_101_in_ws2 = BuildWindowId(client_id_2(), 101);
+ wt_client1()->WaitForChangeCount(1);
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_101_in_ws2) +
+ " old_parent=null new_parent=" + IdToString(window_1_100),
+ SingleChangeToDescription(*changes1()));
+ // Submit a CompositorFrame to window_2_101_in_ws2 (a regular window in
+ // wt2) and make sure client gets it.
+ {
+ viz::mojom::CompositorFrameSinkPtr surface_ptr;
+ viz::mojom::CompositorFrameSinkClientRequest client_request;
+ viz::mojom::CompositorFrameSinkClientPtr surface_client_ptr;
+ client_request = mojo::MakeRequest(&surface_client_ptr);
+ wt2()->AttachCompositorFrameSink(window_2_101,
+ mojo::MakeRequest(&surface_ptr),
+ std::move(surface_client_ptr));
+ viz::CompositorFrame compositor_frame;
+ std::unique_ptr<viz::RenderPass> render_pass = viz::RenderPass::Create();
+ gfx::Rect frame_rect(0, 0, 100, 100);
+ render_pass->SetNew(1, frame_rect, frame_rect, gfx::Transform());
+ compositor_frame.render_pass_list.push_back(std::move(render_pass));
+ compositor_frame.metadata.device_scale_factor = 1.f;
+ compositor_frame.metadata.begin_frame_ack = viz::BeginFrameAck(0, 1, true);
+ viz::LocalSurfaceId local_surface_id(2, base::UnguessableToken::Create());
+ surface_ptr->SubmitCompositorFrame(local_surface_id,
+ std::move(compositor_frame), nullptr, 0);
+ }
+ // Make sure the parent connection gets the surface ID.
+ wt_client2()->WaitForChangeCount(1);
+ // Verify that the submitted frame is for |window_2_101|.
+ viz::FrameSinkId frame_sink_id2 =
+ changes2()->back().surface_id.frame_sink_id();
+ // FrameSinkId is based on window's ClientWindowId.
+ EXPECT_NE(0u, frame_sink_id2.client_id());
+ EXPECT_EQ(LoWord(window_2_101), frame_sink_id2.sink_id());
+}
+
+// Verifies when an unknown window with a known child is added to a hierarchy
+// the known child is identified in the WindowData.
+TEST_F(WindowTreeClientTest, AddUnknownWindowKnownParent) {
+ const Id window_1_100 = wt_client1()->NewWindow(100);
+ ASSERT_TRUE(window_1_100);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window_1_100));
+
+ // Establish the second client at client_id_1(),100.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_100));
+ const Id window_2_1 = wt_client2()->NewWindow(1000);
+ const Id window_2_2 = wt_client2()->NewWindow(2000);
+ // Add 2_1 to the root, remove 2_1, add 2_1 to 2_2 and then 2_2 to the parent.
+ ASSERT_TRUE(
+ wt_client2()->AddWindow(wt_client2()->root_window_id(), window_2_1));
+ ASSERT_TRUE(wt_client2()->RemoveWindowFromParent(window_2_1));
+ ASSERT_TRUE(wt_client2()->AddWindow(window_2_2, window_2_1));
+ wt_client1()->WaitForChangeCount(2);
+ changes1()->clear();
+ ASSERT_TRUE(
+ wt_client2()->AddWindow(wt_client2()->root_window_id(), window_2_2));
+ wt_client1()->WaitForChangeCount(1);
+ const Id window_2_1_in_wm = BuildWindowId(client_id_2(), 1000);
+ const Id window_2_2_in_wm = BuildWindowId(client_id_2(), 2000);
+ EXPECT_EQ("HierarchyChanged window=" + IdToString(window_2_2_in_wm) +
+ " old_parent=null new_parent=" + IdToString(window_1_100),
+ SingleChangeToDescription(*changes1()));
+ EXPECT_EQ("[window=" + IdToString(window_2_2_in_wm) + " parent=" +
+ IdToString(window_1_100) + "],[window=" +
+ IdToString(window_2_1_in_wm) + " parent=" +
+ IdToString(window_2_2_in_wm) + "]",
+ ChangeWindowDescription(*changes1()));
+}
+
+TEST_F(WindowTreeClientTest, Transform) {
+ const Id window1 = wt_client1()->NewWindow(100);
+ ASSERT_TRUE(window1);
+ ASSERT_TRUE(wt_client1()->AddWindow(root_window_id(), window1));
+
+ // Establish the second client at |window1|.
+ ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window1));
+
+ // The first window created in the second client gets a server id of
+ // client_id_2(),1 regardless of the id the client uses.
+ const Id window1_in_client2 = BuildWindowId(client_id_1(), 100);
+ const Id window2 = wt_client2()->NewWindow(11);
+ ASSERT_TRUE(wt_client2()->AddWindow(window1_in_client2, window2));
+ const Id window2_in_client1 = BuildWindowId(client_id_2(), 11);
+ wt_client1()->WaitForChangeCount(1);
+ changes1()->clear();
+
+ // Change the transform of |window2| and make sure server gets it.
+ gfx::Transform transform;
+ transform.Scale(SkIntToMScalar(2), SkIntToMScalar(2));
+ const uint32_t transform_change_id = 12;
+ wt2()->SetWindowTransform(transform_change_id, window2, transform);
+ ASSERT_TRUE(wt_client2()->WaitForChangeCompleted(transform_change_id));
+ wt_client1()->WaitForChangeCount(1);
+ EXPECT_EQ("TransformChanged window_id=" + IdToString(window2_in_client1),
+ SingleChangeToDescription(*changes1()));
+}
+
+// TODO(sky): need to better track changes to initial client. For example,
+// that SetBounsdWindows/AddWindow and the like don't result in messages to the
+// originating client.
+
+// TODO(sky): make sure coverage of what was
+// WindowManagerTest.SecondEmbedRoot_InitService and
+// WindowManagerTest.MultipleEmbedRootsBeforeWTHReady gets added to window
+// manager
+// tests.
+
+} // namespace test
+} // namespace ws
+} // namespace ui
diff --git a/chromium/services/video_capture/BUILD.gn b/chromium/services/video_capture/BUILD.gn
index f875609ba5e..da01593c66c 100644
--- a/chromium/services/video_capture/BUILD.gn
+++ b/chromium/services/video_capture/BUILD.gn
@@ -16,7 +16,7 @@ service("video_capture") {
":lib",
"//mojo/public/cpp/system",
"//services/video_capture/public/cpp",
- "//services/video_capture/public/interfaces",
+ "//services/video_capture/public/mojom",
]
}
@@ -56,8 +56,8 @@ source_set("lib") {
"//mojo/common:common_base",
"//services/service_manager/public/cpp",
"//services/video_capture/public/cpp",
- "//services/video_capture/public/interfaces",
- "//services/video_capture/public/interfaces:constants",
+ "//services/video_capture/public/mojom",
+ "//services/video_capture/public/mojom:constants",
"//services/video_capture/public/uma",
]
}
@@ -66,6 +66,7 @@ source_set("tests") {
testonly = true
sources = [
+ "device_media_to_mojo_adapter_unittest.cc",
"test/device_factory_provider_connectortest.cc",
"test/device_factory_provider_test.cc",
"test/device_factory_provider_test.h",
@@ -76,6 +77,8 @@ source_set("tests") {
"test/fake_device_test.cc",
"test/fake_device_test.h",
"test/fake_device_unittest.cc",
+ "test/mock_device.cc",
+ "test/mock_device.h",
"test/mock_device_factory.cc",
"test/mock_device_factory.h",
"test/mock_device_test.cc",
@@ -92,7 +95,7 @@ source_set("tests") {
":lib",
":video_capture",
"//base/test:test_support",
- "//media/capture/mojo:capture_types",
+ "//media/capture/mojo:video_capture",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
"//services/service_manager/public/cpp/test:test_support",
diff --git a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
index b4892fac302..812dabd3257 100644
--- a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
+++ b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.cc
@@ -20,10 +20,10 @@ namespace {
// Translates a set of device infos reported by a VideoCaptureSystem to a set
// of device infos that the video capture service exposes to its client.
-// The Video Capture Service instances of VideoCaptureDeviceClient to
-// convert the formats provided by the VideoCaptureDevice instances. Here, we
-// translate the set of supported formats as reported by the |device_factory_|
-// to what will be output by the VideoCaptureDeviceClient we connect to it.
+// A translation is needed, because the actual video frames, on their way
+// from the VideoCaptureSystem to clients of the Video Capture Service, will
+// pass through an instance of VideoCaptureDeviceClient, which performs certain
+// format conversions.
// TODO(chfremer): A cleaner design would be to have this translation
// happen in VideoCaptureDeviceClient, and talk only to VideoCaptureDeviceClient
// instead of VideoCaptureSystem.
@@ -48,8 +48,8 @@ static void TranslateDeviceInfos(
continue;
translated_device_info.supported_formats.push_back(translated_format);
}
- if (translated_device_info.supported_formats.empty())
- continue;
+ // We explicitly need to include device infos for which there are zero
+ // supported formats reported until https://crbug.com/792260 is resolved.
translated_device_infos.push_back(translated_device_info);
}
std::move(callback).Run(translated_device_infos);
diff --git a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
index 655eed2b505..6216dc73a49 100644
--- a/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/device_factory_media_to_mojo_adapter.h
@@ -11,7 +11,7 @@
#include "media/capture/video/video_capture_system.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
-#include "services/video_capture/public/interfaces/device_factory.mojom.h"
+#include "services/video_capture/public/mojom/device_factory.mojom.h"
namespace video_capture {
diff --git a/chromium/services/video_capture/device_factory_provider_impl.cc b/chromium/services/video_capture/device_factory_provider_impl.cc
index 40b7a757ad5..3b70305da22 100644
--- a/chromium/services/video_capture/device_factory_provider_impl.cc
+++ b/chromium/services/video_capture/device_factory_provider_impl.cc
@@ -56,7 +56,10 @@ void DeviceFactoryProviderImpl::LazyInitializeDeviceFactory() {
base::ThreadTaskRunnerHandle::Get(),
// TODO(jcliang): Create a GpuMemoryBufferManager from GpuService
// here.
- nullptr);
+ nullptr,
+ // TODO(mojahsu): Create a GpuJpegDecoderMojoFactoryCB here.
+ base::BindRepeating(
+ [](media::mojom::JpegDecodeAcceleratorRequest) {}));
auto video_capture_system = std::make_unique<media::VideoCaptureSystemImpl>(
std::move(media_device_factory));
diff --git a/chromium/services/video_capture/device_factory_provider_impl.h b/chromium/services/video_capture/device_factory_provider_impl.h
index c179f2daf1b..5987091e2f0 100644
--- a/chromium/services/video_capture/device_factory_provider_impl.h
+++ b/chromium/services/video_capture/device_factory_provider_impl.h
@@ -10,7 +10,7 @@
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
-#include "services/video_capture/public/interfaces/device_factory_provider.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
namespace video_capture {
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter.cc b/chromium/services/video_capture/device_media_to_mojo_adapter.cc
index 10c6efc1fb3..1149ef45b9b 100644
--- a/chromium/services/video_capture/device_media_to_mojo_adapter.cc
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter.cc
@@ -23,7 +23,8 @@ DeviceMediaToMojoAdapter::DeviceMediaToMojoAdapter(
: service_ref_(std::move(service_ref)),
device_(std::move(device)),
jpeg_decoder_factory_callback_(jpeg_decoder_factory_callback),
- device_started_(false) {}
+ device_started_(false),
+ weak_factory_(this) {}
DeviceMediaToMojoAdapter::~DeviceMediaToMojoAdapter() {
DCHECK(thread_checker_.CalledOnValidThread());
@@ -37,17 +38,10 @@ void DeviceMediaToMojoAdapter::Start(
DCHECK(thread_checker_.CalledOnValidThread());
receiver.set_connection_error_handler(
base::Bind(&DeviceMediaToMojoAdapter::OnClientConnectionErrorOrClose,
- base::Unretained(this)));
+ weak_factory_.GetWeakPtr()));
auto receiver_adapter =
std::make_unique<ReceiverMojoToMediaAdapter>(std::move(receiver));
- // We must hold on something that allows us to unsubscribe from
- // receiver.set_connection_error_handler() when we stop the device. Otherwise,
- // we may receive a corresponding callback after having been destroyed.
- // This happens when the deletion of |receiver| is delayed (scheduled to a
- // task runner) when we release |device_|, as is the case when using
- // ReceiverOnTaskRunner.
- receiver_adapter_ptr_ = receiver_adapter.get();
auto media_receiver = std::make_unique<ReceiverOnTaskRunner>(
std::move(receiver_adapter), base::ThreadTaskRunnerHandle::Get());
@@ -118,9 +112,7 @@ void DeviceMediaToMojoAdapter::Stop() {
if (device_started_ == false)
return;
device_started_ = false;
- // Unsubscribe from connection error callbacks.
- receiver_adapter_ptr_->ResetConnectionErrorHandler();
- receiver_adapter_ptr_ = nullptr;
+ weak_factory_.InvalidateWeakPtrs();
device_->StopAndDeAllocate();
}
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter.h b/chromium/services/video_capture/device_media_to_mojo_adapter.h
index 18e97fcfdec..2d0f4de7cda 100644
--- a/chromium/services/video_capture/device_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter.h
@@ -10,12 +10,10 @@
#include "media/capture/video/video_capture_device_client.h"
#include "media/capture/video_capture_types.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
-#include "services/video_capture/public/interfaces/device.mojom.h"
+#include "services/video_capture/public/mojom/device.mojom.h"
namespace video_capture {
-class ReceiverMojoToMediaAdapter;
-
// Implementation of mojom::Device backed by a given instance of
// media::VideoCaptureDevice.
class DeviceMediaToMojoAdapter : public mojom::Device {
@@ -52,8 +50,8 @@ class DeviceMediaToMojoAdapter : public mojom::Device {
const std::unique_ptr<media::VideoCaptureDevice> device_;
media::VideoCaptureJpegDecoderFactoryCB jpeg_decoder_factory_callback_;
bool device_started_;
- ReceiverMojoToMediaAdapter* receiver_adapter_ptr_ = nullptr;
base::ThreadChecker thread_checker_;
+ base::WeakPtrFactory<DeviceMediaToMojoAdapter> weak_factory_;
};
} // namespace video_capture
diff --git a/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc b/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc
new file mode 100644
index 00000000000..f88f204f31f
--- /dev/null
+++ b/chromium/services/video_capture/device_media_to_mojo_adapter_unittest.cc
@@ -0,0 +1,115 @@
+// Copyright 2018 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/video_capture/device_media_to_mojo_adapter.h"
+
+#include "base/run_loop.h"
+#include "base/test/scoped_task_environment.h"
+#include "services/video_capture/test/mock_device.h"
+#include "services/video_capture/test/mock_receiver.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Invoke;
+using testing::_;
+
+namespace video_capture {
+
+class DeviceMediaToMojoAdapterTest : public ::testing::Test {
+ public:
+ DeviceMediaToMojoAdapterTest() = default;
+ ~DeviceMediaToMojoAdapterTest() override = default;
+
+ void SetUp() override {
+ mock_receiver_ =
+ std::make_unique<MockReceiver>(mojo::MakeRequest(&receiver_));
+ auto mock_device = std::make_unique<MockDevice>();
+ mock_device_ptr_ = mock_device.get();
+ adapter_ = std::make_unique<DeviceMediaToMojoAdapter>(
+ std::unique_ptr<service_manager::ServiceContextRef>(),
+ std::move(mock_device), media::VideoCaptureJpegDecoderFactoryCB());
+ }
+
+ void TearDown() override {
+ // The internals of ReceiverOnTaskRunner perform a DeleteSoon().
+ adapter_.reset();
+ base::RunLoop wait_loop;
+ wait_loop.RunUntilIdle();
+ }
+
+ protected:
+ MockDevice* mock_device_ptr_;
+ std::unique_ptr<DeviceMediaToMojoAdapter> adapter_;
+ std::unique_ptr<MockReceiver> mock_receiver_;
+ mojom::ReceiverPtr receiver_;
+ base::test::ScopedTaskEnvironment task_environment_;
+};
+
+TEST_F(DeviceMediaToMojoAdapterTest,
+ DeviceIsStoppedWhenReceiverClosesConnection) {
+ {
+ base::RunLoop run_loop;
+ EXPECT_CALL(*mock_device_ptr_, DoAllocateAndStart(_, _))
+ .WillOnce(Invoke(
+ [](const media::VideoCaptureParams& params,
+ std::unique_ptr<media::VideoCaptureDevice::Client>* client) {
+ (*client)->OnStarted();
+ }));
+ EXPECT_CALL(*mock_receiver_, OnStarted()).WillOnce(Invoke([&run_loop]() {
+ run_loop.Quit();
+ }));
+
+ const media::VideoCaptureParams kArbitrarySettings;
+ adapter_->Start(kArbitrarySettings, std::move(receiver_));
+ run_loop.Run();
+ }
+ {
+ base::RunLoop run_loop;
+ EXPECT_CALL(*mock_device_ptr_, DoStopAndDeAllocate())
+ .WillOnce(Invoke([&run_loop]() { run_loop.Quit(); }));
+ mock_receiver_.reset();
+ run_loop.Run();
+ }
+}
+
+// Triggers a condition that caused a use-after-free reported in
+// https://crbug.com/807887. The use-after-free happened because the connection
+// lost event handler got invoked on a base::Unretained() pointer to |adapter_|
+// after |adapter_| was released.
+TEST_F(DeviceMediaToMojoAdapterTest,
+ ReleaseInstanceSynchronouslyAfterReceiverClosedConnection) {
+ {
+ base::RunLoop run_loop;
+ EXPECT_CALL(*mock_device_ptr_, DoAllocateAndStart(_, _))
+ .WillOnce(Invoke(
+ [](const media::VideoCaptureParams& params,
+ std::unique_ptr<media::VideoCaptureDevice::Client>* client) {
+ (*client)->OnStarted();
+ }));
+ EXPECT_CALL(*mock_receiver_, OnStarted()).WillOnce(Invoke([&run_loop]() {
+ run_loop.Quit();
+ }));
+
+ const media::VideoCaptureParams kArbitrarySettings;
+ adapter_->Start(kArbitrarySettings, std::move(receiver_));
+ run_loop.Run();
+ }
+
+ {
+ base::RunLoop run_loop;
+
+ // This posts invocation of the error event handler to the end of the
+ // current sequence.
+ mock_receiver_.reset();
+
+ // This destroys the DeviceMediaToMojoAdapter, which in turn posts a
+ // DeleteSoon in ~ReceiverOnTaskRunner() to the end of the current sequence.
+ adapter_.reset();
+
+ // Give error handle chance to get invoked
+ run_loop.RunUntilIdle();
+ }
+}
+
+} // namespace video_capture
diff --git a/chromium/services/video_capture/public/cpp/BUILD.gn b/chromium/services/video_capture/public/cpp/BUILD.gn
index 59094d4721f..7871eb604ba 100644
--- a/chromium/services/video_capture/public/cpp/BUILD.gn
+++ b/chromium/services/video_capture/public/cpp/BUILD.gn
@@ -4,8 +4,6 @@
source_set("cpp") {
sources = [
- "constants.cc",
- "constants.h",
"device_to_feedback_observer_adapter.cc",
"device_to_feedback_observer_adapter.h",
"receiver_media_to_mojo_adapter.cc",
@@ -17,7 +15,7 @@ source_set("cpp") {
"//media",
"//media/capture:capture",
"//services/service_manager/public/cpp",
- "//services/video_capture/public/interfaces",
+ "//services/video_capture/public/mojom",
]
deps = [
diff --git a/chromium/services/video_capture/public/cpp/constants.cc b/chromium/services/video_capture/public/cpp/constants.cc
deleted file mode 100644
index afbdc211ad1..00000000000
--- a/chromium/services/video_capture/public/cpp/constants.cc
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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 "services/video_capture/public/cpp/constants.h"
-
-#include "build/build_config.h"
-
-namespace video_capture {
-
-const base::Feature kMojoVideoCapture {
- "MojoVideoCapture",
-#if defined(OS_MACOSX) || defined(OS_WIN)
- base::FEATURE_ENABLED_BY_DEFAULT
-#else
- base::FEATURE_DISABLED_BY_DEFAULT
-#endif
-};
-
-} // namespace video_capture
diff --git a/chromium/services/video_capture/public/cpp/constants.h b/chromium/services/video_capture/public/cpp/constants.h
deleted file mode 100644
index 9a970a5a0c0..00000000000
--- a/chromium/services/video_capture/public/cpp/constants.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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 SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_CONSTANTS_H_
-#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_CONSTANTS_H_
-
-#include "base/feature_list.h"
-
-namespace video_capture {
-
-extern const base::Feature kMojoVideoCapture;
-
-} // namespace video_capture
-
-#endif // SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_CONSTANTS_H_
diff --git a/chromium/services/video_capture/public/cpp/device_to_feedback_observer_adapter.h b/chromium/services/video_capture/public/cpp/device_to_feedback_observer_adapter.h
index b35dab01d17..88793a82778 100644
--- a/chromium/services/video_capture/public/cpp/device_to_feedback_observer_adapter.h
+++ b/chromium/services/video_capture/public/cpp/device_to_feedback_observer_adapter.h
@@ -6,7 +6,7 @@
#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_DEVICE_TO_FEEDBACK_OBSERVER_ADAPTER_H_
#include "media/capture/video/video_capture_device.h"
-#include "services/video_capture/public/interfaces/device.mojom.h"
+#include "services/video_capture/public/mojom/device.mojom.h"
namespace video_capture {
diff --git a/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h b/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h
index d9174af344f..52a50cfb0f1 100644
--- a/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/public/cpp/receiver_media_to_mojo_adapter.h
@@ -6,7 +6,7 @@
#define SERVICES_VIDEO_CAPTURE_PUBLIC_CPP_RECEIVER_MEDIA_TO_MOJO_ADAPTER_H_
#include "media/capture/video/video_frame_receiver.h"
-#include "services/video_capture/public/interfaces/receiver.mojom.h"
+#include "services/video_capture/public/mojom/receiver.mojom.h"
namespace video_capture {
diff --git a/chromium/services/video_capture/public/interfaces/BUILD.gn b/chromium/services/video_capture/public/mojom/BUILD.gn
index 48946afe49a..7ba157550ae 100644
--- a/chromium/services/video_capture/public/interfaces/BUILD.gn
+++ b/chromium/services/video_capture/public/mojom/BUILD.gn
@@ -4,7 +4,7 @@
import("//mojo/public/tools/bindings/mojom.gni")
-mojom("interfaces") {
+mojom("mojom") {
sources = [
"device.mojom",
"device_factory.mojom",
@@ -16,8 +16,8 @@ mojom("interfaces") {
]
deps = [
- "//media/capture/mojo:capture_types",
"//media/capture/mojo:image_capture",
+ "//media/capture/mojo:video_capture",
"//media/mojo/interfaces",
"//ui/gfx/geometry/mojo",
]
diff --git a/chromium/services/video_capture/public/interfaces/OWNERS b/chromium/services/video_capture/public/mojom/OWNERS
index ac44cd00686..ac44cd00686 100644
--- a/chromium/services/video_capture/public/interfaces/OWNERS
+++ b/chromium/services/video_capture/public/mojom/OWNERS
diff --git a/chromium/services/video_capture/public/interfaces/constants.mojom b/chromium/services/video_capture/public/mojom/constants.mojom
index 5a5404e0c1d..5a5404e0c1d 100644
--- a/chromium/services/video_capture/public/interfaces/constants.mojom
+++ b/chromium/services/video_capture/public/mojom/constants.mojom
diff --git a/chromium/services/video_capture/public/interfaces/device.mojom b/chromium/services/video_capture/public/mojom/device.mojom
index 0e8ea396fe9..6d0bc1b3bb0 100644
--- a/chromium/services/video_capture/public/interfaces/device.mojom
+++ b/chromium/services/video_capture/public/mojom/device.mojom
@@ -6,7 +6,7 @@ module video_capture.mojom;
import "media/capture/mojo/video_capture_types.mojom";
import "media/capture/mojo/image_capture.mojom";
-import "services/video_capture/public/interfaces/receiver.mojom";
+import "services/video_capture/public/mojom/receiver.mojom";
// Represents access to a video capture device available on the machine.
// Note: Instead of offering an explicit Stop() method, the device
diff --git a/chromium/services/video_capture/public/interfaces/device_factory.mojom b/chromium/services/video_capture/public/mojom/device_factory.mojom
index 9c0e744a168..2858c4f5a14 100644
--- a/chromium/services/video_capture/public/interfaces/device_factory.mojom
+++ b/chromium/services/video_capture/public/mojom/device_factory.mojom
@@ -5,9 +5,9 @@
module video_capture.mojom;
import "media/capture/mojo/video_capture_types.mojom";
-import "services/video_capture/public/interfaces/device.mojom";
-import "services/video_capture/public/interfaces/producer.mojom";
-import "services/video_capture/public/interfaces/virtual_device.mojom";
+import "services/video_capture/public/mojom/device.mojom";
+import "services/video_capture/public/mojom/producer.mojom";
+import "services/video_capture/public/mojom/virtual_device.mojom";
enum DeviceAccessResultCode {
NOT_INITIALIZED,
diff --git a/chromium/services/video_capture/public/interfaces/device_factory_provider.mojom b/chromium/services/video_capture/public/mojom/device_factory_provider.mojom
index 9f91c0cdedc..857251bb93a 100644
--- a/chromium/services/video_capture/public/interfaces/device_factory_provider.mojom
+++ b/chromium/services/video_capture/public/mojom/device_factory_provider.mojom
@@ -4,7 +4,7 @@
module video_capture.mojom;
-import "services/video_capture/public/interfaces/device_factory.mojom";
+import "services/video_capture/public/mojom/device_factory.mojom";
// Entry point to the Video Capture Service API.
// The factory provides access to the capture devices connected to the system.
diff --git a/chromium/services/video_capture/public/interfaces/producer.mojom b/chromium/services/video_capture/public/mojom/producer.mojom
index 6f927aa66c0..6f927aa66c0 100644
--- a/chromium/services/video_capture/public/interfaces/producer.mojom
+++ b/chromium/services/video_capture/public/mojom/producer.mojom
diff --git a/chromium/services/video_capture/public/interfaces/receiver.mojom b/chromium/services/video_capture/public/mojom/receiver.mojom
index 6ec99df97cf..6ec99df97cf 100644
--- a/chromium/services/video_capture/public/interfaces/receiver.mojom
+++ b/chromium/services/video_capture/public/mojom/receiver.mojom
diff --git a/chromium/services/video_capture/public/interfaces/testing_controls.mojom b/chromium/services/video_capture/public/mojom/testing_controls.mojom
index fd5ac9761e8..fd5ac9761e8 100644
--- a/chromium/services/video_capture/public/interfaces/testing_controls.mojom
+++ b/chromium/services/video_capture/public/mojom/testing_controls.mojom
diff --git a/chromium/services/video_capture/public/interfaces/virtual_device.mojom b/chromium/services/video_capture/public/mojom/virtual_device.mojom
index 34c52b407ae..78bb758f55f 100644
--- a/chromium/services/video_capture/public/interfaces/virtual_device.mojom
+++ b/chromium/services/video_capture/public/mojom/virtual_device.mojom
@@ -6,7 +6,7 @@ module video_capture.mojom;
import "media/capture/mojo/video_capture_types.mojom";
import "media/mojo/interfaces/media_types.mojom";
-import "services/video_capture/public/interfaces/producer.mojom";
+import "services/video_capture/public/mojom/producer.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
// Interface for a producer to feed video frames into a virtual
diff --git a/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc b/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc
index ed3b1faef8c..55f9e8fd664 100644
--- a/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc
+++ b/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc
@@ -80,10 +80,6 @@ ReceiverMojoToMediaAdapter::ReceiverMojoToMediaAdapter(
ReceiverMojoToMediaAdapter::~ReceiverMojoToMediaAdapter() = default;
-void ReceiverMojoToMediaAdapter::ResetConnectionErrorHandler() {
- receiver_.set_connection_error_handler(base::Closure());
-}
-
void ReceiverMojoToMediaAdapter::OnNewBufferHandle(
int buffer_id,
std::unique_ptr<media::VideoCaptureDevice::Client::Buffer::HandleProvider>
diff --git a/chromium/services/video_capture/receiver_mojo_to_media_adapter.h b/chromium/services/video_capture/receiver_mojo_to_media_adapter.h
index 3b296919faa..98a1c15859b 100644
--- a/chromium/services/video_capture/receiver_mojo_to_media_adapter.h
+++ b/chromium/services/video_capture/receiver_mojo_to_media_adapter.h
@@ -7,7 +7,7 @@
#include "base/single_thread_task_runner.h"
#include "media/capture/video/video_frame_receiver.h"
-#include "services/video_capture/public/interfaces/receiver.mojom.h"
+#include "services/video_capture/public/mojom/receiver.mojom.h"
namespace video_capture {
@@ -47,8 +47,6 @@ class ReceiverMojoToMediaAdapter : public media::VideoFrameReceiver {
ReceiverMojoToMediaAdapter(mojom::ReceiverPtr receiver);
~ReceiverMojoToMediaAdapter() override;
- void ResetConnectionErrorHandler();
-
// media::VideoFrameReceiver implementation.
void OnNewBufferHandle(
int buffer_id,
diff --git a/chromium/services/video_capture/scoped_access_permission_media_to_mojo_adapter.h b/chromium/services/video_capture/scoped_access_permission_media_to_mojo_adapter.h
index bfe1135e8c8..4ef3e5d4ca3 100644
--- a/chromium/services/video_capture/scoped_access_permission_media_to_mojo_adapter.h
+++ b/chromium/services/video_capture/scoped_access_permission_media_to_mojo_adapter.h
@@ -6,7 +6,7 @@
#define SERVICES_VIDEO_CAPTURE_SCOPED_ACCESS_PERMISSION_MEDIA_TO_MOJO_ADAPTER_H_
#include "media/capture/video/video_capture_device_client.h"
-#include "services/video_capture/public/interfaces/receiver.mojom.h"
+#include "services/video_capture/public/mojom/receiver.mojom.h"
namespace video_capture {
diff --git a/chromium/services/video_capture/service_impl.cc b/chromium/services/video_capture/service_impl.cc
index 478e65fdc9e..4f145c4bf8c 100644
--- a/chromium/services/video_capture/service_impl.cc
+++ b/chromium/services/video_capture/service_impl.cc
@@ -7,7 +7,7 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/video_capture/device_factory_provider_impl.h"
-#include "services/video_capture/public/interfaces/constants.mojom.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/public/uma/video_capture_service_event.h"
#include "services/video_capture/testing_controls_impl.h"
@@ -21,15 +21,20 @@ ServiceImpl::~ServiceImpl() {
DCHECK(thread_checker_.CalledOnValidThread());
}
+// static
+std::unique_ptr<service_manager::Service> ServiceImpl::Create() {
+ return std::make_unique<ServiceImpl>();
+}
+
void ServiceImpl::OnStart() {
DCHECK(thread_checker_.CalledOnValidThread());
video_capture::uma::LogVideoCaptureServiceEvent(
video_capture::uma::SERVICE_STARTED);
- ref_factory_ =
- std::make_unique<service_manager::ServiceContextRefFactory>(base::Bind(
- &ServiceImpl::MaybeRequestQuitDelayed, base::Unretained(this)));
+ ref_factory_ = std::make_unique<service_manager::ServiceContextRefFactory>(
+ base::BindRepeating(&ServiceImpl::MaybeRequestQuitDelayed,
+ weak_factory_.GetWeakPtr()));
registry_.AddInterface<mojom::DeviceFactoryProvider>(
// Unretained |this| is safe because |registry_| is owned by |this|.
base::Bind(&ServiceImpl::OnDeviceFactoryProviderRequest,
@@ -97,7 +102,7 @@ void ServiceImpl::MaybeRequestQuit() {
if (ref_factory_->HasNoRefs()) {
video_capture::uma::LogVideoCaptureServiceEvent(
video_capture::uma::SERVICE_SHUTTING_DOWN_BECAUSE_NO_CLIENT);
- context()->RequestQuit();
+ context()->CreateQuitClosure().Run();
} else {
video_capture::uma::LogVideoCaptureServiceEvent(
video_capture::uma::SERVICE_SHUTDOWN_TIMEOUT_CANCELED);
diff --git a/chromium/services/video_capture/service_impl.h b/chromium/services/video_capture/service_impl.h
index 011a5e9d338..977f90addf8 100644
--- a/chromium/services/video_capture/service_impl.h
+++ b/chromium/services/video_capture/service_impl.h
@@ -13,8 +13,8 @@
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
#include "services/video_capture/device_factory_provider_impl.h"
-#include "services/video_capture/public/interfaces/device_factory_provider.mojom.h"
-#include "services/video_capture/public/interfaces/testing_controls.mojom.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
+#include "services/video_capture/public/mojom/testing_controls.mojom.h"
#if defined(OS_WIN)
#include "base/win/scoped_com_initializer.h"
@@ -27,6 +27,8 @@ class ServiceImpl : public service_manager::Service {
ServiceImpl();
~ServiceImpl() override;
+ static std::unique_ptr<service_manager::Service> Create();
+
// service_manager::Service implementation.
void OnStart() override;
void OnBindInterface(const service_manager::BindSourceInfo& source_info,
diff --git a/chromium/services/video_capture/testing_controls_impl.h b/chromium/services/video_capture/testing_controls_impl.h
index f0a17fe53f9..860820be50d 100644
--- a/chromium/services/video_capture/testing_controls_impl.h
+++ b/chromium/services/video_capture/testing_controls_impl.h
@@ -6,7 +6,7 @@
#define SERVICES_VIDEO_CAPTURE_TESTING_CONTROLS_IMPL_H_
#include "services/service_manager/public/cpp/service_context_ref.h"
-#include "services/video_capture/public/interfaces/testing_controls.mojom.h"
+#include "services/video_capture/public/mojom/testing_controls.mojom.h"
namespace video_capture {
diff --git a/chromium/services/video_capture/virtual_device_enabled_device_factory.h b/chromium/services/video_capture/virtual_device_enabled_device_factory.h
index 386ed3ea685..4f95ced0f03 100644
--- a/chromium/services/video_capture/virtual_device_enabled_device_factory.h
+++ b/chromium/services/video_capture/virtual_device_enabled_device_factory.h
@@ -9,9 +9,9 @@
#include "mojo/public/cpp/bindings/binding.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
-#include "services/video_capture/public/interfaces/device.mojom.h"
-#include "services/video_capture/public/interfaces/device_factory.mojom.h"
-#include "services/video_capture/public/interfaces/virtual_device.mojom.h"
+#include "services/video_capture/public/mojom/device.mojom.h"
+#include "services/video_capture/public/mojom/device_factory.mojom.h"
+#include "services/video_capture/public/mojom/virtual_device.mojom.h"
namespace video_capture {
diff --git a/chromium/services/video_capture/virtual_device_mojo_adapter.cc b/chromium/services/video_capture/virtual_device_mojo_adapter.cc
index 7b553323a02..58eb199d015 100644
--- a/chromium/services/video_capture/virtual_device_mojo_adapter.cc
+++ b/chromium/services/video_capture/virtual_device_mojo_adapter.cc
@@ -12,7 +12,7 @@
#include "media/capture/video/video_capture_buffer_tracker_factory_impl.h"
#include "mojo/public/cpp/bindings/callback_helpers.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/video_capture/public/interfaces/constants.mojom.h"
+#include "services/video_capture/public/mojom/constants.mojom.h"
#include "services/video_capture/scoped_access_permission_media_to_mojo_adapter.h"
namespace {
diff --git a/chromium/services/video_capture/virtual_device_mojo_adapter.h b/chromium/services/video_capture/virtual_device_mojo_adapter.h
index 8f2f08a8845..f06f65a0762 100644
--- a/chromium/services/video_capture/virtual_device_mojo_adapter.h
+++ b/chromium/services/video_capture/virtual_device_mojo_adapter.h
@@ -9,9 +9,9 @@
#include "media/capture/video/video_capture_buffer_pool.h"
#include "media/capture/video_capture_types.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
-#include "services/video_capture/public/interfaces/device.mojom.h"
-#include "services/video_capture/public/interfaces/producer.mojom.h"
-#include "services/video_capture/public/interfaces/virtual_device.mojom.h"
+#include "services/video_capture/public/mojom/device.mojom.h"
+#include "services/video_capture/public/mojom/producer.mojom.h"
+#include "services/video_capture/public/mojom/virtual_device.mojom.h"
namespace video_capture {
diff --git a/chromium/services/viz/privileged/interfaces/BUILD.gn b/chromium/services/viz/privileged/interfaces/BUILD.gn
index f956978673c..667962aea05 100644
--- a/chromium/services/viz/privileged/interfaces/BUILD.gn
+++ b/chromium/services/viz/privileged/interfaces/BUILD.gn
@@ -10,6 +10,7 @@ mojom("interfaces") {
]
public_deps = [
+ "//components/discardable_memory/public/interfaces",
"//services/viz/privileged/interfaces/compositing",
"//services/viz/privileged/interfaces/gl",
"//services/viz/public/interfaces",
@@ -26,7 +27,7 @@ source_set("unit_tests") {
deps = [
"//base/test:test_support",
"//components/viz/common:common",
- "//media/capture/mojo:capture_types",
+ "//media/capture/mojo:video_capture",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
"//services/viz/privileged/interfaces/compositing",
diff --git a/chromium/services/viz/privileged/interfaces/compositing/BUILD.gn b/chromium/services/viz/privileged/interfaces/compositing/BUILD.gn
index 3d5aab075ae..6ea4fe9e4fa 100644
--- a/chromium/services/viz/privileged/interfaces/compositing/BUILD.gn
+++ b/chromium/services/viz/privileged/interfaces/compositing/BUILD.gn
@@ -15,7 +15,7 @@ mojom("compositing") {
public_deps = [
"//gpu/ipc/common:interfaces",
- "//media/capture/mojo:capture_types",
+ "//media/capture/mojo:video_capture",
"//media/mojo/interfaces:interfaces",
"//mojo/common:common_custom_types",
"//services/viz/public/interfaces",
diff --git a/chromium/services/viz/privileged/interfaces/compositing/display_private.mojom b/chromium/services/viz/privileged/interfaces/compositing/display_private.mojom
index 90a4e0e4c70..f2082e65137 100644
--- a/chromium/services/viz/privileged/interfaces/compositing/display_private.mojom
+++ b/chromium/services/viz/privileged/interfaces/compositing/display_private.mojom
@@ -23,10 +23,16 @@ interface DisplayPrivate {
gfx.mojom.ColorSpace device_color_space);
SetOutputIsSecure(bool secure);
- // Locks the BeginFrame vsync interval for this display to |interval| and
- // ignores vsync interval information from other sources. This will do nothing
- // if the display is using an external BeginFrame source.
+ // Locks the vsync interval used to generate BeginFrames for this display to
+ // |interval|. Changes to vsync interval from other sources will be ignored.
+ // This will do nothing if the display is using an external BeginFrame source.
SetAuthoritativeVSyncInterval(mojo.common.mojom.TimeDelta interval);
+
+ // Updates vsync parameters used to generate BeginFrames for this display.
+ // This will do nothing if the display is using an external BeginFrame source.
+ SetDisplayVSyncParameters(
+ mojo.common.mojom.TimeTicks timebase,
+ mojo.common.mojom.TimeDelta interval);
};
interface DisplayClient {
diff --git a/chromium/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom b/chromium/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
index bc5ba2b0c56..c52119018d7 100644
--- a/chromium/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
+++ b/chromium/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
@@ -60,6 +60,14 @@ interface FrameSinkManager {
// message pipe to the client will be closed.
InvalidateFrameSinkId(FrameSinkId frame_sink_id);
+ // Tells FrameSinkManger to report when a synchronization event completes via
+ // tracing and UMA and the duration of that event. A synchronization event
+ // occurs when a CompositorFrame submitted to the CompositorFrameSink
+ // specified by |frame_sink_id| activates after having been blocked by
+ // unresolved dependencies.
+ EnableSynchronizationReporting(FrameSinkId frame_sink_id,
+ string reporting_label);
+
// |debug_label| is used when printing out the surface hierarchy so we know
// which clients are contributing which surfaces.
SetFrameSinkDebugLabel(FrameSinkId frame_sink_id, string debug_label);
@@ -83,6 +91,13 @@ interface FrameSinkManager {
CompositorFrameSink& compositor_frame_sink,
CompositorFrameSinkClient compositor_frame_sink_client);
+ // Destroys CompositorFrameSink created by Create[Root]CompositorFrameSink().
+ // This function should only be used synchronously for destroying root
+ // CompositorFrameSinks to ensure the GL context/surface is destroyed before
+ // the platform window.
+ [Sync]
+ DestroyCompositorFrameSink(FrameSinkId frame_sink_id) => ();
+
// Set up a BeginFrame relationship between two FrameSinkIds. In this case,
// the child inherits the viz::BeginFrameSource from the parent if it doesn't
// already have a viz::BeginFrameSource.
@@ -109,6 +124,9 @@ interface FrameSinkManager {
// Creates a FrameSinkVideoCapturer instance.
CreateVideoCapturer(FrameSinkVideoCapturer& request);
+
+ // Marks the given SurfaceIds for destruction.
+ EvictSurfaces(array<SurfaceId> surface_ids);
};
// The FrameSinkManagerClient interface is implemented by the Display
diff --git a/chromium/services/viz/privileged/interfaces/compositing/renderer_settings.mojom b/chromium/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
index 7c348990bed..1465900524b 100644
--- a/chromium/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
+++ b/chromium/services/viz/privileged/interfaces/compositing/renderer_settings.mojom
@@ -4,8 +4,6 @@
module viz.mojom;
-import "services/viz/public/interfaces/compositing/resource_settings.mojom";
-
struct RendererSettings {
bool allow_antialiasing;
bool finish_rendering_on_resize;
@@ -15,10 +13,10 @@ struct RendererSettings {
int32 highp_threshold_min;
bool partial_swap_enabled;
bool release_overlay_resources_after_gpu_query;
- ResourceSettings resource_settings;
bool should_clear_root_render_pass;
bool show_overdraw_feedback;
bool enable_draw_occlusion;
int32 slow_down_compositing_scale_factor;
bool use_skia_renderer;
+ bool allow_overlays;
};
diff --git a/chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc b/chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
index 63b8414955c..16a357bc6ad 100644
--- a/chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
+++ b/chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.cc
@@ -26,7 +26,8 @@ bool StructTraits<viz::mojom::RendererSettingsDataView, viz::RendererSettings>::
out->slow_down_compositing_scale_factor =
data.slow_down_compositing_scale_factor();
out->use_skia_renderer = data.use_skia_renderer();
- return data.ReadResourceSettings(&out->resource_settings);
+ out->allow_overlays = data.allow_overlays();
+ return true;
}
} // namespace mojo
diff --git a/chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h b/chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
index 092ebbe0312..e2a739db105 100644
--- a/chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
+++ b/chromium/services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h
@@ -12,11 +12,6 @@ namespace mojo {
template <>
struct StructTraits<viz::mojom::RendererSettingsDataView,
viz::RendererSettings> {
- static const viz::ResourceSettings& resource_settings(
- const viz::RendererSettings& input) {
- return input.resource_settings;
- }
-
static bool allow_antialiasing(const viz::RendererSettings& input) {
return input.allow_antialiasing;
}
@@ -72,6 +67,10 @@ struct StructTraits<viz::mojom::RendererSettingsDataView,
return input.use_skia_renderer;
}
+ static bool allow_overlays(const viz::RendererSettings& input) {
+ return input.allow_overlays;
+ }
+
static bool Read(viz::mojom::RendererSettingsDataView data,
viz::RendererSettings* out);
};
diff --git a/chromium/services/viz/privileged/interfaces/gl/BUILD.gn b/chromium/services/viz/privileged/interfaces/gl/BUILD.gn
index 26dd41cb7f1..11b4d416feb 100644
--- a/chromium/services/viz/privileged/interfaces/gl/BUILD.gn
+++ b/chromium/services/viz/privileged/interfaces/gl/BUILD.gn
@@ -17,6 +17,6 @@ mojom("gl") {
"//media/mojo/interfaces",
"//ui/gfx/geometry/mojo",
"//ui/gfx/mojo",
- "//url/mojo:url_mojom_gurl",
+ "//url/mojom:url_mojom_gurl",
]
}
diff --git a/chromium/services/viz/privileged/interfaces/gl/gpu_host.mojom b/chromium/services/viz/privileged/interfaces/gl/gpu_host.mojom
index c23f711066f..3c8d8396b68 100644
--- a/chromium/services/viz/privileged/interfaces/gl/gpu_host.mojom
+++ b/chromium/services/viz/privileged/interfaces/gl/gpu_host.mojom
@@ -8,7 +8,7 @@ import "gpu/ipc/common/gpu_feature_info.mojom";
import "gpu/ipc/common/gpu_info.mojom";
import "gpu/ipc/common/surface_handle.mojom";
import "services/viz/privileged/interfaces/gl/context_lost_reason.mojom";
-import "url/mojo/url.mojom";
+import "url/mojom/url.mojom";
// Communication channel from the gpu process to the gpu host. This interface
// should never have any sync function calls.
diff --git a/chromium/services/viz/privileged/interfaces/struct_traits_unittest.cc b/chromium/services/viz/privileged/interfaces/struct_traits_unittest.cc
index 978538fc494..9eefafcd6f1 100644
--- a/chromium/services/viz/privileged/interfaces/struct_traits_unittest.cc
+++ b/chromium/services/viz/privileged/interfaces/struct_traits_unittest.cc
@@ -6,10 +6,8 @@
#include "base/message_loop/message_loop.h"
#include "components/viz/common/display/renderer_settings.h"
-#include "components/viz/common/resources/resource_settings.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/viz/privileged/interfaces/compositing/renderer_settings_struct_traits.h"
-#include "services/viz/public/cpp/compositing/resource_settings_struct_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace viz {
@@ -18,18 +16,10 @@ namespace {
using StructTraitsTest = testing::Test;
-constexpr size_t kArbitrarySize = 32;
-constexpr bool kArbitraryBool = true;
-
TEST_F(StructTraitsTest, RendererSettings) {
- ResourceSettings arbitrary_resource_settings;
- arbitrary_resource_settings.texture_id_allocation_chunk_size = kArbitrarySize;
- arbitrary_resource_settings.use_gpu_memory_buffer_resources = kArbitraryBool;
-
RendererSettings input;
// Set |input| to non-default values.
- input.resource_settings = arbitrary_resource_settings;
input.allow_antialiasing = false;
input.force_antialiasing = true;
input.force_blending_with_shaders = true;
@@ -45,10 +35,6 @@ TEST_F(StructTraitsTest, RendererSettings) {
RendererSettings output;
mojom::RendererSettings::Deserialize(
mojom::RendererSettings::Serialize(&input), &output);
- EXPECT_EQ(input.resource_settings.texture_id_allocation_chunk_size,
- output.resource_settings.texture_id_allocation_chunk_size);
- EXPECT_EQ(input.resource_settings.use_gpu_memory_buffer_resources,
- output.resource_settings.use_gpu_memory_buffer_resources);
EXPECT_EQ(input.allow_antialiasing, output.allow_antialiasing);
EXPECT_EQ(input.force_antialiasing, output.force_antialiasing);
EXPECT_EQ(input.force_blending_with_shaders,
diff --git a/chromium/services/viz/privileged/interfaces/viz_main.mojom b/chromium/services/viz/privileged/interfaces/viz_main.mojom
index 84f6b0b146a..c032829269a 100644
--- a/chromium/services/viz/privileged/interfaces/viz_main.mojom
+++ b/chromium/services/viz/privileged/interfaces/viz_main.mojom
@@ -4,6 +4,8 @@
module viz.mojom;
+import "mojo/common/values.mojom";
+import "components/discardable_memory/public/interfaces/discardable_shared_memory_manager.mojom";
import "services/viz/public/interfaces/compositing/compositing_mode_watcher.mojom";
import "services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom";
import "services/viz/privileged/interfaces/gl/gpu_host.mojom";
@@ -13,8 +15,12 @@ struct FrameSinkManagerParams {
// An id that changes for each viz process restart.
uint32 restart_id;
+ // Indicates whether CompositorFrames should activate after the deadline
+ // below passes.
+ bool use_activation_deadline = true;
+
// Default number of frames to CompositorFrame activation deadline.
- uint32 number_of_frames_to_activation_deadline = 4;
+ uint32 activation_deadline_in_frames = 4;
// Host to viz interface.
FrameSinkManager& frame_sink_manager;
@@ -34,5 +40,6 @@ interface VizMain {
CreateGpuService(GpuService& gpu_service,
GpuHost gpu_host,
+ discardable_memory.mojom.DiscardableSharedMemoryManager discardable_memory_manager,
handle<shared_buffer>? activity_flags);
};
diff --git a/chromium/services/viz/public/cpp/compositing/BUILD.gn b/chromium/services/viz/public/cpp/compositing/BUILD.gn
index 4ae9d32a854..9aa6fa5a846 100644
--- a/chromium/services/viz/public/cpp/compositing/BUILD.gn
+++ b/chromium/services/viz/public/cpp/compositing/BUILD.gn
@@ -14,7 +14,7 @@ source_set("tests") {
"//components/viz/common:common",
"//components/viz/test:test_support",
"//gpu/ipc/common:struct_traits",
- "//media/capture/mojo:capture_types",
+ "//media/capture/mojo:video_capture",
"//services/service_manager/public/cpp",
"//services/service_manager/public/cpp:service_test_support",
"//services/viz/public/interfaces",
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap b/chromium/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
index bd7a79b41c0..acdf6407f84 100644
--- a/chromium/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
+++ b/chromium/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
@@ -19,7 +19,6 @@ traits_headers = [
"//services/viz/public/cpp/compositing/selection_struct_traits.h",
"//services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h",
"//services/viz/public/cpp/compositing/transferable_resource_struct_traits.h",
- "//skia/public/interfaces/image_filter_struct_traits.h",
"//ui/gfx/mojo/selection_bound_struct_traits.h",
"//ui/gfx/mojo/transform_struct_traits.h",
"//ui/latency/mojo/latency_info_struct_traits.h",
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc b/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
index 1b2f35c3584..dda926fd599 100644
--- a/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.cc
@@ -29,7 +29,6 @@ bool StructTraits<viz::mojom::CompositorFrameMetadataDataView,
out->min_page_scale_factor = data.min_page_scale_factor();
out->max_page_scale_factor = data.max_page_scale_factor();
- out->root_overflow_x_hidden = data.root_overflow_x_hidden();
out->root_overflow_y_hidden = data.root_overflow_y_hidden();
out->may_contain_video = data.may_contain_video();
out->is_resourceless_software_draw_with_scroll_or_animation =
@@ -45,7 +44,7 @@ bool StructTraits<viz::mojom::CompositorFrameMetadataDataView,
return data.ReadSelection(&out->selection) &&
data.ReadLatencyInfo(&out->latency_info) &&
data.ReadReferencedSurfaces(&out->referenced_surfaces) &&
- data.ReadDeadlineInFrames(&out->deadline_in_frames) &&
+ data.ReadDeadline(&out->deadline) &&
data.ReadActivationDependencies(&out->activation_dependencies) &&
data.ReadBeginFrameAck(&out->begin_frame_ack);
}
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h b/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
index 968dd063ca3..8211350b198 100644
--- a/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h
@@ -51,11 +51,6 @@ struct StructTraits<viz::mojom::CompositorFrameMetadataDataView,
return metadata.max_page_scale_factor;
}
- static bool root_overflow_x_hidden(
- const viz::CompositorFrameMetadata& metadata) {
- return metadata.root_overflow_x_hidden;
- }
-
static bool root_overflow_y_hidden(
const viz::CompositorFrameMetadata& metadata) {
return metadata.root_overflow_y_hidden;
@@ -115,9 +110,9 @@ struct StructTraits<viz::mojom::CompositorFrameMetadataDataView,
return metadata.activation_dependencies;
}
- static const base::Optional<uint32_t>& deadline_in_frames(
+ static const viz::FrameDeadline& deadline(
const viz::CompositorFrameMetadata& metadata) {
- return metadata.deadline_in_frames;
+ return metadata.deadline;
}
static uint32_t content_source_id(
diff --git a/chromium/services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc b/chromium/services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc
index 17cbe9928b6..71b5934faa5 100644
--- a/chromium/services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/compositor_frame_struct_traits.cc
@@ -17,7 +17,9 @@ bool StructTraits<viz::mojom::CompositorFrameDataView, viz::CompositorFrame>::
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
"StructTraits::CompositorFrame::Read");
return data.ReadPasses(&out->render_pass_list) &&
- !out->render_pass_list.empty() && data.ReadMetadata(&out->metadata) &&
+ !out->render_pass_list.empty() &&
+ !out->render_pass_list.back()->output_rect.size().IsEmpty() &&
+ data.ReadMetadata(&out->metadata) &&
data.ReadResources(&out->resource_list);
}
diff --git a/chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc b/chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
index 9825cbf4a6c..f5d8b2cfac0 100644
--- a/chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
@@ -91,16 +91,13 @@ bool StructTraits<viz::mojom::CopyOutputRequestDataView,
}
request->SetScaleRatio(scale_from, scale_to);
- if (!data.ReadSource(&request->source_))
- return false;
-
- if (!data.ReadArea(&request->area_))
+ if (!data.ReadSource(&request->source_) || !data.ReadArea(&request->area_) ||
+ !data.ReadResultSelection(&request->result_selection_) ||
+ !data.ReadMailbox(&request->mailbox_) ||
+ !data.ReadSyncToken(&request->sync_token_)) {
return false;
+ }
- if (!data.ReadMailbox(&request->mailbox_))
- return false;
- if (!data.ReadSyncToken(&request->sync_token_))
- return false;
// Mailbox and SyncToken always come together.
if (!request->mailbox_ != !request->sync_token_)
return false;
diff --git a/chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h b/chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
index 494c34f667b..9ddac49f5b1 100644
--- a/chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
@@ -7,6 +7,7 @@
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "mojo/common/common_custom_types_struct_traits.h"
+#include "services/viz/public/cpp/compositing/copy_output_result_struct_traits.h"
#include "services/viz/public/interfaces/compositing/copy_output_request.mojom.h"
#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
@@ -40,6 +41,11 @@ struct StructTraits<viz::mojom::CopyOutputRequestDataView,
return request->area_;
}
+ static const base::Optional<gfx::Rect>& result_selection(
+ const std::unique_ptr<viz::CopyOutputRequest>& request) {
+ return request->result_selection_;
+ }
+
static const base::Optional<gpu::Mailbox>& mailbox(
const std::unique_ptr<viz::CopyOutputRequest>& request) {
return request->mailbox_;
diff --git a/chromium/services/viz/public/cpp/compositing/copy_output_result.typemap b/chromium/services/viz/public/cpp/compositing/copy_output_result.typemap
index 31a707a262a..60449c8ec07 100644
--- a/chromium/services/viz/public/cpp/compositing/copy_output_result.typemap
+++ b/chromium/services/viz/public/cpp/compositing/copy_output_result.typemap
@@ -4,11 +4,12 @@
mojom = "//services/viz/public/interfaces/compositing/copy_output_result.mojom"
public_headers = [ "//components/viz/common/frame_sinks/copy_output_result.h" ]
-traits_headers = [ "//services/viz/public/cpp/compositing/copy_output_result_struct_traits.h" ]
+traits_headers = [
+ "//services/viz/public/cpp/compositing/copy_output_result_struct_traits.h",
+]
public_deps = [
"//cc",
"//components/viz/common",
- "//skia/public/interfaces:struct_traits",
]
sources = [
"//services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc",
diff --git a/chromium/services/viz/public/cpp/compositing/filter_operation_struct_traits.h b/chromium/services/viz/public/cpp/compositing/filter_operation_struct_traits.h
index 4d668312567..9788324bd1c 100644
--- a/chromium/services/viz/public/cpp/compositing/filter_operation_struct_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/filter_operation_struct_traits.h
@@ -7,11 +7,13 @@
#include "base/containers/span.h"
#include "base/memory/aligned_memory.h"
+#include "base/optional.h"
#include "cc/paint/filter_operation.h"
#include "cc/paint/paint_filter.h"
#include "services/viz/public/cpp/compositing/paint_filter_struct_traits.h"
#include "services/viz/public/interfaces/compositing/filter_operation.mojom-shared.h"
#include "skia/public/interfaces/blur_image_filter_tile_mode_struct_traits.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
namespace mojo {
@@ -135,10 +137,11 @@ struct StructTraits<viz::mojom::FilterOperationDataView, cc::FilterOperation> {
return operation.image_filter();
}
- static base::span<const float> matrix(const cc::FilterOperation& operation) {
+ static base::Optional<base::span<const float>> matrix(
+ const cc::FilterOperation& operation) {
if (operation.type() != cc::FilterOperation::COLOR_MATRIX)
- return base::span<const float>();
- return operation.matrix();
+ return base::nullopt;
+ return base::make_span(operation.matrix());
}
static base::span<const gfx::Rect> shape(
diff --git a/chromium/services/viz/public/cpp/compositing/filter_operations.typemap b/chromium/services/viz/public/cpp/compositing/filter_operations.typemap
index d5f63c8328f..77b56b12311 100644
--- a/chromium/services/viz/public/cpp/compositing/filter_operations.typemap
+++ b/chromium/services/viz/public/cpp/compositing/filter_operations.typemap
@@ -4,5 +4,10 @@
mojom = "//services/viz/public/interfaces/compositing/filter_operations.mojom"
public_headers = [ "//cc/paint/filter_operations.h" ]
-traits_headers = [ "//services/viz/public/cpp/compositing/filter_operations_struct_traits.h" ]
+traits_headers = [
+ "//services/viz/public/cpp/compositing/filter_operations_struct_traits.h",
+]
+sources = [
+ "//services/viz/public/cpp/compositing/filter_operations_struct_traits.cc",
+]
type_mappings = [ "viz.mojom.FilterOperations=cc::FilterOperations" ]
diff --git a/chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.cc b/chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.cc
new file mode 100644
index 00000000000..a95213a1b73
--- /dev/null
+++ b/chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.cc
@@ -0,0 +1,29 @@
+// Copyright 2018 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/viz/public/cpp/compositing/filter_operations_struct_traits.h"
+
+#include "cc/paint/filter_operations.h"
+#include "services/viz/public/cpp/compositing/filter_operation_struct_traits.h"
+
+namespace mojo {
+
+// static
+const std::vector<cc::FilterOperation>& StructTraits<
+ viz::mojom::FilterOperationsDataView,
+ cc::FilterOperations>::operations(const cc::FilterOperations& operations) {
+ return operations.operations();
+}
+
+// static
+bool StructTraits<viz::mojom::FilterOperationsDataView, cc::FilterOperations>::
+ Read(viz::mojom::FilterOperationsDataView data, cc::FilterOperations* out) {
+ std::vector<cc::FilterOperation> operations;
+ if (!data.ReadOperations(&operations))
+ return false;
+ *out = cc::FilterOperations(std::move(operations));
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.h b/chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.h
index 591bfcfbd41..fefa9a09004 100644
--- a/chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/filter_operations_struct_traits.h
@@ -5,27 +5,23 @@
#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FILTER_OPERATIONS_STRUCT_TRAITS_H_
#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_FILTER_OPERATIONS_STRUCT_TRAITS_H_
-#include "cc/paint/filter_operations.h"
#include "services/viz/public/interfaces/compositing/filter_operations.mojom-shared.h"
+namespace cc {
+class FilterOperation;
+class FilterOperations;
+} // namespace cc
+
namespace mojo {
template <>
struct StructTraits<viz::mojom::FilterOperationsDataView,
cc::FilterOperations> {
static const std::vector<cc::FilterOperation>& operations(
- const cc::FilterOperations& operations) {
- return operations.operations();
- }
+ const cc::FilterOperations& operations);
static bool Read(viz::mojom::FilterOperationsDataView data,
- cc::FilterOperations* out) {
- std::vector<cc::FilterOperation> operations;
- if (!data.ReadOperations(&operations))
- return false;
- *out = cc::FilterOperations(std::move(operations));
- return true;
- }
+ cc::FilterOperations* out);
};
} // namespace mojo
diff --git a/chromium/services/viz/public/cpp/compositing/frame_deadline.typemap b/chromium/services/viz/public/cpp/compositing/frame_deadline.typemap
index 9baa01175a9..32237d0c2ae 100644
--- a/chromium/services/viz/public/cpp/compositing/frame_deadline.typemap
+++ b/chromium/services/viz/public/cpp/compositing/frame_deadline.typemap
@@ -9,4 +9,7 @@ deps = [
"//components/viz/common",
"//mojo/common:struct_traits",
]
-type_mappings = [ "viz.mojom.FrameDeadline=uint32_t" ]
+sources = [
+ "//services/viz/public/cpp/compositing/frame_deadline_struct_traits.cc",
+]
+type_mappings = [ "viz.mojom.FrameDeadline=viz::FrameDeadline" ]
diff --git a/chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.cc b/chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.cc
new file mode 100644
index 00000000000..d3fbf1e66eb
--- /dev/null
+++ b/chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.cc
@@ -0,0 +1,25 @@
+// Copyright 2018 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/viz/public/cpp/compositing/frame_deadline_struct_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<viz::mojom::FrameDeadlineDataView, viz::FrameDeadline>::Read(
+ viz::mojom::FrameDeadlineDataView data,
+ viz::FrameDeadline* out) {
+ base::TimeTicks frame_start_time;
+ base::TimeDelta frame_interval;
+ if (!data.ReadFrameStartTime(&frame_start_time) ||
+ !data.ReadFrameInterval(&frame_interval)) {
+ return false;
+ }
+ *out = viz::FrameDeadline(frame_start_time, data.deadline_in_frames(),
+ frame_interval,
+ data.use_default_lower_bound_deadline());
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.h b/chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.h
index 7c543dfafac..8770b1b5ff2 100644
--- a/chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/frame_deadline_struct_traits.h
@@ -7,16 +7,32 @@
#include "services/viz/public/interfaces/compositing/frame_deadline.mojom.h"
+#include "components/viz/common/quads/frame_deadline.h"
+#include "mojo/common/time_struct_traits.h"
+
namespace mojo {
template <>
-struct StructTraits<viz::mojom::FrameDeadlineDataView, uint32_t> {
- static uint32_t value(const uint32_t& input) { return input; }
+struct StructTraits<viz::mojom::FrameDeadlineDataView, viz::FrameDeadline> {
+ static base::TimeTicks frame_start_time(const viz::FrameDeadline& input) {
+ return input.frame_start_time();
+ }
+
+ static uint32_t deadline_in_frames(const viz::FrameDeadline& input) {
+ return input.deadline_in_frames();
+ }
- static bool Read(viz::mojom::FrameDeadlineDataView data, uint32_t* out) {
- *out = data.value();
- return true;
+ static base::TimeDelta frame_interval(const viz::FrameDeadline& input) {
+ return input.frame_interval();
}
+
+ static bool use_default_lower_bound_deadline(
+ const viz::FrameDeadline& input) {
+ return input.use_default_lower_bound_deadline();
+ }
+
+ static bool Read(viz::mojom::FrameDeadlineDataView data,
+ viz::FrameDeadline* out);
};
} // namespace mojo
diff --git a/chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.cc b/chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.cc
index 5dda21389af..0ec7a9d8e4c 100644
--- a/chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.cc
@@ -23,7 +23,8 @@ bool StructTraits<viz::mojom::RenderPassDataView,
!data.ReadTransformToRootTarget(&(*out)->transform_to_root_target) ||
!data.ReadFilters(&(*out)->filters) ||
!data.ReadBackgroundFilters(&(*out)->background_filters) ||
- !data.ReadColorSpace(&(*out)->color_space)) {
+ !data.ReadColorSpace(&(*out)->color_space) ||
+ !data.ReadCopyRequests(&(*out)->copy_requests)) {
return false;
}
(*out)->id = data.id();
diff --git a/chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.h b/chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.h
index 52d6b5710d7..a7e871d5497 100644
--- a/chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/render_pass_struct_traits.h
@@ -9,6 +9,7 @@
#include "base/logging.h"
#include "components/viz/common/quads/render_pass.h"
+#include "services/viz/public/cpp/compositing/copy_output_request_struct_traits.h"
#include "services/viz/public/cpp/compositing/quads_struct_traits.h"
#include "services/viz/public/interfaces/compositing/render_pass.mojom-shared.h"
#include "ui/gfx/ipc/color/gfx_param_traits.h"
@@ -72,6 +73,11 @@ struct StructTraits<viz::mojom::RenderPassDataView,
return input->generate_mipmap;
}
+ static const std::vector<std::unique_ptr<viz::CopyOutputRequest>>&
+ copy_requests(const std::unique_ptr<viz::RenderPass>& input) {
+ return input->copy_requests;
+ }
+
static const viz::QuadList& quad_list(
const std::unique_ptr<viz::RenderPass>& input) {
return input->quad_list;
diff --git a/chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc b/chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc
index 9b7f1730b40..120e577fef5 100644
--- a/chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc
+++ b/chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.cc
@@ -10,8 +10,6 @@ namespace mojo {
bool StructTraits<viz::mojom::ResourceSettingsDataView, viz::ResourceSettings>::
Read(viz::mojom::ResourceSettingsDataView data,
viz::ResourceSettings* out) {
- out->texture_id_allocation_chunk_size =
- data.texture_id_allocation_chunk_size();
out->use_gpu_memory_buffer_resources = data.use_gpu_memory_buffer_resources();
return true;
diff --git a/chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.h b/chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.h
index 44e349371f9..e108439db25 100644
--- a/chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.h
+++ b/chromium/services/viz/public/cpp/compositing/resource_settings_struct_traits.h
@@ -17,11 +17,6 @@ namespace mojo {
template <>
struct StructTraits<viz::mojom::ResourceSettingsDataView,
viz::ResourceSettings> {
- static size_t texture_id_allocation_chunk_size(
- const viz::ResourceSettings& input) {
- return input.texture_id_allocation_chunk_size;
- }
-
static bool use_gpu_memory_buffer_resources(
const viz::ResourceSettings& input) {
return input.use_gpu_memory_buffer_resources;
diff --git a/chromium/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/chromium/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index 243031d9a50..7433f9f6ea1 100644
--- a/chromium/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/chromium/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -41,7 +41,6 @@
#include "services/viz/public/cpp/compositing/shared_quad_state_struct_traits.h"
#include "services/viz/public/cpp/compositing/surface_id_struct_traits.h"
#include "services/viz/public/cpp/compositing/surface_info_struct_traits.h"
-#include "services/viz/public/cpp/compositing/surface_sequence_struct_traits.h"
#include "services/viz/public/cpp/compositing/transferable_resource_struct_traits.h"
#include "services/viz/public/interfaces/compositing/begin_frame_args.mojom.h"
#include "services/viz/public/interfaces/compositing/compositor_frame.mojom.h"
@@ -49,11 +48,9 @@
#include "services/viz/public/interfaces/compositing/filter_operations.mojom.h"
#include "services/viz/public/interfaces/compositing/returned_resource.mojom.h"
#include "services/viz/public/interfaces/compositing/surface_info.mojom.h"
-#include "services/viz/public/interfaces/compositing/surface_sequence.mojom.h"
#include "services/viz/public/interfaces/compositing/transferable_resource.mojom.h"
#include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
#include "skia/public/interfaces/blur_image_filter_tile_mode_struct_traits.h"
-#include "skia/public/interfaces/image_filter_struct_traits.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkString.h"
#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
@@ -262,6 +259,7 @@ TEST_F(StructTraitsTest, CopyOutputRequest_BitmapRequest) {
EXPECT_EQ(scale_from, input->scale_from());
EXPECT_EQ(scale_to, input->scale_to());
input->set_area(area);
+ input->set_result_selection(result_rect);
input->set_source(source);
EXPECT_TRUE(input->is_scaled());
std::unique_ptr<CopyOutputRequest> output;
@@ -275,6 +273,8 @@ TEST_F(StructTraitsTest, CopyOutputRequest_BitmapRequest) {
EXPECT_EQ(source, output->source());
EXPECT_TRUE(output->has_area());
EXPECT_EQ(area, output->area());
+ EXPECT_TRUE(output->has_result_selection());
+ EXPECT_EQ(result_rect, output->result_selection());
SkBitmap bitmap;
bitmap.allocN32Pixels(result_rect.width(), result_rect.height());
@@ -387,17 +387,13 @@ TEST_F(StructTraitsTest, CopyOutputRequest_CallbackRunsOnce) {
}
TEST_F(StructTraitsTest, ResourceSettings) {
- constexpr size_t kArbitrarySize = 32;
constexpr bool kArbitraryBool = true;
ResourceSettings input;
- input.texture_id_allocation_chunk_size = kArbitrarySize;
input.use_gpu_memory_buffer_resources = kArbitraryBool;
ResourceSettings output;
SerializeAndDeserialize<mojom::ResourceSettings>(input, &output);
- EXPECT_EQ(input.texture_id_allocation_chunk_size,
- output.texture_id_allocation_chunk_size);
EXPECT_EQ(input.use_gpu_memory_buffer_resources,
output.use_gpu_memory_buffer_resources);
}
@@ -448,19 +444,6 @@ TEST_F(StructTraitsTest, SharedQuadState) {
EXPECT_EQ(sorting_context_id, output_sqs.sorting_context_id);
}
-TEST_F(StructTraitsTest, SurfaceSequence) {
- const FrameSinkId frame_sink_id(2016, 1234);
- const uint32_t sequence = 0xfbadbeef;
-
- SurfaceSequence input(frame_sink_id, sequence);
- SurfaceSequence output;
- mojom::SurfaceSequence::Deserialize(mojom::SurfaceSequence::Serialize(&input),
- &output);
-
- EXPECT_EQ(frame_sink_id, output.frame_sink_id);
- EXPECT_EQ(sequence, output.sequence);
-}
-
// Note that this is a fairly trivial test of CompositorFrame serialization as
// most of the heavy lifting has already been done by CompositorFrameMetadata,
// RenderPass, and QuadListBasic unit tests.
@@ -637,7 +620,6 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
const gfx::SizeF root_layer_size(1234.5f, 5432.1f);
const float min_page_scale_factor = 3.5f;
const float max_page_scale_factor = 4.6f;
- const bool root_overflow_x_hidden = true;
const bool root_overflow_y_hidden = true;
const bool may_contain_video = true;
const bool is_resourceless_software_draw_with_scroll_or_animation = true;
@@ -670,7 +652,7 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
activation_dependencies.push_back(id2);
uint32_t frame_token = 0xdeadbeef;
uint64_t begin_frame_ack_sequence_number = 0xdeadbeef;
- uint32_t deadline_in_frames = 4u;
+ FrameDeadline frame_deadline(base::TimeTicks(), 4u, base::TimeDelta(), true);
CompositorFrameMetadata input;
input.device_scale_factor = device_scale_factor;
@@ -680,7 +662,6 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
input.root_layer_size = root_layer_size;
input.min_page_scale_factor = min_page_scale_factor;
input.max_page_scale_factor = max_page_scale_factor;
- input.root_overflow_x_hidden = root_overflow_x_hidden;
input.root_overflow_y_hidden = root_overflow_y_hidden;
input.may_contain_video = may_contain_video;
input.is_resourceless_software_draw_with_scroll_or_animation =
@@ -694,7 +675,7 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
input.latency_info = latency_infos;
input.referenced_surfaces = referenced_surfaces;
input.activation_dependencies = activation_dependencies;
- input.deadline_in_frames = deadline_in_frames;
+ input.deadline = frame_deadline;
input.frame_token = frame_token;
input.begin_frame_ack.sequence_number = begin_frame_ack_sequence_number;
@@ -707,7 +688,6 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
EXPECT_EQ(root_layer_size, output.root_layer_size);
EXPECT_EQ(min_page_scale_factor, output.min_page_scale_factor);
EXPECT_EQ(max_page_scale_factor, output.max_page_scale_factor);
- EXPECT_EQ(root_overflow_x_hidden, output.root_overflow_x_hidden);
EXPECT_EQ(root_overflow_y_hidden, output.root_overflow_y_hidden);
EXPECT_EQ(may_contain_video, output.may_contain_video);
EXPECT_EQ(is_resourceless_software_draw_with_scroll_or_animation,
@@ -731,13 +711,16 @@ TEST_F(StructTraitsTest, CompositorFrameMetadata) {
output.activation_dependencies.size());
for (uint32_t i = 0; i < activation_dependencies.size(); ++i)
EXPECT_EQ(activation_dependencies[i], output.activation_dependencies[i]);
- EXPECT_EQ(deadline_in_frames, output.deadline_in_frames);
+ EXPECT_EQ(frame_deadline, output.deadline);
EXPECT_EQ(frame_token, output.frame_token);
EXPECT_EQ(begin_frame_ack_sequence_number,
output.begin_frame_ack.sequence_number);
}
TEST_F(StructTraitsTest, RenderPass) {
+ // The CopyOutputRequest struct traits require a TaskRunner.
+ base::test::ScopedTaskEnvironment scoped_task_environment;
+
const RenderPassId render_pass_id = 3u;
const gfx::Rect output_rect(45, 22, 120, 13);
const gfx::Transform transform_to_root =
@@ -760,6 +743,9 @@ TEST_F(StructTraitsTest, RenderPass) {
filters, background_filters, color_space,
has_transparent_background, cache_render_pass,
has_damage_from_contributing_content, generate_mipmap);
+ input->copy_requests.push_back(CopyOutputRequest::CreateStubForTesting());
+ const gfx::Rect copy_output_area(24, 42, 75, 57);
+ input->copy_requests.back()->set_area(copy_output_area);
SharedQuadState* shared_state_1 = input->CreateAndAppendSharedQuadState();
shared_state_1->SetAll(
@@ -818,6 +804,8 @@ TEST_F(StructTraitsTest, RenderPass) {
EXPECT_EQ(has_damage_from_contributing_content,
output->has_damage_from_contributing_content);
EXPECT_EQ(generate_mipmap, output->generate_mipmap);
+ ASSERT_EQ(1u, output->copy_requests.size());
+ EXPECT_EQ(copy_output_area, output->copy_requests.front()->area());
SharedQuadState* out_sqs1 = output->shared_quad_state_list.ElementAt(0);
EXPECT_EQ(shared_state_1->quad_to_target_transform,
diff --git a/chromium/services/viz/public/cpp/compositing/surface_sequence.typemap b/chromium/services/viz/public/cpp/compositing/surface_sequence.typemap
deleted file mode 100644
index b2377ba681a..00000000000
--- a/chromium/services/viz/public/cpp/compositing/surface_sequence.typemap
+++ /dev/null
@@ -1,12 +0,0 @@
-# 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.
-
-mojom = "//services/viz/public/interfaces/compositing/surface_sequence.mojom"
-public_headers = [ "//components/viz/common/surfaces/surface_sequence.h" ]
-traits_headers =
- [ "//services/viz/public/cpp/compositing/surface_sequence_struct_traits.h" ]
-deps = [
- "//components/viz/common",
-]
-type_mappings = [ "viz.mojom.SurfaceSequence=viz::SurfaceSequence" ]
diff --git a/chromium/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h b/chromium/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h
deleted file mode 100644
index 24563cb026f..00000000000
--- a/chromium/services/viz/public/cpp/compositing/surface_sequence_struct_traits.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.
-
-#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
-#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
-
-#include "components/viz/common/surfaces/surface_sequence.h"
-#include "services/viz/public/interfaces/compositing/surface_sequence.mojom-shared.h"
-
-namespace mojo {
-
-template <>
-struct StructTraits<viz::mojom::SurfaceSequenceDataView, viz::SurfaceSequence> {
- static const viz::FrameSinkId& frame_sink_id(const viz::SurfaceSequence& id) {
- return id.frame_sink_id;
- }
-
- static uint32_t sequence(const viz::SurfaceSequence& id) {
- return id.sequence;
- }
-
- static bool Read(viz::mojom::SurfaceSequenceDataView data,
- viz::SurfaceSequence* out) {
- viz::FrameSinkId frame_sink_id;
- if (!data.ReadFrameSinkId(&frame_sink_id))
- return false;
- *out = viz::SurfaceSequence(frame_sink_id, data.sequence());
- return true;
- }
-};
-
-} // namespace mojo
-
-#endif // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_SURFACE_SEQUENCE_STRUCT_TRAITS_H_
diff --git a/chromium/services/viz/public/cpp/compositing/typemaps.gni b/chromium/services/viz/public/cpp/compositing/typemaps.gni
index 689f6f4ba86..5e57cf68255 100644
--- a/chromium/services/viz/public/cpp/compositing/typemaps.gni
+++ b/chromium/services/viz/public/cpp/compositing/typemaps.gni
@@ -19,7 +19,6 @@ typemaps = [
"//services/viz/public/cpp/compositing/returned_resource.typemap",
"//services/viz/public/cpp/compositing/selection.typemap",
"//services/viz/public/cpp/compositing/shared_quad_state.typemap",
- "//services/viz/public/cpp/compositing/surface_sequence.typemap",
"//services/viz/public/cpp/compositing/surface_id.typemap",
"//services/viz/public/cpp/compositing/surface_info.typemap",
"//services/viz/public/cpp/compositing/transferable_resource.typemap",
diff --git a/chromium/services/viz/public/interfaces/BUILD.gn b/chromium/services/viz/public/interfaces/BUILD.gn
index 7f2c09c206a..1cad4c46319 100644
--- a/chromium/services/viz/public/interfaces/BUILD.gn
+++ b/chromium/services/viz/public/interfaces/BUILD.gn
@@ -28,7 +28,6 @@ mojom("interfaces") {
"compositing/shared_quad_state.mojom",
"compositing/surface_id.mojom",
"compositing/surface_info.mojom",
- "compositing/surface_sequence.mojom",
"compositing/texture_releaser.mojom",
"compositing/transferable_resource.mojom",
"compositing/video_detector_observer.mojom",
diff --git a/chromium/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom b/chromium/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
index 2de89e461c0..51095e3ae64 100644
--- a/chromium/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
+++ b/chromium/services/viz/public/interfaces/compositing/compositor_frame_metadata.mojom
@@ -20,7 +20,6 @@ struct CompositorFrameMetadata {
gfx.mojom.SizeF root_layer_size;
float min_page_scale_factor;
float max_page_scale_factor;
- bool root_overflow_x_hidden;
bool root_overflow_y_hidden;
bool may_contain_video;
bool is_resourceless_software_draw_with_scroll_or_animation;
@@ -32,7 +31,7 @@ struct CompositorFrameMetadata {
Selection selection;
array<ui.mojom.LatencyInfo> latency_info;
array<SurfaceId> referenced_surfaces;
- FrameDeadline? deadline_in_frames;
+ FrameDeadline deadline;
array<SurfaceId> activation_dependencies;
uint32 content_source_id;
BeginFrameAck begin_frame_ack;
diff --git a/chromium/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom b/chromium/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
index de9500d8ad6..c1b95a402d7 100644
--- a/chromium/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
+++ b/chromium/services/viz/public/interfaces/compositing/compositor_frame_sink.mojom
@@ -11,6 +11,7 @@ import "services/viz/public/interfaces/compositing/local_surface_id.mojom";
import "services/viz/public/interfaces/compositing/returned_resource.mojom";
import "services/viz/public/interfaces/hit_test/hit_test_region_list.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
+import "gpu/ipc/common/mailbox.mojom";
// A CompositorFrameSink is an interface for receiving CompositorFrame
@@ -22,7 +23,7 @@ interface CompositorFrameSink {
// Lets the display compositor know that the client wishes to receive the next
// BeginFrame event.
SetNeedsBeginFrame(bool needs_begin_frame);
-
+
// Lets the display compositor know that the client also wants to receive
// BeginFrames with the animate_only flag set. Only clients that opt in
// will receive such BeginFrames.
@@ -49,6 +50,18 @@ interface CompositorFrameSink {
// Notifies the frame sink that a BeginFrame was completed, but that no
// CompositorFrame was produced as a result of it.
DidNotProduceFrame(BeginFrameAck ack);
+
+ // Informs the display compositor that the client allocated a shared bitmap.
+ // The |id| can then be used in subsequent CompositorFrames given to
+ // SubmitCompositorFrame. The |id| is a Mailbox type which doubles as a
+ // SharedBitmapId for this case.
+ DidAllocateSharedBitmap(handle<shared_buffer> buffer, gpu.mojom.Mailbox id);
+
+ // Informs the display compositor that the client deleted a shared bitmap. This
+ // allows the service to free the shared memory that was previously given to it
+ // via DidAllocateSharedBitmap(). The |id| is a Mailbox type which doubles as a
+ // SharedBitmapId for this case.
+ DidDeleteSharedBitmap(gpu.mojom.Mailbox id);
};
interface CompositorFrameSinkClient {
diff --git a/chromium/services/viz/public/interfaces/compositing/copy_output_request.mojom b/chromium/services/viz/public/interfaces/compositing/copy_output_request.mojom
index b3d9fc3369f..a292ac78860 100644
--- a/chromium/services/viz/public/interfaces/compositing/copy_output_request.mojom
+++ b/chromium/services/viz/public/interfaces/compositing/copy_output_request.mojom
@@ -20,6 +20,7 @@ struct CopyOutputRequest {
mojo.common.mojom.UnguessableToken? source;
gfx.mojom.Rect? area;
+ gfx.mojom.Rect? result_selection;
// DEPRECATED: To be removed once tab capture is moved into VIZ.
// http://crbug.com/754872
diff --git a/chromium/services/viz/public/interfaces/compositing/frame_deadline.mojom b/chromium/services/viz/public/interfaces/compositing/frame_deadline.mojom
index 3a606bf8bc8..851e0b2d10f 100644
--- a/chromium/services/viz/public/interfaces/compositing/frame_deadline.mojom
+++ b/chromium/services/viz/public/interfaces/compositing/frame_deadline.mojom
@@ -4,6 +4,11 @@
module viz.mojom;
+import "mojo/common/time.mojom";
+
struct FrameDeadline {
- uint32 value;
+ mojo.common.mojom.TimeTicks frame_start_time;
+ uint32 deadline_in_frames;
+ mojo.common.mojom.TimeDelta frame_interval;
+ bool use_default_lower_bound_deadline;
};
diff --git a/chromium/services/viz/public/interfaces/compositing/render_pass.mojom b/chromium/services/viz/public/interfaces/compositing/render_pass.mojom
index c0614701251..af2b98c4f08 100644
--- a/chromium/services/viz/public/interfaces/compositing/render_pass.mojom
+++ b/chromium/services/viz/public/interfaces/compositing/render_pass.mojom
@@ -4,6 +4,7 @@
module viz.mojom;
+import "services/viz/public/interfaces/compositing/copy_output_request.mojom";
import "services/viz/public/interfaces/compositing/filter_operations.mojom";
import "services/viz/public/interfaces/compositing/quads.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
@@ -23,5 +24,7 @@ struct RenderPass {
bool cache_render_pass = false;
bool has_damage_from_contributing_content = false;
bool generate_mipmap = false;
+ // |copy_requests| are only allowed by privileged clients.
+ array<CopyOutputRequest> copy_requests;
array<DrawQuad> quad_list;
};
diff --git a/chromium/services/viz/public/interfaces/compositing/resource_settings.mojom b/chromium/services/viz/public/interfaces/compositing/resource_settings.mojom
index 62e571e3f03..0ea14a2939b 100644
--- a/chromium/services/viz/public/interfaces/compositing/resource_settings.mojom
+++ b/chromium/services/viz/public/interfaces/compositing/resource_settings.mojom
@@ -7,6 +7,5 @@ module viz.mojom;
// Corresponds to |viz::ResourceSettings| in
// components/viz/common/resources/resource_settings.h
struct ResourceSettings {
- uint32 texture_id_allocation_chunk_size;
bool use_gpu_memory_buffer_resources;
};
diff --git a/chromium/services/viz/public/interfaces/compositing/surface_sequence.mojom b/chromium/services/viz/public/interfaces/compositing/surface_sequence.mojom
deleted file mode 100644
index 7d59501e9a6..00000000000
--- a/chromium/services/viz/public/interfaces/compositing/surface_sequence.mojom
+++ /dev/null
@@ -1,15 +0,0 @@
-// 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.
-
-module viz.mojom;
-
-import "services/viz/public/interfaces/compositing/frame_sink_id.mojom";
-
-// A per-surface-namespace sequence number that's used to coordinate
-// dependencies between frames. A sequence number may be satisfied once, and
-// may be depended on once.
-struct SurfaceSequence {
- FrameSinkId frame_sink_id;
- uint32 sequence;
-};