summaryrefslogtreecommitdiff
path: root/chromium/services
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/services')
-rw-r--r--chromium/services/BUILD.gn18
-rw-r--r--chromium/services/README.md55
-rw-r--r--chromium/services/catalog/catalog.cc25
-rw-r--r--chromium/services/catalog/entry.cc2
-rw-r--r--chromium/services/catalog/public/tools/catalog.cc.tmpl2
-rw-r--r--chromium/services/data_decoder/BUILD.gn (renamed from chromium/services/image_decoder/BUILD.gn)10
-rw-r--r--chromium/services/data_decoder/DEPS (renamed from chromium/services/image_decoder/DEPS)1
-rw-r--r--chromium/services/data_decoder/README.md3
-rw-r--r--chromium/services/data_decoder/data_decoder_service.cc68
-rw-r--r--chromium/services/data_decoder/data_decoder_service.h46
-rw-r--r--chromium/services/data_decoder/image_decoder_impl.cc (renamed from chromium/services/image_decoder/image_decoder_impl.cc)24
-rw-r--r--chromium/services/data_decoder/image_decoder_impl.h (renamed from chromium/services/image_decoder/image_decoder_impl.h)12
-rw-r--r--chromium/services/data_decoder/image_decoder_impl_unittest.cc (renamed from chromium/services/image_decoder/image_decoder_impl_unittest.cc)20
-rw-r--r--chromium/services/data_decoder/manifest.json (renamed from chromium/services/image_decoder/manifest.json)6
-rw-r--r--chromium/services/data_decoder/public/cpp/BUILD.gn (renamed from chromium/services/image_decoder/public/cpp/BUILD.gn)6
-rw-r--r--chromium/services/data_decoder/public/cpp/decode_image.cc (renamed from chromium/services/image_decoder/public/cpp/decode.cc)22
-rw-r--r--chromium/services/data_decoder/public/cpp/decode_image.h (renamed from chromium/services/image_decoder/public/cpp/decode.h)28
-rw-r--r--chromium/services/data_decoder/public/interfaces/BUILD.gn (renamed from chromium/services/image_decoder/public/interfaces/BUILD.gn)0
-rw-r--r--chromium/services/data_decoder/public/interfaces/OWNERS (renamed from chromium/services/image_decoder/public/interfaces/OWNERS)0
-rw-r--r--chromium/services/data_decoder/public/interfaces/constants.mojom (renamed from chromium/services/image_decoder/public/interfaces/constants.mojom)4
-rw-r--r--chromium/services/data_decoder/public/interfaces/image_decoder.mojom (renamed from chromium/services/image_decoder/public/interfaces/image_decoder.mojom)2
-rw-r--r--chromium/services/device/BUILD.gn99
-rw-r--r--chromium/services/device/DEPS2
-rw-r--r--chromium/services/device/OWNERS2
-rw-r--r--chromium/services/device/device_service.cc230
-rw-r--r--chromium/services/device/device_service.h113
-rw-r--r--chromium/services/device/device_service_test_base.cc95
-rw-r--r--chromium/services/device/device_service_test_base.h28
-rw-r--r--chromium/services/device/manifest.json13
-rw-r--r--chromium/services/device/power_monitor/OWNERS2
-rw-r--r--chromium/services/device/power_monitor/power_monitor_message_broadcaster.cc28
-rw-r--r--chromium/services/device/power_monitor/power_monitor_message_broadcaster.h11
-rw-r--r--chromium/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc4
-rw-r--r--chromium/services/device/public/cpp/BUILD.gn17
-rw-r--r--chromium/services/device/public/cpp/device_features.cc14
-rw-r--r--chromium/services/device/public/cpp/device_features.h21
-rw-r--r--chromium/services/device/public/cpp/power_monitor/OWNERS2
-rw-r--r--chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.cc11
-rw-r--r--chromium/services/device/public/cpp/power_monitor/power_monitor_broadcast_source.h8
-rw-r--r--chromium/services/device/public/interfaces/power_monitor.mojom4
-rw-r--r--chromium/services/device/screen_orientation/BUILD.gn53
-rw-r--r--chromium/services/device/screen_orientation/DEPS4
-rw-r--r--chromium/services/device/screen_orientation/OWNERS2
-rw-r--r--chromium/services/device/screen_orientation/android/java/DEPS3
-rw-r--r--chromium/services/device/screen_orientation/screen_orientation_listener_android.cc58
-rw-r--r--chromium/services/device/screen_orientation/screen_orientation_listener_android.h34
-rw-r--r--chromium/services/device/time_zone_monitor/BUILD.gn11
-rw-r--r--chromium/services/device/unittest_manifest.json16
-rw-r--r--chromium/services/device/vibration/vibration_manager_impl_unittest.cc81
-rw-r--r--chromium/services/file/file_service.cc18
-rw-r--r--chromium/services/file/file_service.h8
-rw-r--r--chromium/services/file/file_system.cc1
-rw-r--r--chromium/services/file/user_id_map.cc2
-rw-r--r--chromium/services/identity/BUILD.gn29
-rw-r--r--chromium/services/identity/DEPS6
-rw-r--r--chromium/services/identity/OWNERS2
-rw-r--r--chromium/services/identity/README.md8
-rw-r--r--chromium/services/identity/identity_manager.cc39
-rw-r--r--chromium/services/identity/identity_manager.h32
-rw-r--r--chromium/services/identity/identity_service.cc34
-rw-r--r--chromium/services/identity/identity_service.h44
-rw-r--r--chromium/services/identity/manifest.json11
-rw-r--r--chromium/services/identity/public/interfaces/BUILD.gn22
-rw-r--r--chromium/services/identity/public/interfaces/OWNERS2
-rw-r--r--chromium/services/identity/public/interfaces/constants.mojom7
-rw-r--r--chromium/services/identity/public/interfaces/identity_manager.mojom17
-rw-r--r--chromium/services/image_decoder/README.md3
-rw-r--r--chromium/services/image_decoder/image_decoder_service.cc79
-rw-r--r--chromium/services/image_decoder/image_decoder_service.h43
-rw-r--r--chromium/services/navigation/navigation.cc23
-rw-r--r--chromium/services/navigation/navigation.h19
-rw-r--r--chromium/services/navigation/navigation_unittest.cc3
-rw-r--r--chromium/services/preferences/BUILD.gn63
-rw-r--r--chromium/services/preferences/DEPS3
-rw-r--r--chromium/services/preferences/manifest.json19
-rw-r--r--chromium/services/preferences/persistent_pref_store_factory.cc51
-rw-r--r--chromium/services/preferences/persistent_pref_store_factory.h28
-rw-r--r--chromium/services/preferences/persistent_pref_store_impl.cc161
-rw-r--r--chromium/services/preferences/persistent_pref_store_impl.h64
-rw-r--r--chromium/services/preferences/persistent_pref_store_impl_unittest.cc336
-rw-r--r--chromium/services/preferences/pref_service_factory_unittest.cc269
-rw-r--r--chromium/services/preferences/pref_store_manager_impl.cc280
-rw-r--r--chromium/services/preferences/pref_store_manager_impl.h136
-rw-r--r--chromium/services/preferences/public/cpp/BUILD.gn33
-rw-r--r--chromium/services/preferences/public/cpp/DEPS7
-rw-r--r--chromium/services/preferences/public/cpp/OWNERS4
-rw-r--r--chromium/services/preferences/public/cpp/persistent_pref_store_client.cc184
-rw-r--r--chromium/services/preferences/public/cpp/persistent_pref_store_client.h89
-rw-r--r--chromium/services/preferences/public/cpp/pref_client_store.cc104
-rw-r--r--chromium/services/preferences/public/cpp/pref_client_store.h82
-rw-r--r--chromium/services/preferences/public/cpp/pref_registry_serializer.cc21
-rw-r--r--chromium/services/preferences/public/cpp/pref_registry_serializer.h18
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_factory.cc116
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_factory.h48
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_main.cc20
-rw-r--r--chromium/services/preferences/public/cpp/pref_service_main.h30
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_adapter.cc40
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_adapter.h44
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client.cc18
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client.h34
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client_mixin.cc129
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_client_mixin.h82
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_impl.cc113
-rw-r--r--chromium/services/preferences/public/cpp/pref_store_impl.h63
-rw-r--r--chromium/services/preferences/public/cpp/preferences.typemap22
-rw-r--r--chromium/services/preferences/public/cpp/preferences_struct_traits.cc136
-rw-r--r--chromium/services/preferences/public/cpp/preferences_struct_traits.h38
-rw-r--r--chromium/services/preferences/public/cpp/tests/BUILD.gn16
-rw-r--r--chromium/services/preferences/public/cpp/tracked/BUILD.gn33
-rw-r--r--chromium/services/preferences/public/cpp/tracked/OWNERS2
-rw-r--r--chromium/services/preferences/public/cpp/tracked/configuration.cc25
-rw-r--r--chromium/services/preferences/public/cpp/tracked/configuration.h37
-rw-r--r--chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.cc84
-rw-r--r--chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h124
-rw-r--r--chromium/services/preferences/public/cpp/tracked/pref_names.cc13
-rw-r--r--chromium/services/preferences/public/cpp/tracked/pref_names.h14
-rw-r--r--chromium/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.cc31
-rw-r--r--chromium/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h26
-rw-r--r--chromium/services/preferences/public/cpp/typemaps.gni5
-rw-r--r--chromium/services/preferences/public/interfaces/BUILD.gn2
-rw-r--r--chromium/services/preferences/public/interfaces/preferences.mojom140
-rw-r--r--chromium/services/preferences/public/interfaces/preferences_configuration.mojom62
-rw-r--r--chromium/services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom56
-rw-r--r--chromium/services/preferences/tracked/BUILD.gn86
-rw-r--r--chromium/services/preferences/tracked/DEPS4
-rw-r--r--chromium/services/preferences/tracked/OWNERS2
-rw-r--r--chromium/services/preferences/tracked/device_id.h23
-rw-r--r--chromium/services/preferences/tracked/device_id_mac.cc32
-rw-r--r--chromium/services/preferences/tracked/device_id_stub.cc11
-rw-r--r--chromium/services/preferences/tracked/device_id_unittest.cc35
-rw-r--r--chromium/services/preferences/tracked/device_id_win.cc73
-rw-r--r--chromium/services/preferences/tracked/dictionary_hash_store_contents.cc133
-rw-r--r--chromium/services/preferences/tracked/dictionary_hash_store_contents.h62
-rw-r--r--chromium/services/preferences/tracked/hash_store_contents.h90
-rw-r--r--chromium/services/preferences/tracked/interceptable_pref_filter.cc39
-rw-r--r--chromium/services/preferences/tracked/interceptable_pref_filter.h68
-rw-r--r--chromium/services/preferences/tracked/interceptable_pref_filter_unittest.cc55
-rw-r--r--chromium/services/preferences/tracked/pref_hash_calculator.cc112
-rw-r--r--chromium/services/preferences/tracked/pref_hash_calculator.h55
-rw-r--r--chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc196
-rw-r--r--chromium/services/preferences/tracked/pref_hash_filter.cc366
-rw-r--r--chromium/services/preferences/tracked/pref_hash_filter.h157
-rw-r--r--chromium/services/preferences/tracked/pref_hash_filter_unittest.cc1355
-rw-r--r--chromium/services/preferences/tracked/pref_hash_store.h48
-rw-r--r--chromium/services/preferences/tracked/pref_hash_store_impl.cc321
-rw-r--r--chromium/services/preferences/tracked/pref_hash_store_impl.h61
-rw-r--r--chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc507
-rw-r--r--chromium/services/preferences/tracked/pref_hash_store_transaction.h80
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win.cc182
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win.h49
-rw-r--r--chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc120
-rw-r--r--chromium/services/preferences/tracked/segregated_pref_store.cc195
-rw-r--r--chromium/services/preferences/tracked/segregated_pref_store.h122
-rw-r--r--chromium/services/preferences/tracked/segregated_pref_store_unittest.cc304
-rw-r--r--chromium/services/preferences/tracked/tracked_atomic_preference.cc89
-rw-r--r--chromium/services/preferences/tracked/tracked_atomic_preference.h55
-rw-r--r--chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc133
-rw-r--r--chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h27
-rw-r--r--chromium/services/preferences/tracked/tracked_preference.h44
-rw-r--r--chromium/services/preferences/tracked/tracked_preference_helper.cc139
-rw-r--r--chromium/services/preferences/tracked/tracked_preference_helper.h75
-rw-r--r--chromium/services/preferences/tracked/tracked_preferences_migration.cc333
-rw-r--r--chromium/services/preferences/tracked/tracked_preferences_migration.h45
-rw-r--r--chromium/services/preferences/tracked/tracked_preferences_migration_unittest.cc645
-rw-r--r--chromium/services/preferences/tracked/tracked_split_preference.cc120
-rw-r--r--chromium/services/preferences/tracked/tracked_split_preference.h58
-rw-r--r--chromium/services/preferences/unittest_manifest.json16
-rw-r--r--chromium/services/resource_coordinator/BUILD.gn7
-rw-r--r--chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.cc65
-rw-r--r--chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.h19
-rw-r--r--chromium/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc23
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc75
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h67
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc135
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation.typemap3
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.cc34
-rw-r--r--chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h53
-rw-r--r--chromium/services/resource_coordinator/public/interfaces/BUILD.gn6
-rw-r--r--chromium/services/resource_coordinator/public/interfaces/memory/constants.mojom7
-rw-r--r--chromium/services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom21
-rw-r--r--chromium/services/resource_coordinator/public/interfaces/tracing/OWNERS2
-rw-r--r--chromium/services/resource_coordinator/public/interfaces/tracing/tracing.mojom58
-rw-r--r--chromium/services/service_manager/README.md1271
-rw-r--r--chromium/services/service_manager/connect_params.cc5
-rw-r--r--chromium/services/service_manager/connect_params.h37
-rw-r--r--chromium/services/service_manager/connect_util.cc14
-rw-r--r--chromium/services/service_manager/embedder/BUILD.gn38
-rw-r--r--chromium/services/service_manager/embedder/DEPS3
-rw-r--r--chromium/services/service_manager/embedder/README.md17
-rw-r--r--chromium/services/service_manager/embedder/mac_init.h15
-rw-r--r--chromium/services/service_manager/embedder/mac_init.mm25
-rw-r--r--chromium/services/service_manager/embedder/main.cc200
-rw-r--r--chromium/services/service_manager/embedder/main.h33
-rw-r--r--chromium/services/service_manager/embedder/main_delegate.h50
-rw-r--r--chromium/services/service_manager/embedder/service_manager_embedder_export.h29
-rw-r--r--chromium/services/service_manager/embedder/set_process_title.cc94
-rw-r--r--chromium/services/service_manager/embedder/set_process_title.h31
-rw-r--r--chromium/services/service_manager/embedder/set_process_title_linux.cc116
-rw-r--r--chromium/services/service_manager/embedder/set_process_title_linux.h22
-rw-r--r--chromium/services/service_manager/embedder/shared_file_util.cc (renamed from chromium/services/service_manager/public/cpp/lib/shared_file_util.cc)2
-rw-r--r--chromium/services/service_manager/embedder/shared_file_util.h (renamed from chromium/services/service_manager/public/cpp/shared_file_util.h)13
-rw-r--r--chromium/services/service_manager/embedder/switches.cc20
-rw-r--r--chromium/services/service_manager/embedder/switches.h16
-rw-r--r--chromium/services/service_manager/public/cpp/BUILD.gn5
-rw-r--r--chromium/services/service_manager/public/cpp/connection.h96
-rw-r--r--chromium/services/service_manager/public/cpp/connector.h80
-rw-r--r--chromium/services/service_manager/public/cpp/lib/connection_impl.cc100
-rw-r--r--chromium/services/service_manager/public/cpp/lib/connection_impl.h76
-rw-r--r--chromium/services/service_manager/public/cpp/lib/connector_impl.cc93
-rw-r--r--chromium/services/service_manager/public/cpp/lib/connector_impl.h23
-rw-r--r--chromium/services/service_manager/public/cpp/lib/identity.cc3
-rw-r--r--chromium/services/service_manager/public/cpp/lib/interface_registry.cc1
-rw-r--r--chromium/services/service_manager/public/cpp/lib/service.cc30
-rw-r--r--chromium/services/service_manager/public/cpp/lib/service_context.cc60
-rw-r--r--chromium/services/service_manager/public/cpp/lib/service_test.cc11
-rw-r--r--chromium/services/service_manager/public/cpp/service.h13
-rw-r--r--chromium/services/service_manager/public/cpp/service_context.h17
-rw-r--r--chromium/services/service_manager/public/cpp/service_test.h5
-rw-r--r--chromium/services/service_manager/public/cpp/test/BUILD.gn4
-rw-r--r--chromium/services/service_manager/public/interfaces/connector.mojom170
-rw-r--r--chromium/services/service_manager/public/interfaces/service.mojom21
-rw-r--r--chromium/services/service_manager/public/java/BUILD.gn1
-rw-r--r--chromium/services/service_manager/public/tools/test/service_test.gni1
-rw-r--r--chromium/services/service_manager/runner/host/service_process_launcher.cc20
-rw-r--r--chromium/services/service_manager/service_manager.cc255
-rw-r--r--chromium/services/service_manager/service_manager.h3
-rw-r--r--chromium/services/service_manager/standalone/context.cc4
-rw-r--r--chromium/services/shape_detection/BUILD.gn5
-rw-r--r--chromium/services/shape_detection/OWNERS5
-rw-r--r--chromium/services/shape_detection/manifest.json3
-rw-r--r--chromium/services/shape_detection/shape_detection_service.cc31
-rw-r--r--chromium/services/shape_detection/shape_detection_service.h7
-rw-r--r--chromium/services/shape_detection/text_detection_impl.cc14
-rw-r--r--chromium/services/shape_detection/text_detection_impl.h24
-rw-r--r--chromium/services/shape_detection/text_detection_impl_mac.h33
-rw-r--r--chromium/services/shape_detection/text_detection_impl_mac.mm83
-rw-r--r--chromium/services/shape_detection/text_detection_impl_mac_unittest.mm111
-rw-r--r--chromium/services/tracing/public/cpp/provider.cc1
-rw-r--r--chromium/services/tracing/service.cc39
-rw-r--r--chromium/services/tracing/service.h7
-rw-r--r--chromium/services/ui/OWNERS2
-rw-r--r--chromium/services/ui/common/BUILD.gn2
-rw-r--r--chromium/services/ui/common/accelerator_util.cc8
-rw-r--r--chromium/services/ui/common/accelerator_util.h4
-rw-r--r--chromium/services/ui/demo/OWNERS2
-rw-r--r--chromium/services/ui/demo/mus_demo.cc13
-rw-r--r--chromium/services/ui/demo/mus_demo.h2
-rw-r--r--chromium/services/ui/demo/mus_demo_internal.cc22
-rw-r--r--chromium/services/ui/demo/mus_demo_internal.h15
-rw-r--r--chromium/services/ui/demo/mus_demo_unittests.cc2
-rw-r--r--chromium/services/ui/display/BUILD.gn3
-rw-r--r--chromium/services/ui/display/OWNERS2
-rw-r--r--chromium/services/ui/display/output_protection.h1
-rw-r--r--chromium/services/ui/display/screen_manager.h4
-rw-r--r--chromium/services/ui/display/screen_manager_delegate.h19
-rw-r--r--chromium/services/ui/display/screen_manager_forwarding.cc200
-rw-r--r--chromium/services/ui/display/screen_manager_forwarding.h96
-rw-r--r--chromium/services/ui/display/screen_manager_ozone_external.cc4
-rw-r--r--chromium/services/ui/display/screen_manager_ozone_external.h2
-rw-r--r--chromium/services/ui/display/screen_manager_ozone_internal.cc53
-rw-r--r--chromium/services/ui/display/screen_manager_ozone_internal.h3
-rw-r--r--chromium/services/ui/display/screen_manager_ozone_internal_unittests.cc29
-rw-r--r--chromium/services/ui/display/screen_manager_stub_internal.cc41
-rw-r--r--chromium/services/ui/display/screen_manager_stub_internal.h7
-rw-r--r--chromium/services/ui/display/viewport_metrics.cc41
-rw-r--r--chromium/services/ui/display/viewport_metrics.h12
-rw-r--r--chromium/services/ui/gpu/BUILD.gn7
-rw-r--r--chromium/services/ui/gpu/DEPS3
-rw-r--r--chromium/services/ui/gpu/OWNERS3
-rw-r--r--chromium/services/ui/gpu/gpu_main.cc110
-rw-r--r--chromium/services/ui/gpu/gpu_main.h53
-rw-r--r--chromium/services/ui/gpu/gpu_service.cc413
-rw-r--r--chromium/services/ui/gpu/gpu_service.h68
-rw-r--r--chromium/services/ui/gpu/gpu_service_unittest.cc100
-rw-r--r--chromium/services/ui/gpu/interfaces/gpu_host.mojom8
-rw-r--r--chromium/services/ui/gpu/interfaces/gpu_main.mojom11
-rw-r--r--chromium/services/ui/gpu/interfaces/gpu_service.mojom29
-rw-r--r--chromium/services/ui/ime/ime_server_impl.cc2
-rw-r--r--chromium/services/ui/ime/ime_unittest.cc2
-rw-r--r--chromium/services/ui/ime/test_ime_driver/test_ime_application.cc6
-rw-r--r--chromium/services/ui/ime/test_ime_driver/test_ime_application.h2
-rw-r--r--chromium/services/ui/input_devices/input_device_server.cc4
-rw-r--r--chromium/services/ui/input_devices/input_device_server.h5
-rw-r--r--chromium/services/ui/manifest.json3
-rw-r--r--chromium/services/ui/public/cpp/BUILD.gn5
-rw-r--r--chromium/services/ui/public/cpp/OWNERS2
-rw-r--r--chromium/services/ui/public/cpp/bitmap/BUILD.gn20
-rw-r--r--chromium/services/ui/public/cpp/bitmap/child_shared_bitmap_manager.cc165
-rw-r--r--chromium/services/ui/public/cpp/bitmap/child_shared_bitmap_manager.h51
-rw-r--r--chromium/services/ui/public/cpp/client_compositor_frame_sink.cc (renamed from chromium/services/ui/public/cpp/window_compositor_frame_sink.cc)76
-rw-r--r--chromium/services/ui/public/cpp/client_compositor_frame_sink.h (renamed from chromium/services/ui/public/cpp/window_compositor_frame_sink.h)37
-rw-r--r--chromium/services/ui/public/cpp/gpu/context_provider_command_buffer.cc3
-rw-r--r--chromium/services/ui/public/cpp/gpu/gpu.cc31
-rw-r--r--chromium/services/ui/public/cpp/gpu/gpu.h9
-rw-r--r--chromium/services/ui/public/interfaces/BUILD.gn7
-rw-r--r--chromium/services/ui/public/interfaces/cursor/BUILD.gn18
-rw-r--r--chromium/services/ui/public/interfaces/cursor/DEPS3
-rw-r--r--chromium/services/ui/public/interfaces/cursor/OWNERS8
-rw-r--r--chromium/services/ui/public/interfaces/cursor/cursor.mojom (renamed from chromium/services/ui/public/interfaces/cursor.mojom)24
-rw-r--r--chromium/services/ui/public/interfaces/cursor/cursor.typemap19
-rw-r--r--chromium/services/ui/public/interfaces/cursor/cursor_struct_traits.cc64
-rw-r--r--chromium/services/ui/public/interfaces/cursor/cursor_struct_traits.h29
-rw-r--r--chromium/services/ui/public/interfaces/cursor/cursor_struct_traits_unittest.cc106
-rw-r--r--chromium/services/ui/public/interfaces/cursor/typemaps.gni5
-rw-r--r--chromium/services/ui/public/interfaces/window_manager.mojom62
-rw-r--r--chromium/services/ui/public/interfaces/window_manager_constants.mojom1
-rw-r--r--chromium/services/ui/public/interfaces/window_manager_window_tree_factory.mojom15
-rw-r--r--chromium/services/ui/public/interfaces/window_server_test.mojom8
-rw-r--r--chromium/services/ui/public/interfaces/window_tree.mojom67
-rw-r--r--chromium/services/ui/service.cc56
-rw-r--r--chromium/services/ui/service.h17
-rw-r--r--chromium/services/ui/surfaces/BUILD.gn9
-rw-r--r--chromium/services/ui/surfaces/DEPS2
-rw-r--r--chromium/services/ui/surfaces/OWNERS2
-rw-r--r--chromium/services/ui/surfaces/display_compositor.cc197
-rw-r--r--chromium/services/ui/surfaces/display_compositor.h137
-rw-r--r--chromium/services/ui/surfaces/mus_display_provider.cc94
-rw-r--r--chromium/services/ui/surfaces/mus_display_provider.h52
-rw-r--r--chromium/services/ui/test_wm/test_wm.cc19
-rw-r--r--chromium/services/ui/ws/BUILD.gn51
-rw-r--r--chromium/services/ui/ws/DEPS3
-rw-r--r--chromium/services/ui/ws/OWNERS1
-rw-r--r--chromium/services/ui/ws/cursor_unittest.cc79
-rw-r--r--chromium/services/ui/ws/display.cc119
-rw-r--r--chromium/services/ui/ws/display.h49
-rw-r--r--chromium/services/ui/ws/display_binding.cc3
-rw-r--r--chromium/services/ui/ws/display_client_compositor_frame_sink.cc107
-rw-r--r--chromium/services/ui/ws/display_client_compositor_frame_sink.h73
-rw-r--r--chromium/services/ui/ws/display_manager.cc70
-rw-r--r--chromium/services/ui/ws/display_manager.h16
-rw-r--r--chromium/services/ui/ws/display_unittest.cc43
-rw-r--r--chromium/services/ui/ws/drag_controller.cc49
-rw-r--r--chromium/services/ui/ws/drag_controller.h10
-rw-r--r--chromium/services/ui/ws/drag_controller_unittest.cc45
-rw-r--r--chromium/services/ui/ws/drag_source.h3
-rw-r--r--chromium/services/ui/ws/event_dispatcher.cc19
-rw-r--r--chromium/services/ui/ws/event_dispatcher.h4
-rw-r--r--chromium/services/ui/ws/event_dispatcher_unittest.cc108
-rw-r--r--chromium/services/ui/ws/event_matcher.cc4
-rw-r--r--chromium/services/ui/ws/event_matcher_unittest.cc8
-rw-r--r--chromium/services/ui/ws/frame_generator.cc161
-rw-r--r--chromium/services/ui/ws/frame_generator.h78
-rw-r--r--chromium/services/ui/ws/frame_generator_delegate.h22
-rw-r--r--chromium/services/ui/ws/frame_generator_unittest.cc352
-rw-r--r--chromium/services/ui/ws/gpu_client.cc67
-rw-r--r--chromium/services/ui/ws/gpu_client.h69
-rw-r--r--chromium/services/ui/ws/gpu_host.cc103
-rw-r--r--chromium/services/ui/ws/gpu_host.h25
-rw-r--r--chromium/services/ui/ws/gpu_host_unittest.cc125
-rw-r--r--chromium/services/ui/ws/modal_window_controller.cc15
-rw-r--r--chromium/services/ui/ws/platform_display.cc16
-rw-r--r--chromium/services/ui/ws/platform_display.h29
-rw-r--r--chromium/services/ui/ws/platform_display_default.cc161
-rw-r--r--chromium/services/ui/ws/platform_display_default.h31
-rw-r--r--chromium/services/ui/ws/platform_display_default_unittest.cc153
-rw-r--r--chromium/services/ui/ws/platform_display_delegate.h17
-rw-r--r--chromium/services/ui/ws/platform_display_factory.h9
-rw-r--r--chromium/services/ui/ws/platform_display_init_params.cc22
-rw-r--r--chromium/services/ui/ws/platform_display_init_params.h32
-rw-r--r--chromium/services/ui/ws/server_window.cc29
-rw-r--r--chromium/services/ui/ws/server_window.h30
-rw-r--r--chromium/services/ui/ws/server_window_compositor_frame_sink_manager.cc5
-rw-r--r--chromium/services/ui/ws/server_window_compositor_frame_sink_manager.h2
-rw-r--r--chromium/services/ui/ws/server_window_delegate.h13
-rw-r--r--chromium/services/ui/ws/server_window_observer.h6
-rw-r--r--chromium/services/ui/ws/test_change_tracker.cc60
-rw-r--r--chromium/services/ui/ws/test_change_tracker.h25
-rw-r--r--chromium/services/ui/ws/test_server_window_delegate.cc2
-rw-r--r--chromium/services/ui/ws/test_server_window_delegate.h8
-rw-r--r--chromium/services/ui/ws/test_utils.cc219
-rw-r--r--chromium/services/ui/ws/test_utils.h173
-rw-r--r--chromium/services/ui/ws/window_finder_unittest.cc26
-rw-r--r--chromium/services/ui/ws/window_manager_client_unittest.cc30
-rw-r--r--chromium/services/ui/ws/window_manager_display_root.cc3
-rw-r--r--chromium/services/ui/ws/window_manager_display_root.h2
-rw-r--r--chromium/services/ui/ws/window_manager_state.cc54
-rw-r--r--chromium/services/ui/ws/window_manager_state.h9
-rw-r--r--chromium/services/ui/ws/window_manager_state_unittest.cc89
-rw-r--r--chromium/services/ui/ws/window_manager_window_tree_factory.cc14
-rw-r--r--chromium/services/ui/ws/window_manager_window_tree_factory.h5
-rw-r--r--chromium/services/ui/ws/window_server.cc62
-rw-r--r--chromium/services/ui/ws/window_server.h34
-rw-r--r--chromium/services/ui/ws/window_server_service_test_base.cc8
-rw-r--r--chromium/services/ui/ws/window_server_service_test_base.h7
-rw-r--r--chromium/services/ui/ws/window_server_test_base.cc45
-rw-r--r--chromium/services/ui/ws/window_server_test_base.h24
-rw-r--r--chromium/services/ui/ws/window_server_test_impl.cc25
-rw-r--r--chromium/services/ui/ws/window_server_test_impl.h3
-rw-r--r--chromium/services/ui/ws/window_tree.cc329
-rw-r--r--chromium/services/ui/ws/window_tree.h81
-rw-r--r--chromium/services/ui/ws/window_tree_client_unittest.cc121
-rw-r--r--chromium/services/ui/ws/window_tree_host_factory.cc25
-rw-r--r--chromium/services/ui/ws/window_tree_host_factory.h2
-rw-r--r--chromium/services/ui/ws/window_tree_unittest.cc259
-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.h1
-rw-r--r--chromium/services/video_capture/service_impl.cc16
-rw-r--r--chromium/services/video_capture/service_impl.h7
-rw-r--r--chromium/services/viz/OWNERS6
399 files changed, 19011 insertions, 4171 deletions
diff --git a/chromium/services/BUILD.gn b/chromium/services/BUILD.gn
index 31a46c33983..52a819f38bc 100644
--- a/chromium/services/BUILD.gn
+++ b/chromium/services/BUILD.gn
@@ -15,15 +15,20 @@ import("//testing/test.gni")
# entries in the "service_unittests_catalog" target below.
service_test("service_unittests") {
deps = [
+ "//services/data_decoder:tests",
"//services/device:tests",
- "//services/image_decoder:tests",
+ "//services/preferences:tests",
"//services/resource_coordinator:tests",
"//services/shape_detection:tests",
]
if (is_android) {
- # Some tests need to initialize V8.
- deps += [ "//v8:v8_external_startup_data_assets" ]
+ deps += [
+ "//services/device:java",
+
+ # Some tests need to initialize V8.
+ "//v8:v8_external_startup_data_assets",
+ ]
} else {
# NOTE: We do not currently support standalone service binaries on Android,
# so any tests which use the ServiceTest framework to connect to standalone
@@ -35,5 +40,10 @@ service_test("service_unittests") {
}
catalog("service_unittests_catalog") {
- catalog_deps = [ "//services/video_capture:tests_catalog" ]
+ testonly = true
+ catalog_deps = [
+ "//services/device:tests_catalog",
+ "//services/preferences:tests_catalog",
+ "//services/video_capture:tests_catalog",
+ ]
}
diff --git a/chromium/services/README.md b/chromium/services/README.md
index b8e15401238..c386b42f008 100644
--- a/chromium/services/README.md
+++ b/chromium/services/README.md
@@ -1,7 +1,8 @@
-Chrome Foundation Services
-====
+# Chrome Foundation Services
-### Overview
+[TOC]
+
+## Overview
This directory contains Chrome Foundation Services. If you think of Chrome as a
"portable OS," Chrome Foundation Services can be thought of as that OS'
@@ -13,48 +14,56 @@ Roughly each subdirectory here corresponds to a service that:
* could logically run a standalone process for security/performance isolation
benefits depending on the constraints of the host OS.
-### Service Directory Structure
+## Service Directory Structure
Individual services are structured like so:
- //services/foo/ <-- Implementation code, may have subdirs.
- /public/
- /cpp/ <-- C++ client libraries (optional)
- /interfaces/ <-- Mojom interfaces
+```
+//services/foo/ <-- Implementation code, may have subdirs.
+ /public/
+ /cpp/ <-- C++ client libraries (optional)
+ /interfaces/ <-- Mojom interfaces
+```
-### Dependencies
+## Dependencies
Code within `//services` may only depend on each other via each other's
-`/public/` directories, i.e. implementation code cannot be shared directly.
+`/public/` directories, *i.e.* implementation code may not be shared directly.
Service code should also take care to tightly limit the dependencies on static
libraries from outside of `//services`. Dependencies to large platform
layers like `//content`, `//chrome` or `//third_party/WebKit` must be avoided.
-### Physical Packaging
+## Physical Packaging
Note that while it may be possible to build a discrete physical package (DSO)
for each service, products consuming these services may package them
differently, e.g. by combining them into a single package.
-### Documentation
+## Additional Documentation
[High-level Design Doc](https://docs.google.com/document/d/15I7sQyQo6zsqXVNAlVd520tdGaS8FCicZHrN0yRu-oU)
-[Homepage](https://sites.google.com/a/chromium.org/dev/servicification)
-### Relationship to other top-level directories in //
+[Servicification Homepage](https://sites.google.com/a/chromium.org/dev/servicification)
+
+## Relationship To Other Top-Level Directories
Services can be thought of as integrators of library code from across the
-Chromium repository, most commonly //base and //mojo (obviously) but for each
-service also //components, //ui, etc in accordance with the functionality they
-provide.
+Chromium repository, most commonly `//base` and `//mojo` (obviously) but for
+each service also `//components`, `//ui`, *etc.* in accordance with the
+functionality they provide.
-Not everything in //components is automatically a service in its own right.
-Think of //components as sort of like a //lib. Individual //components can
-define, implement and use mojom interfaces, but only //services have unique
-identities with the Service Manager.
+Not everything in `//components` is automatically a service in its own right.
+Think of `//components` as sort of like a `//lib`. Individual `//components` can
+define, implement and use Mojom interfaces, but only `//services` have unique
+identities with the Service Manager and so only `//services` make it possible
+for Mojom interfaces to be acquired.
-### Adding a new service
+## Adding a new service
-Please start a thread on [services-dev](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev)
+See the [Service Manager documentation](/services/service_manager) for more
+details regarding how to define a service and expose or consume interfaces to
+and from other services.
+Please start a thread on [services-dev@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/services-dev)
+if you want to introduce a new service.
diff --git a/chromium/services/catalog/catalog.cc b/chromium/services/catalog/catalog.cc
index bdd55811d23..3189881d843 100644
--- a/chromium/services/catalog/catalog.cc
+++ b/chromium/services/catalog/catalog.cc
@@ -24,8 +24,7 @@
#include "services/catalog/constants.h"
#include "services/catalog/entry_cache.h"
#include "services/catalog/instance.h"
-#include "services/service_manager/public/cpp/connection.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
namespace catalog {
@@ -37,8 +36,8 @@ const char kCatalogServiceEmbeddedKey[] = "embedded";
const char kCatalogServiceExecutableKey[] = "executable";
const char kCatalogServiceManifestKey[] = "manifest";
-base::LazyInstance<std::unique_ptr<base::Value>> g_default_static_manifest =
- LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<std::unique_ptr<base::Value>>::DestructorAtExit
+ g_default_static_manifest = LAZY_INSTANCE_INITIALIZER;
void LoadCatalogManifestIntoCache(const base::Value* root, EntryCache* cache) {
DCHECK(root);
@@ -112,20 +111,24 @@ void LoadCatalogManifestIntoCache(const base::Value* root, EntryCache* cache) {
class Catalog::ServiceImpl : public service_manager::Service {
public:
- explicit ServiceImpl(Catalog* catalog) : catalog_(catalog) {}
+ explicit ServiceImpl(Catalog* catalog) : catalog_(catalog) {
+ registry_.AddInterface<mojom::Catalog>(catalog_);
+ registry_.AddInterface<filesystem::mojom::Directory>(catalog_);
+ registry_.AddInterface<service_manager::mojom::Resolver>(catalog_);
+ }
~ServiceImpl() override {}
// service_manager::Service:
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override {
- registry->AddInterface<mojom::Catalog>(catalog_);
- registry->AddInterface<filesystem::mojom::Directory>(catalog_);
- registry->AddInterface<service_manager::mojom::Resolver>(catalog_);
- return true;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
private:
Catalog* const catalog_;
+ service_manager::BinderRegistry registry_;
DISALLOW_COPY_AND_ASSIGN(ServiceImpl);
};
diff --git a/chromium/services/catalog/entry.cc b/chromium/services/catalog/entry.cc
index 7db2026282d..2e2836bd21f 100644
--- a/chromium/services/catalog/entry.cc
+++ b/chromium/services/catalog/entry.cc
@@ -25,7 +25,7 @@ bool ReadStringSet(const base::ListValue& list_value,
DCHECK(string_set);
for (const auto& value_value : list_value) {
std::string value;
- if (!value_value->GetAsString(&value)) {
+ if (!value_value.GetAsString(&value)) {
LOG(ERROR) << "Entry::Deserialize: list member must be a string";
return false;
}
diff --git a/chromium/services/catalog/public/tools/catalog.cc.tmpl b/chromium/services/catalog/public/tools/catalog.cc.tmpl
index 2edab791594..f905080e8e2 100644
--- a/chromium/services/catalog/public/tools/catalog.cc.tmpl
+++ b/chromium/services/catalog/public/tools/catalog.cc.tmpl
@@ -39,7 +39,7 @@ base::MakeUnique<base::Value>({{source}})
{%- elif source|is_bool -%}
base::MakeUnique<base::Value>({{source|lower}})
{%- elif source|is_string or source|is_unicode -%}
-base::MakeUnique<base::StringValue>("{{source|make_ascii}}")
+base::MakeUnique<base::Value>("{{source|make_ascii}}")
{%- else %}
{{raise("Unknown value type: %s" % source, source)}}
{%- endif %}
diff --git a/chromium/services/image_decoder/BUILD.gn b/chromium/services/data_decoder/BUILD.gn
index fac256d2043..6f347b955b2 100644
--- a/chromium/services/image_decoder/BUILD.gn
+++ b/chromium/services/data_decoder/BUILD.gn
@@ -7,23 +7,23 @@ import("//services/service_manager/public/service_manifest.gni")
source_set("lib") {
sources = [
+ "data_decoder_service.cc",
+ "data_decoder_service.h",
"image_decoder_impl.cc",
"image_decoder_impl.h",
- "image_decoder_service.cc",
- "image_decoder_service.h",
]
deps = [
"//base",
- "//content/public/child",
"//mojo/public/cpp/bindings",
"//skia",
+ "//third_party/WebKit/public:blink",
"//ui/gfx",
"//ui/gfx/geometry",
]
public_deps = [
- "//services/image_decoder/public/interfaces",
+ "//services/data_decoder/public/interfaces",
"//services/service_manager/public/cpp",
]
}
@@ -50,6 +50,6 @@ source_set("tests") {
}
service_manifest("manifest") {
- name = "image_decoder"
+ name = "data_decoder"
source = "manifest.json"
}
diff --git a/chromium/services/image_decoder/DEPS b/chromium/services/data_decoder/DEPS
index 9dca8ee9efc..d15dcafe231 100644
--- a/chromium/services/image_decoder/DEPS
+++ b/chromium/services/data_decoder/DEPS
@@ -1,5 +1,4 @@
include_rules = [
- "+content/public/child",
"+gin",
"+skia",
"+third_party/WebKit/public",
diff --git a/chromium/services/data_decoder/README.md b/chromium/services/data_decoder/README.md
new file mode 100644
index 00000000000..e84b2a13460
--- /dev/null
+++ b/chromium/services/data_decoder/README.md
@@ -0,0 +1,3 @@
+The data_decoder service exists to facilitate safe data decoding within an
+isolated sandboxed process.
+
diff --git a/chromium/services/data_decoder/data_decoder_service.cc b/chromium/services/data_decoder/data_decoder_service.cc
new file mode 100644
index 00000000000..cf793910310
--- /dev/null
+++ b/chromium/services/data_decoder/data_decoder_service.cc
@@ -0,0 +1,68 @@
+// 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/data_decoder/data_decoder_service.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/data_decoder/image_decoder_impl.h"
+#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
+#include "services/service_manager/public/cpp/service_context.h"
+
+namespace data_decoder {
+
+namespace {
+
+void OnImageDecoderRequest(
+ service_manager::ServiceContextRefFactory* ref_factory,
+ mojom::ImageDecoderRequest request) {
+ mojo::MakeStrongBinding(
+ base::MakeUnique<ImageDecoderImpl>(ref_factory->CreateRef()),
+ std::move(request));
+}
+
+} // namespace
+
+DataDecoderService::DataDecoderService() : weak_factory_(this) {}
+
+DataDecoderService::~DataDecoderService() = default;
+
+// static
+std::unique_ptr<service_manager::Service> DataDecoderService::Create() {
+ return base::MakeUnique<DataDecoderService>();
+}
+
+void DataDecoderService::OnStart() {
+ ref_factory_.reset(new service_manager::ServiceContextRefFactory(base::Bind(
+ &DataDecoderService::MaybeRequestQuitDelayed, base::Unretained(this))));
+ registry_.AddInterface(
+ base::Bind(&OnImageDecoderRequest, ref_factory_.get()));
+}
+
+void DataDecoderService::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
+}
+
+void DataDecoderService::MaybeRequestQuitDelayed() {
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&DataDecoderService::MaybeRequestQuit,
+ weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromSeconds(5));
+}
+
+void DataDecoderService::MaybeRequestQuit() {
+ DCHECK(ref_factory_);
+ if (ref_factory_->HasNoRefs())
+ context()->RequestQuit();
+}
+
+} // namespace data_decoder
diff --git a/chromium/services/data_decoder/data_decoder_service.h b/chromium/services/data_decoder/data_decoder_service.h
new file mode 100644
index 00000000000..0de223d1890
--- /dev/null
+++ b/chromium/services/data_decoder/data_decoder_service.h
@@ -0,0 +1,46 @@
+// 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_DATA_DECODER_DATA_DECODER_SERVICE_H_
+#define SERVICES_DATA_DECODER_DATA_DECODER_SERVICE_H_
+
+#include <memory>
+
+#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"
+
+namespace data_decoder {
+
+class DataDecoderService : public service_manager::Service {
+ public:
+ DataDecoderService();
+ ~DataDecoderService() override;
+
+ // 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::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
+
+ private:
+ void MaybeRequestQuitDelayed();
+ void MaybeRequestQuit();
+
+ std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
+ service_manager::BinderRegistry registry_;
+ base::WeakPtrFactory<DataDecoderService> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DataDecoderService);
+};
+
+} // namespace data_decoder
+
+#endif // SERVICES_DATA_DECODER_DATA_DECODER_SERVICE_H_
diff --git a/chromium/services/image_decoder/image_decoder_impl.cc b/chromium/services/data_decoder/image_decoder_impl.cc
index 30c2fe95c26..2ecabe69b6b 100644
--- a/chromium/services/image_decoder/image_decoder_impl.cc
+++ b/chromium/services/data_decoder/image_decoder_impl.cc
@@ -2,24 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/image_decoder/image_decoder_impl.h"
+#include "services/data_decoder/image_decoder_impl.h"
#include <string.h>
#include <utility>
#include "base/logging.h"
-#include "content/public/child/image_decoder_utils.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "skia/ext/image_operations.h"
+#include "third_party/WebKit/public/platform/WebData.h"
+#include "third_party/WebKit/public/platform/WebImage.h"
+#include "third_party/WebKit/public/platform/WebSize.h"
#include "third_party/skia/include/core/SkBitmap.h"
#if defined(OS_CHROMEOS)
-#include "ui/gfx/chromeos/codec/jpeg_codec_robust_slow.h"
+#include "ui/gfx/codec/chromeos/jpeg_codec_robust_slow.h"
#include "ui/gfx/codec/png_codec.h"
#endif
-namespace image_decoder {
+namespace data_decoder {
namespace {
@@ -58,16 +60,20 @@ void ImageDecoderImpl::DecodeImage(const std::vector<uint8_t>& encoded_data,
// Our robust PNG decoding is using libpng.
if (encoded_data.size()) {
SkBitmap decoded_png;
- if (gfx::PNGCodec::Decode(
- encoded_data.data(), encoded_data.size(), &decoded_png)) {
+ if (gfx::PNGCodec::Decode(encoded_data.data(), encoded_data.size(),
+ &decoded_png)) {
decoded_image = decoded_png;
}
}
}
#endif // defined(OS_CHROMEOS)
if (codec == mojom::ImageCodec::DEFAULT) {
- decoded_image = content::DecodeImage(
- encoded_data.data(), desired_image_frame_size, encoded_data.size());
+ decoded_image =
+ blink::WebImage::FromData(
+ blink::WebData(reinterpret_cast<const char*>(encoded_data.data()),
+ encoded_data.size()),
+ desired_image_frame_size)
+ .GetSkBitmap();
}
if (!decoded_image.isNull()) {
@@ -100,4 +106,4 @@ void ImageDecoderImpl::DecodeImage(const std::vector<uint8_t>& encoded_data,
callback.Run(decoded_image);
}
-} // namespace image_decoder
+} // namespace data_decoder
diff --git a/chromium/services/image_decoder/image_decoder_impl.h b/chromium/services/data_decoder/image_decoder_impl.h
index 09dbc99f030..b669b254161 100644
--- a/chromium/services/image_decoder/image_decoder_impl.h
+++ b/chromium/services/data_decoder/image_decoder_impl.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 CHROME_UTILITY_IMAGE_DECODER_IMPL_H_
-#define CHROME_UTILITY_IMAGE_DECODER_IMPL_H_
+#ifndef SERVICES_DATA_DECODER_IMAGE_DECODER_IMPL_H_
+#define SERVICES_DATA_DECODER_IMAGE_DECODER_IMPL_H_
#include <stdint.h>
#include "base/macros.h"
-#include "services/image_decoder/public/interfaces/image_decoder.mojom.h"
+#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
#include "ui/gfx/geometry/size.h"
-namespace image_decoder {
+namespace data_decoder {
class ImageDecoderImpl : public mojom::ImageDecoder {
public:
@@ -34,6 +34,6 @@ class ImageDecoderImpl : public mojom::ImageDecoder {
DISALLOW_COPY_AND_ASSIGN(ImageDecoderImpl);
};
-} // namespace image_decoder
+} // namespace data_decoder
-#endif // CHROME_UTILITY_IMAGE_DECODER_IMPL_H_
+#endif // SERVICES_DATA_DECODER_IMAGE_DECODER_IMPL_H_
diff --git a/chromium/services/image_decoder/image_decoder_impl_unittest.cc b/chromium/services/data_decoder/image_decoder_impl_unittest.cc
index f75e8ec249f..0f304256d7e 100644
--- a/chromium/services/image_decoder/image_decoder_impl_unittest.cc
+++ b/chromium/services/data_decoder/image_decoder_impl_unittest.cc
@@ -10,9 +10,9 @@
#include "base/message_loop/message_loop.h"
#include "gin/array_buffer.h"
#include "gin/public/isolate_holder.h"
-#include "services/image_decoder/image_decoder_impl.h"
+#include "services/data_decoder/image_decoder_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/WebKit/public/platform/scheduler/utility/webthread_impl_for_utility_thread.h"
+#include "third_party/WebKit/public/platform/scheduler/child/webthread_base.h"
#include "third_party/WebKit/public/web/WebKit.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/jpeg_codec.h"
@@ -21,7 +21,7 @@
#include "gin/v8_initializer.h"
#endif
-namespace image_decoder {
+namespace data_decoder {
namespace {
@@ -71,21 +71,22 @@ class Request {
class BlinkInitializer : public blink::Platform {
public:
BlinkInitializer()
- : main_thread_(new blink::scheduler::WebThreadImplForUtilityThread()) {
+ : main_thread_(
+ blink::scheduler::WebThreadBase::InitializeUtilityThread()) {
#if defined(V8_USE_EXTERNAL_STARTUP_DATA)
gin::V8Initializer::LoadV8Snapshot();
gin::V8Initializer::LoadV8Natives();
#endif
- blink::initialize(this);
+ blink::Initialize(this);
}
~BlinkInitializer() override {}
- blink::WebThread* currentThread() override { return main_thread_.get(); }
+ blink::WebThread* CurrentThread() override { return main_thread_.get(); }
private:
- std::unique_ptr<blink::scheduler::WebThreadImplForUtilityThread> main_thread_;
+ std::unique_ptr<blink::scheduler::WebThreadBase> main_thread_;
DISALLOW_COPY_AND_ASSIGN(BlinkInitializer);
};
@@ -118,8 +119,7 @@ TEST_F(ImageDecoderImplTest, DecodeImageSizeLimit) {
int base_msg_size = sizeof(skia::mojom::Bitmap::Data_);
// Sizes which should trigger dimension-halving 0, 1 and 2 times
- int heights[] = {max_height_for_msg - 10,
- max_height_for_msg + 10,
+ int heights[] = {max_height_for_msg - 10, max_height_for_msg + 10,
2 * max_height_for_msg + 10};
int widths[] = {heights[0] * 3 / 2, heights[1] * 3 / 2, heights[2] * 3 / 2};
for (size_t i = 0; i < arraysize(heights); i++) {
@@ -161,4 +161,4 @@ TEST_F(ImageDecoderImplTest, DecodeImageFailed) {
EXPECT_TRUE(request.bitmap().isNull());
}
-} // namespace image_decoder
+} // namespace data_decoder
diff --git a/chromium/services/image_decoder/manifest.json b/chromium/services/data_decoder/manifest.json
index a9fdb075816..bc0335b3ef6 100644
--- a/chromium/services/image_decoder/manifest.json
+++ b/chromium/services/data_decoder/manifest.json
@@ -1,10 +1,10 @@
{
- "name": "image_decoder",
- "display_name": "Image Decoder Service",
+ "name": "data_decoder",
+ "display_name": "Data Decoder Service",
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "decode": [ "image_decoder::mojom::ImageDecoder" ]
+ "image_decoder": [ "data_decoder::mojom::ImageDecoder" ]
},
"requires": {
"service_manager": [ "service_manager:all_users" ]
diff --git a/chromium/services/image_decoder/public/cpp/BUILD.gn b/chromium/services/data_decoder/public/cpp/BUILD.gn
index b9b2a7c2869..ebab3dca302 100644
--- a/chromium/services/image_decoder/public/cpp/BUILD.gn
+++ b/chromium/services/data_decoder/public/cpp/BUILD.gn
@@ -6,12 +6,12 @@ import("//mojo/public/tools/bindings/mojom.gni")
source_set("cpp") {
sources = [
- "decode.cc",
- "decode.h",
+ "decode_image.cc",
+ "decode_image.h",
]
public_deps = [
- "//services/image_decoder/public/interfaces",
+ "//services/data_decoder/public/interfaces",
"//services/service_manager/public/cpp",
]
}
diff --git a/chromium/services/image_decoder/public/cpp/decode.cc b/chromium/services/data_decoder/public/cpp/decode_image.cc
index 99109266b47..3efd460bb0d 100644
--- a/chromium/services/image_decoder/public/cpp/decode.cc
+++ b/chromium/services/data_decoder/public/cpp/decode_image.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/image_decoder/public/cpp/decode.h"
+#include "services/data_decoder/public/cpp/decode_image.h"
-#include "services/image_decoder/public/interfaces/constants.mojom.h"
+#include "services/data_decoder/public/interfaces/constants.mojom.h"
#include "services/service_manager/public/cpp/connector.h"
#include "third_party/skia/include/core/SkBitmap.h"
-namespace image_decoder {
+namespace data_decoder {
namespace {
@@ -30,13 +30,13 @@ void OnConnectionError(
} // namespace
-void Decode(service_manager::Connector* connector,
- const std::vector<uint8_t>& encoded_bytes,
- mojom::ImageCodec codec,
- bool shrink_to_fit,
- uint64_t max_size_in_bytes,
- const gfx::Size& desired_image_frame_size,
- const mojom::ImageDecoder::DecodeImageCallback& callback) {
+void DecodeImage(service_manager::Connector* connector,
+ const std::vector<uint8_t>& encoded_bytes,
+ mojom::ImageCodec codec,
+ bool shrink_to_fit,
+ uint64_t max_size_in_bytes,
+ const gfx::Size& desired_image_frame_size,
+ const mojom::ImageDecoder::DecodeImageCallback& callback) {
mojom::ImageDecoderPtr decoder;
connector->BindInterface(mojom::kServiceName, &decoder);
decoder.set_connection_error_handler(
@@ -48,4 +48,4 @@ void Decode(service_manager::Connector* connector,
base::Bind(&OnDecodeImage, base::Passed(&decoder), callback));
}
-} // namespace image_decoder
+} // namespace data_decoder
diff --git a/chromium/services/image_decoder/public/cpp/decode.h b/chromium/services/data_decoder/public/cpp/decode_image.h
index ea0fa2e848f..2517fdc5d5f 100644
--- a/chromium/services/image_decoder/public/cpp/decode.h
+++ b/chromium/services/data_decoder/public/cpp/decode_image.h
@@ -2,14 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef SERVICES_IMAGE_DECODER_PUBLIC_CPP_DECODE_H_
-#define SERVICES_IMAGE_DECODER_PUBLIC_CPP_DECODE_H_
+#ifndef SERVICES_DATA_DECODER_PUBLIC_CPP_DECODE_H_
+#define SERVICES_DATA_DECODER_PUBLIC_CPP_DECODE_H_
#include <stdint.h>
#include <vector>
-#include "services/image_decoder/public/interfaces/image_decoder.mojom.h"
+#include "services/data_decoder/public/interfaces/image_decoder.mojom.h"
namespace gfx {
class Size;
@@ -19,11 +19,11 @@ namespace service_manager {
class Connector;
}
-namespace image_decoder {
+namespace data_decoder {
const uint64_t kDefaultMaxSizeInBytes = 128 * 1024 * 1024;
-// Helper function to decode an image via the image_decoder service. For images
+// Helper function to decode an image via the data_decoder service. For images
// with multiple frames (e.g. ico files), a frame with a size as close as
// possible to |desired_image_frame_size| is chosen (tries to take one in larger
// size if there's no precise match). Passing gfx::Size() as
@@ -32,14 +32,14 @@ const uint64_t kDefaultMaxSizeInBytes = 128 * 1024 * 1024;
// Upon completion, |callback| is invoked on the calling thread TaskRunner with
// an SkBitmap argument. The SkBitmap will be null on failure and non-null on
// success.
-void Decode(service_manager::Connector* connector,
- const std::vector<uint8_t>& encoded_bytes,
- mojom::ImageCodec codec,
- bool shrink_to_fit,
- uint64_t max_size_in_bytes,
- const gfx::Size& desired_image_frame_size,
- const mojom::ImageDecoder::DecodeImageCallback& callback);
+void DecodeImage(service_manager::Connector* connector,
+ const std::vector<uint8_t>& encoded_bytes,
+ mojom::ImageCodec codec,
+ bool shrink_to_fit,
+ uint64_t max_size_in_bytes,
+ const gfx::Size& desired_image_frame_size,
+ const mojom::ImageDecoder::DecodeImageCallback& callback);
-} // namespace image_decoder
+} // namespace data_decoder
-#endif // SERVICES_IMAGE_DECODER_PUBLIC_CPP_DECODE_H_
+#endif // SERVICES_DATA_DECODER_PUBLIC_CPP_DECODE_H_
diff --git a/chromium/services/image_decoder/public/interfaces/BUILD.gn b/chromium/services/data_decoder/public/interfaces/BUILD.gn
index 8e695db7a77..8e695db7a77 100644
--- a/chromium/services/image_decoder/public/interfaces/BUILD.gn
+++ b/chromium/services/data_decoder/public/interfaces/BUILD.gn
diff --git a/chromium/services/image_decoder/public/interfaces/OWNERS b/chromium/services/data_decoder/public/interfaces/OWNERS
index 08850f42120..08850f42120 100644
--- a/chromium/services/image_decoder/public/interfaces/OWNERS
+++ b/chromium/services/data_decoder/public/interfaces/OWNERS
diff --git a/chromium/services/image_decoder/public/interfaces/constants.mojom b/chromium/services/data_decoder/public/interfaces/constants.mojom
index 5897a7d9c6d..60a96f275bd 100644
--- a/chromium/services/image_decoder/public/interfaces/constants.mojom
+++ b/chromium/services/data_decoder/public/interfaces/constants.mojom
@@ -2,6 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-module image_decoder.mojom;
+module data_decoder.mojom;
-const string kServiceName = "image_decoder";
+const string kServiceName = "data_decoder";
diff --git a/chromium/services/image_decoder/public/interfaces/image_decoder.mojom b/chromium/services/data_decoder/public/interfaces/image_decoder.mojom
index c13e796cd1f..f53dd5fbf25 100644
--- a/chromium/services/image_decoder/public/interfaces/image_decoder.mojom
+++ b/chromium/services/data_decoder/public/interfaces/image_decoder.mojom
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-module image_decoder.mojom;
+module data_decoder.mojom;
import "skia/public/interfaces/bitmap.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
diff --git a/chromium/services/device/BUILD.gn b/chromium/services/device/BUILD.gn
index 3783fed88bd..3f781a768a8 100644
--- a/chromium/services/device/BUILD.gn
+++ b/chromium/services/device/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/features.gni")
+import("//services/catalog/public/tools/catalog.gni")
import("//services/service_manager/public/cpp/service.gni")
import("//services/service_manager/public/service_manifest.gni")
@@ -10,6 +12,12 @@ if (is_android) {
}
source_set("lib") {
+ # This should be visible only to embedders of the Device Service, and the
+ # dependence should only be for the purpose of embedding the Device Service.
+ visibility = [
+ ":test_support",
+ "//content/browser",
+ ]
sources = [
"device_service.cc",
"device_service.h",
@@ -17,10 +25,19 @@ source_set("lib") {
deps = [
"//base",
+ "//device/battery:mojo_bindings",
+ "//device/generic_sensor",
+ "//device/sensors",
+ "//device/sensors/public/interfaces",
+ "//device/vibration:mojo_bindings",
+ "//device/wake_lock",
"//services/device/fingerprint",
"//services/device/power_monitor",
+ "//services/device/public/cpp:device_features",
+ "//services/device/screen_orientation",
"//services/device/time_zone_monitor",
"//services/service_manager/public/cpp",
+ "//ui/gfx",
]
if (is_android) {
@@ -28,6 +45,12 @@ source_set("lib") {
"//services/device/android/register_jni.cc",
"//services/device/android/register_jni.h",
]
+ deps += [ ":device_service_jni_headers" ]
+ } else {
+ deps += [
+ "//device/battery",
+ "//device/vibration",
+ ]
}
}
@@ -37,11 +60,14 @@ source_set("tests") {
sources = [
"power_monitor/power_monitor_message_broadcaster_unittest.cc",
"public/cpp/power_monitor/power_monitor_broadcast_source_unittest.cc",
+ "vibration/vibration_manager_impl_unittest.cc",
]
deps = [
+ ":test_support",
"//base",
"//base/test:test_support",
+ "//device/vibration:mojo_bindings",
"//mojo/public/cpp/bindings",
"//services/device/power_monitor",
"//services/device/public/cpp/power_monitor",
@@ -52,6 +78,18 @@ source_set("tests") {
sources += [ "fingerprint/fingerprint_chromeos_unittest.cc" ]
deps += [ "//services/device/fingerprint" ]
}
+
+ if (is_android) {
+ deps += [
+ ":device_service_jni_headers",
+ "//device/vibration/android:vibration_jni_headers",
+ ]
+ } else {
+ deps += [
+ "//device/battery",
+ "//device/vibration",
+ ]
+ }
}
service_manifest("manifest") {
@@ -59,11 +97,70 @@ service_manifest("manifest") {
source = "manifest.json"
}
+service_manifest("unittest_manifest") {
+ name = "device_unittests"
+ source = "unittest_manifest.json"
+ packaged_services = [ ":manifest" ]
+}
+
+catalog("tests_catalog") {
+ testonly = true
+ embedded_services = [ ":unittest_manifest" ]
+}
+
+source_set("test_support") {
+ testonly = true
+
+ sources = [
+ "device_service_test_base.cc",
+ "device_service_test_base.h",
+ ]
+
+ deps = [
+ ":lib",
+ "//base",
+ "//base/test:test_support",
+ "//mojo/public/cpp/bindings",
+ "//services/device/public/interfaces:constants",
+ "//services/service_manager/public/cpp:service_test_support",
+ "//services/service_manager/public/cpp:sources",
+ ]
+}
+
if (is_android) {
+ generate_jni("device_service_jni_headers") {
+ sources = [
+ "android/java/src/org/chromium/services/device/InterfaceRegistrar.java",
+ ]
+ jni_package = "device_service"
+ }
+
android_library("java") {
- java_files = [ "time_zone_monitor/android/java/src/org/chromium/device/time_zone_monitor/TimeZoneMonitor.java" ]
+ # This should be visible only to embedders of the Device Service, and the
+ # dependence should only be for the purpose of embedding the Device Service.
+ # //content/public/android:* here actually wants to identify the
+ # //content/public/android:content_java target and all of its generated
+ # targets which also need to see this target as well.
+ # //services:* identifies //services:service_unittests and all of its
+ # generated targets.
+ visibility = [
+ "//content/public/android:*",
+ "//services:*",
+ ]
+ java_files = [ "android/java/src/org/chromium/services/device/InterfaceRegistrar.java" ]
deps = [
"//base:base_java",
+ "//device/battery:mojo_bindings_java",
+ "//device/battery/android:battery_monitor_java",
+ "//device/vibration:mojo_bindings_java",
+ "//device/vibration/android:vibration_manager_java",
+ "//mojo/android:system_java",
+ "//mojo/public/java:bindings_java",
+ "//mojo/public/java:system_java",
+ "//services/device/screen_orientation:java",
+ "//services/device/time_zone_monitor:java",
+ "//services/service_manager/public/interfaces:interfaces_java",
+ "//services/service_manager/public/java:service_manager_java",
]
}
}
diff --git a/chromium/services/device/DEPS b/chromium/services/device/DEPS
index 56fffa1fea5..6383a3f26cd 100644
--- a/chromium/services/device/DEPS
+++ b/chromium/services/device/DEPS
@@ -1,3 +1,5 @@
include_rules = [
"+device",
+ "+jni",
+ "+ui/gfx/native_widget_types.h",
]
diff --git a/chromium/services/device/OWNERS b/chromium/services/device/OWNERS
index f4ee2fd74db..e3cd731321f 100644
--- a/chromium/services/device/OWNERS
+++ b/chromium/services/device/OWNERS
@@ -2,4 +2,4 @@ blundell@chromium.org
reillyg@chromium.org
rockot@chromium.org
-# COMPONENT: IO>USB \ No newline at end of file
+# TEAM: device-dev@chromium.org
diff --git a/chromium/services/device/device_service.cc b/chromium/services/device/device_service.cc
index f51d5a922e3..5578cf57256 100644
--- a/chromium/services/device/device_service.cc
+++ b/chromium/services/device/device_service.cc
@@ -4,65 +4,261 @@
#include "services/device/device_service.h"
+#include <utility>
+
#include "base/bind.h"
+#include "base/feature_list.h"
#include "base/memory/ptr_util.h"
#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
+#include "device/battery/battery_monitor.mojom.h"
+#include "device/battery/battery_monitor_impl.h"
+#include "device/battery/battery_status_service.h"
+#include "device/generic_sensor/sensor_provider_impl.h"
+#include "device/sensors/device_sensor_host.h"
+#include "device/wake_lock/wake_lock_context_provider.h"
+#include "mojo/public/cpp/system/message_pipe.h"
#include "services/device/fingerprint/fingerprint.h"
#include "services/device/power_monitor/power_monitor_message_broadcaster.h"
+#include "services/device/public/cpp/device_features.h"
#include "services/device/time_zone_monitor/time_zone_monitor.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/service_info.h"
+#include "ui/gfx/native_widget_types.h"
#if defined(OS_ANDROID)
+#include "base/android/context_utils.h"
+#include "base/android/jni_android.h"
+#include "jni/InterfaceRegistrar_jni.h"
#include "services/device/android/register_jni.h"
+#include "services/device/screen_orientation/screen_orientation_listener_android.h"
+#else
+#include "device/vibration/vibration_manager_impl.h"
#endif
namespace device {
-std::unique_ptr<service_manager::Service> CreateDeviceService(
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner) {
#if defined(OS_ANDROID)
+std::unique_ptr<service_manager::Service> CreateDeviceService(
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+ const WakeLockContextCallback& wake_lock_context_callback) {
if (!EnsureJniRegistered()) {
DLOG(ERROR) << "Failed to register JNI for Device Service";
return nullptr;
}
-#endif
- return base::MakeUnique<DeviceService>(std::move(file_task_runner));
+ return base::MakeUnique<DeviceService>(std::move(file_task_runner),
+ std::move(io_task_runner),
+ wake_lock_context_callback);
}
+#else
+std::unique_ptr<service_manager::Service> CreateDeviceService(
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner) {
+ return base::MakeUnique<DeviceService>(std::move(file_task_runner),
+ std::move(io_task_runner));
+}
+#endif
+#if defined(OS_ANDROID)
+DeviceService::DeviceService(
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+ const WakeLockContextCallback& wake_lock_context_callback)
+ : java_interface_provider_initialized_(false),
+ file_task_runner_(std::move(file_task_runner)),
+ io_task_runner_(std::move(io_task_runner)),
+ wake_lock_context_callback_(wake_lock_context_callback) {}
+#else
DeviceService::DeviceService(
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner)
- : file_task_runner_(std::move(file_task_runner)) {}
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
+ : file_task_runner_(std::move(file_task_runner)),
+ io_task_runner_(std::move(io_task_runner)) {}
+#endif
+
+DeviceService::~DeviceService() {
+#if !defined(OS_ANDROID)
+ device::BatteryStatusService::GetInstance()->Shutdown();
+#endif
+}
-DeviceService::~DeviceService() {}
+void DeviceService::OnStart() {
+ registry_.AddInterface<mojom::Fingerprint>(this);
+ registry_.AddInterface<mojom::LightSensor>(this);
+ registry_.AddInterface<mojom::MotionSensor>(this);
+ registry_.AddInterface<mojom::OrientationSensor>(this);
+ registry_.AddInterface<mojom::OrientationAbsoluteSensor>(this);
+ registry_.AddInterface<mojom::PowerMonitor>(this);
+ registry_.AddInterface<mojom::ScreenOrientationListener>(this);
+ if (base::FeatureList::IsEnabled(features::kGenericSensor)) {
+ registry_.AddInterface<mojom::SensorProvider>(this);
+ }
+ registry_.AddInterface<mojom::TimeZoneMonitor>(this);
+ registry_.AddInterface<mojom::WakeLockContextProvider>(this);
-void DeviceService::OnStart() {}
+#if defined(OS_ANDROID)
+ registry_.AddInterface(GetJavaInterfaceProvider()
+ ->CreateInterfaceFactory<mojom::BatteryMonitor>());
+ registry_.AddInterface(
+ GetJavaInterfaceProvider()
+ ->CreateInterfaceFactory<mojom::VibrationManager>());
+#else
+ registry_.AddInterface<mojom::BatteryMonitor>(this);
+ registry_.AddInterface<mojom::VibrationManager>(this);
+#endif
+}
-bool DeviceService::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface<mojom::Fingerprint>(this);
- registry->AddInterface<mojom::PowerMonitor>(this);
- registry->AddInterface<mojom::TimeZoneMonitor>(this);
- return true;
+void DeviceService::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
+#if !defined(OS_ANDROID)
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::BatteryMonitorRequest request) {
+ BatteryMonitorImpl::Create(std::move(request));
+}
+
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::VibrationManagerRequest request) {
+ VibrationManagerImpl::Create(std::move(request));
+}
+#endif
+
void DeviceService::Create(const service_manager::Identity& remote_identity,
mojom::FingerprintRequest request) {
Fingerprint::Create(std::move(request));
}
void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::LightSensorRequest request) {
+#if defined(OS_ANDROID)
+ // On Android the device sensors implementations need to run on the UI thread
+ // to communicate to Java.
+ DeviceLightHost::Create(std::move(request));
+#else
+ // On platforms other than Android the device sensors implementations run on
+ // the IO thread.
+ if (io_task_runner_) {
+ io_task_runner_->PostTask(FROM_HERE, base::Bind(&DeviceLightHost::Create,
+ base::Passed(&request)));
+ }
+#endif // defined(OS_ANDROID)
+}
+
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::MotionSensorRequest request) {
+#if defined(OS_ANDROID)
+ // On Android the device sensors implementations need to run on the UI thread
+ // to communicate to Java.
+ DeviceMotionHost::Create(std::move(request));
+#else
+ // On platforms other than Android the device sensors implementations run on
+ // the IO thread.
+ if (io_task_runner_) {
+ io_task_runner_->PostTask(FROM_HERE, base::Bind(&DeviceMotionHost::Create,
+ base::Passed(&request)));
+ }
+#endif // defined(OS_ANDROID)
+}
+
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::OrientationSensorRequest request) {
+#if defined(OS_ANDROID)
+ // On Android the device sensors implementations need to run on the UI thread
+ // to communicate to Java.
+ DeviceOrientationHost::Create(std::move(request));
+#else
+ // On platforms other than Android the device sensors implementations run on
+ // the IO thread.
+ if (io_task_runner_) {
+ io_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&DeviceOrientationHost::Create, base::Passed(&request)));
+ }
+#endif // defined(OS_ANDROID)
+}
+
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::OrientationAbsoluteSensorRequest request) {
+#if defined(OS_ANDROID)
+ // On Android the device sensors implementations need to run on the UI thread
+ // to communicate to Java.
+ DeviceOrientationAbsoluteHost::Create(std::move(request));
+#else
+ // On platforms other than Android the device sensors implementations run on
+ // the IO thread.
+ if (io_task_runner_) {
+ io_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&DeviceOrientationAbsoluteHost::Create,
+ base::Passed(&request)));
+ }
+#endif // defined(OS_ANDROID)
+}
+
+void DeviceService::Create(const service_manager::Identity& remote_identity,
mojom::PowerMonitorRequest request) {
- PowerMonitorMessageBroadcaster::Create(std::move(request));
+ if (!power_monitor_message_broadcaster_) {
+ power_monitor_message_broadcaster_ =
+ base::MakeUnique<PowerMonitorMessageBroadcaster>();
+ }
+ power_monitor_message_broadcaster_->Bind(std::move(request));
+}
+
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::ScreenOrientationListenerRequest request) {
+#if defined(OS_ANDROID)
+ if (io_task_runner_) {
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&ScreenOrientationListenerAndroid::Create,
+ base::Passed(&request)));
+ }
+#endif
+}
+
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::SensorProviderRequest request) {
+ if (io_task_runner_) {
+ io_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&device::SensorProviderImpl::Create,
+ file_task_runner_, base::Passed(&request)));
+ }
}
void DeviceService::Create(const service_manager::Identity& remote_identity,
mojom::TimeZoneMonitorRequest request) {
if (!time_zone_monitor_)
- time_zone_monitor_ = device::TimeZoneMonitor::Create(file_task_runner_);
+ time_zone_monitor_ = TimeZoneMonitor::Create(file_task_runner_);
time_zone_monitor_->Bind(std::move(request));
}
+void DeviceService::Create(const service_manager::Identity& remote_identity,
+ mojom::WakeLockContextProviderRequest request) {
+ WakeLockContextProvider::Create(std::move(request), file_task_runner_,
+ wake_lock_context_callback_);
+}
+
+#if defined(OS_ANDROID)
+service_manager::InterfaceProvider* DeviceService::GetJavaInterfaceProvider() {
+ if (!java_interface_provider_initialized_) {
+ service_manager::mojom::InterfaceProviderPtr provider;
+ JNIEnv* env = base::android::AttachCurrentThread();
+ Java_InterfaceRegistrar_createInterfaceRegistryForContext(
+ env, mojo::MakeRequest(&provider).PassMessagePipe().release().value(),
+ base::android::GetApplicationContext());
+ java_interface_provider_.Bind(std::move(provider));
+
+ java_interface_provider_initialized_ = true;
+ }
+
+ return &java_interface_provider_;
+}
+#endif
+
} // namespace device
diff --git a/chromium/services/device/device_service.h b/chromium/services/device/device_service.h
index 630b928af7b..cd38c236003 100644
--- a/chromium/services/device/device_service.h
+++ b/chromium/services/device/device_service.h
@@ -6,50 +6,151 @@
#define SERVICES_DEVICE_DEVICE_SERVICE_H_
#include "base/memory/ref_counted.h"
+#include "device/battery/battery_monitor.mojom.h"
+#include "device/generic_sensor/public/interfaces/sensor_provider.mojom.h"
+#include "device/screen_orientation/public/interfaces/screen_orientation.mojom.h"
+#include "device/sensors/public/interfaces/light.mojom.h"
+#include "device/sensors/public/interfaces/motion.mojom.h"
+#include "device/sensors/public/interfaces/orientation.mojom.h"
+#include "device/vibration/vibration_manager.mojom.h"
+#include "device/wake_lock/public/interfaces/wake_lock_context_provider.mojom.h"
+#include "device/wake_lock/wake_lock_service_context.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/device/public/interfaces/fingerprint.mojom.h"
#include "services/device/public/interfaces/power_monitor.mojom.h"
#include "services/device/public/interfaces/time_zone_monitor.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
+#include "services/service_manager/public/cpp/interface_provider.h"
#include "services/service_manager/public/cpp/service.h"
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace device {
+class PowerMonitorMessageBroadcaster;
class TimeZoneMonitor;
+#if defined(OS_ANDROID)
+std::unique_ptr<service_manager::Service> CreateDeviceService(
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+ const WakeLockContextCallback& wake_lock_context_callback);
+#else
std::unique_ptr<service_manager::Service> CreateDeviceService(
- scoped_refptr<base::SingleThreadTaskRunner> file_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+#endif
class DeviceService
: public service_manager::Service,
public service_manager::InterfaceFactory<mojom::Fingerprint>,
+ public service_manager::InterfaceFactory<mojom::LightSensor>,
+ public service_manager::InterfaceFactory<mojom::MotionSensor>,
+ public service_manager::InterfaceFactory<mojom::OrientationSensor>,
+ public service_manager::InterfaceFactory<
+ mojom::OrientationAbsoluteSensor>,
+#if !defined(OS_ANDROID)
+ // On Android the Device Service provides BatteryMonitor via Java.
+ public service_manager::InterfaceFactory<mojom::BatteryMonitor>,
+ // On Android the Device Service provides VibrationManager via Java.
+ public service_manager::InterfaceFactory<mojom::VibrationManager>,
+#endif
public service_manager::InterfaceFactory<mojom::PowerMonitor>,
- public service_manager::InterfaceFactory<mojom::TimeZoneMonitor> {
+ public service_manager::InterfaceFactory<
+ mojom::ScreenOrientationListener>,
+ public service_manager::InterfaceFactory<mojom::SensorProvider>,
+ public service_manager::InterfaceFactory<mojom::TimeZoneMonitor>,
+ public service_manager::InterfaceFactory<mojom::WakeLockContextProvider> {
public:
- DeviceService(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner);
+#if defined(OS_ANDROID)
+ DeviceService(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+ const WakeLockContextCallback& wake_lock_context_callback);
+#else
+ DeviceService(scoped_refptr<base::SingleThreadTaskRunner> file_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner);
+#endif
~DeviceService() override;
private:
// service_manager::Service:
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// InterfaceFactory<mojom::Fingerprint>:
void Create(const service_manager::Identity& remote_identity,
mojom::FingerprintRequest request) override;
+ // InterfaceFactory<mojom::LightSensor>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::LightSensorRequest request) override;
+
+ // InterfaceFactory<mojom::MotionSensor>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::MotionSensorRequest request) override;
+
+ // InterfaceFactory<mojom::OrientationSensor>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::OrientationSensorRequest request) override;
+
+ // InterfaceFactory<mojom::OrientationAbsolueSensor>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::OrientationAbsoluteSensorRequest request) override;
+
+#if !defined(OS_ANDROID)
+ // InterfaceFactory<mojom::BatteryMonitor>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::BatteryMonitorRequest request) override;
+ // InterfaceFactory<mojom::VibrationManager>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::VibrationManagerRequest request) override;
+#endif
+
// InterfaceFactory<mojom::PowerMonitor>:
void Create(const service_manager::Identity& remote_identity,
mojom::PowerMonitorRequest request) override;
+ // InterfaceFactory<mojom::ScreenOrientationListener>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::ScreenOrientationListenerRequest request) override;
+
+ // InterfaceFactory<mojom::SensorProvider>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::SensorProviderRequest request) override;
+
// InterfaceFactory<mojom::TimeZoneMonitor>:
void Create(const service_manager::Identity& remote_identity,
mojom::TimeZoneMonitorRequest request) override;
- std::unique_ptr<device::TimeZoneMonitor> time_zone_monitor_;
+ // InterfaceFactory<mojom::WakeLockContextProvider>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::WakeLockContextProviderRequest request) override;
+
+ std::unique_ptr<PowerMonitorMessageBroadcaster>
+ power_monitor_message_broadcaster_;
+ std::unique_ptr<TimeZoneMonitor> time_zone_monitor_;
+#if defined(OS_ANDROID)
+ // Binds |java_interface_provider_| to an interface registry that exposes
+ // factories for the interfaces that are provided via Java on Android.
+ service_manager::InterfaceProvider* GetJavaInterfaceProvider();
+
+ // InterfaceProvider that is bound to the Java-side interface registry.
+ service_manager::InterfaceProvider java_interface_provider_;
+
+ bool java_interface_provider_initialized_;
+#endif
scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+
+ WakeLockContextCallback wake_lock_context_callback_;
+
+ service_manager::BinderRegistry registry_;
DISALLOW_COPY_AND_ASSIGN(DeviceService);
};
diff --git a/chromium/services/device/device_service_test_base.cc b/chromium/services/device/device_service_test_base.cc
new file mode 100644
index 00000000000..595f669d9ce
--- /dev/null
+++ b/chromium/services/device/device_service_test_base.cc
@@ -0,0 +1,95 @@
+// 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/device/device_service_test_base.h"
+
+#include <memory>
+
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/device/device_service.h"
+#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/interface_factory.h"
+#include "services/service_manager/public/cpp/service_context.h"
+#include "services/service_manager/public/interfaces/service_factory.mojom.h"
+
+namespace device {
+
+namespace {
+
+const char kTestServiceName[] = "device_unittests";
+
+// The test service responsible to package Device Service.
+class ServiceTestClient : public service_manager::test::ServiceTestClient,
+ public service_manager::mojom::ServiceFactory,
+ public service_manager::InterfaceFactory<
+ service_manager::mojom::ServiceFactory> {
+ public:
+ explicit ServiceTestClient(service_manager::test::ServiceTest* test)
+ : service_manager::test::ServiceTestClient(test),
+ io_thread_("DeviceServiceTestIOThread"),
+ file_thread_("DeviceServiceTestFileThread") {
+ registry_.AddInterface<service_manager::mojom::ServiceFactory>(this);
+ }
+ ~ServiceTestClient() override {}
+
+ protected:
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
+ }
+
+ void CreateService(service_manager::mojom::ServiceRequest request,
+ const std::string& name) override {
+ if (name == device::mojom::kServiceName) {
+ io_thread_.Start();
+ file_thread_.Start();
+#if defined(OS_ANDROID)
+ device_service_context_.reset(new service_manager::ServiceContext(
+ CreateDeviceService(file_thread_.task_runner(),
+ io_thread_.task_runner(),
+ wake_lock_context_callback_),
+ std::move(request)));
+#else
+ device_service_context_.reset(new service_manager::ServiceContext(
+ CreateDeviceService(file_thread_.task_runner(),
+ io_thread_.task_runner()),
+ std::move(request)));
+#endif
+ }
+ }
+
+ void Create(const service_manager::Identity& remote_identity,
+ service_manager::mojom::ServiceFactoryRequest request) override {
+ service_factory_bindings_.AddBinding(this, std::move(request));
+ }
+
+ private:
+ base::Thread io_thread_;
+ base::Thread file_thread_;
+ service_manager::BinderRegistry registry_;
+ mojo::BindingSet<service_manager::mojom::ServiceFactory>
+ service_factory_bindings_;
+ std::unique_ptr<service_manager::ServiceContext> device_service_context_;
+
+ WakeLockContextCallback wake_lock_context_callback_;
+};
+
+} // namespace
+
+DeviceServiceTestBase::DeviceServiceTestBase()
+ : ServiceTest(kTestServiceName) {}
+
+DeviceServiceTestBase::~DeviceServiceTestBase() {}
+
+std::unique_ptr<service_manager::Service>
+DeviceServiceTestBase::CreateService() {
+ return base::MakeUnique<ServiceTestClient>(this);
+}
+
+} // namespace device
diff --git a/chromium/services/device/device_service_test_base.h b/chromium/services/device/device_service_test_base.h
new file mode 100644
index 00000000000..4df7d1ea454
--- /dev/null
+++ b/chromium/services/device/device_service_test_base.h
@@ -0,0 +1,28 @@
+// 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_DEVICE_DEVICE_SERVICE_TEST_BASE_H_
+#define SERVICES_DEVICE_DEVICE_SERVICE_TEST_BASE_H_
+
+#include "base/macros.h"
+#include "services/service_manager/public/cpp/service_test.h"
+
+namespace device {
+
+// Base class responsible to setup Device Service for test.
+class DeviceServiceTestBase : public service_manager::test::ServiceTest {
+ public:
+ DeviceServiceTestBase();
+ ~DeviceServiceTestBase() override;
+
+ private:
+ // service_manager::test::ServiceTest:
+ std::unique_ptr<service_manager::Service> CreateService() override;
+
+ DISALLOW_COPY_AND_ASSIGN(DeviceServiceTestBase);
+};
+
+} // namespace device
+
+#endif // SERVICES_DEVICE_DEVICE_SERVICE_TEST_BASE_H_
diff --git a/chromium/services/device/manifest.json b/chromium/services/device/manifest.json
index 0ec13e56105..6b7a1b0ddfd 100644
--- a/chromium/services/device/manifest.json
+++ b/chromium/services/device/manifest.json
@@ -4,9 +4,20 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
+ "device:battery_monitor": [ "device::mojom::BatteryMonitor" ],
+ "device:fingerprint": [ "device::mojom::Fingerprint" ],
+ "device:generic_sensor": [ "device::mojom::SensorProvider" ],
"device:power_monitor": [ "device::mojom::PowerMonitor" ],
+ "device:screen_orientation": [ "device::mojom::ScreenOrientationListener" ],
+ "device:sensors": [
+ "device::mojom::LightSensor",
+ "device::mojom::MotionSensor",
+ "device::mojom::OrientationAbsoluteSensor",
+ "device::mojom::OrientationSensor"
+ ],
"device:time_zone_monitor": [ "device::mojom::TimeZoneMonitor" ],
- "device:fingerprint": [ "device::mojom::Fingerprint" ]
+ "device:vibration": [ "device::mojom::VibrationManager" ],
+ "device:wake_lock": [ "device::mojom::WakeLockContextProvider" ]
},
"requires": {
"service_manager": [ "service_manager:all_users" ]
diff --git a/chromium/services/device/power_monitor/OWNERS b/chromium/services/device/power_monitor/OWNERS
index 92c60edbe66..887a99be3cb 100644
--- a/chromium/services/device/power_monitor/OWNERS
+++ b/chromium/services/device/power_monitor/OWNERS
@@ -1,4 +1,2 @@
bajones@chromium.org
blundell@chromium.org
-
-# COMPONENT: Manifest
diff --git a/chromium/services/device/power_monitor/power_monitor_message_broadcaster.cc b/chromium/services/device/power_monitor/power_monitor_message_broadcaster.cc
index 8361caea812..efc26420c8b 100644
--- a/chromium/services/device/power_monitor/power_monitor_message_broadcaster.cc
+++ b/chromium/services/device/power_monitor/power_monitor_message_broadcaster.cc
@@ -23,37 +23,35 @@ PowerMonitorMessageBroadcaster::~PowerMonitorMessageBroadcaster() {
}
// static
-void PowerMonitorMessageBroadcaster::Create(
+void PowerMonitorMessageBroadcaster::Bind(
device::mojom::PowerMonitorRequest request) {
- mojo::MakeStrongBinding(base::MakeUnique<PowerMonitorMessageBroadcaster>(),
- std::move(request));
+ bindings_.AddBinding(this, std::move(request));
}
-void PowerMonitorMessageBroadcaster::SetClient(
+void PowerMonitorMessageBroadcaster::AddClient(
device::mojom::PowerMonitorClientPtr power_monitor_client) {
- power_monitor_client_ = std::move(power_monitor_client);
+ clients_.AddPtr(std::move(power_monitor_client));
base::PowerMonitor* power_monitor = base::PowerMonitor::Get();
// Unit tests does not initialize the PowerMonitor.
- if (power_monitor)
+ if (power_monitor) {
OnPowerStateChange(power_monitor->IsOnBatteryPower());
+ }
}
void PowerMonitorMessageBroadcaster::OnPowerStateChange(bool on_battery_power) {
- if (power_monitor_client_) {
- power_monitor_client_->PowerStateChange(on_battery_power);
- }
+ clients_.ForAllPtrs([&on_battery_power](mojom::PowerMonitorClient* client) {
+ client->PowerStateChange(on_battery_power);
+ });
}
void PowerMonitorMessageBroadcaster::OnSuspend() {
- if (power_monitor_client_) {
- power_monitor_client_->Suspend();
- }
+ clients_.ForAllPtrs(
+ [](mojom::PowerMonitorClient* client) { client->Suspend(); });
}
void PowerMonitorMessageBroadcaster::OnResume() {
- if (power_monitor_client_) {
- power_monitor_client_->Resume();
- }
+ clients_.ForAllPtrs(
+ [](mojom::PowerMonitorClient* client) { client->Resume(); });
}
} // namespace device
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 41ea658e2ee..0b42dfe1b3c 100644
--- a/chromium/services/device/power_monitor/power_monitor_message_broadcaster.h
+++ b/chromium/services/device/power_monitor/power_monitor_message_broadcaster.h
@@ -7,6 +7,8 @@
#include "base/macros.h"
#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"
namespace device {
@@ -16,13 +18,13 @@ namespace device {
class PowerMonitorMessageBroadcaster : public base::PowerObserver,
public device::mojom::PowerMonitor {
public:
- explicit PowerMonitorMessageBroadcaster();
+ PowerMonitorMessageBroadcaster();
~PowerMonitorMessageBroadcaster() override;
- static void Create(device::mojom::PowerMonitorRequest request);
+ void Bind(device::mojom::PowerMonitorRequest request);
// device::mojom::PowerMonitor:
- void SetClient(
+ void AddClient(
device::mojom::PowerMonitorClientPtr power_monitor_client) override;
// base::PowerObserver:
@@ -31,7 +33,8 @@ class PowerMonitorMessageBroadcaster : public base::PowerObserver,
void OnResume() override;
private:
- device::mojom::PowerMonitorClientPtr power_monitor_client_;
+ mojo::BindingSet<device::mojom::PowerMonitor> bindings_;
+ mojo::InterfacePtrSet<device::mojom::PowerMonitorClient> clients_;
DISALLOW_COPY_AND_ASSIGN(PowerMonitorMessageBroadcaster);
};
diff --git a/chromium/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc b/chromium/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc
index bde8cc3bc41..fddd208c4e7 100644
--- a/chromium/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc
+++ b/chromium/services/device/power_monitor/power_monitor_message_broadcaster_unittest.cc
@@ -66,8 +66,8 @@ TEST_F(PowerMonitorMessageBroadcasterTest, PowerMessageBroadcast) {
FakePowerMonitorClient client(mojo::MakeRequest(&proxy));
PowerMonitorMessageBroadcaster broadcaster;
- // Calling SetClient should invoke a power state change.
- broadcaster.SetClient(std::move(proxy));
+ // Calling AddClient should invoke a power state change.
+ broadcaster.AddClient(std::move(proxy));
base::RunLoop().RunUntilIdle();
EXPECT_EQ(client.power_state_changes(), 1);
diff --git a/chromium/services/device/public/cpp/BUILD.gn b/chromium/services/device/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..e9ebe278f99
--- /dev/null
+++ b/chromium/services/device/public/cpp/BUILD.gn
@@ -0,0 +1,17 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+
+source_set("device_features") {
+ public = [
+ "device_features.h",
+ ]
+ sources = [
+ "device_features.cc",
+ ]
+ public_deps = [
+ "//base",
+ ]
+}
diff --git a/chromium/services/device/public/cpp/device_features.cc b/chromium/services/device/public/cpp/device_features.cc
new file mode 100644
index 00000000000..ab4b9baa430
--- /dev/null
+++ b/chromium/services/device/public/cpp/device_features.cc
@@ -0,0 +1,14 @@
+// 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/device/public/cpp/device_features.h"
+
+namespace features {
+
+// Enables sensors based on Generic Sensor API:
+// https://w3c.github.io/sensors/
+const base::Feature kGenericSensor{"GenericSensor",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+} // namespace features
diff --git a/chromium/services/device/public/cpp/device_features.h b/chromium/services/device/public/cpp/device_features.h
new file mode 100644
index 00000000000..b10a16b6f0c
--- /dev/null
+++ b/chromium/services/device/public/cpp/device_features.h
@@ -0,0 +1,21 @@
+// 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.
+
+// This file defines all the public base::FeatureList features for the
+// services/device module.
+
+#ifndef SERVICES_DEVICE_PUBLIC_CPP_DEVICE_FEATURES_H_
+#define SERVICES_DEVICE_PUBLIC_CPP_DEVICE_FEATURES_H_
+
+#include "base/feature_list.h"
+
+namespace features {
+
+// The features should be documented alongside the definition of their values
+// in the .cc file.
+extern const base::Feature kGenericSensor;
+
+} // namespace features
+
+#endif // SERVICES_DEVICE_PUBLIC_CPP_DEVICE_FEATURES_H_
diff --git a/chromium/services/device/public/cpp/power_monitor/OWNERS b/chromium/services/device/public/cpp/power_monitor/OWNERS
index 92c60edbe66..887a99be3cb 100644
--- a/chromium/services/device/public/cpp/power_monitor/OWNERS
+++ b/chromium/services/device/public/cpp/power_monitor/OWNERS
@@ -1,4 +1,2 @@
bajones@chromium.org
blundell@chromium.org
-
-# COMPONENT: Manifest
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 d2b06d506f7..e3253556b39 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
@@ -7,16 +7,19 @@
#include "base/location.h"
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding.h"
+#include "services/device/public/interfaces/constants.mojom.h"
+#include "services/service_manager/public/cpp/connector.h"
namespace device {
PowerMonitorBroadcastSource::PowerMonitorBroadcastSource(
- service_manager::InterfaceProvider* interface_provider)
+ service_manager::Connector* connector)
: last_reported_battery_power_state_(false), binding_(this) {
- if (interface_provider) {
+ if (connector) {
device::mojom::PowerMonitorPtr power_monitor;
- interface_provider->GetInterface(mojo::MakeRequest(&power_monitor));
- power_monitor->SetClient(binding_.CreateInterfacePtrAndBind());
+ connector->BindInterface(device::mojom::kServiceName,
+ mojo::MakeRequest(&power_monitor));
+ power_monitor->AddClient(binding_.CreateInterfacePtrAndBind());
}
}
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 5f8f06ec379..1969aff114d 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
@@ -9,7 +9,10 @@
#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/service_manager/public/cpp/interface_provider.h"
+
+namespace service_manager {
+class Connector;
+}
namespace device {
@@ -18,8 +21,7 @@ namespace device {
class PowerMonitorBroadcastSource : public base::PowerMonitorSource,
public device::mojom::PowerMonitorClient {
public:
- explicit PowerMonitorBroadcastSource(
- service_manager::InterfaceProvider* interface_provider);
+ explicit PowerMonitorBroadcastSource(service_manager::Connector* connector);
~PowerMonitorBroadcastSource() override;
void PowerStateChange(bool on_battery_power) override;
diff --git a/chromium/services/device/public/interfaces/power_monitor.mojom b/chromium/services/device/public/interfaces/power_monitor.mojom
index ab2c287d5b3..a6d8701fb07 100644
--- a/chromium/services/device/public/interfaces/power_monitor.mojom
+++ b/chromium/services/device/public/interfaces/power_monitor.mojom
@@ -5,8 +5,8 @@
module device.mojom;
interface PowerMonitor {
- // Set client that will be notified on PowerStateChange, Suspend and Resume.
- SetClient(PowerMonitorClient client);
+ // Add a client that will be notified on PowerStateChange, Suspend and Resume.
+ AddClient(PowerMonitorClient client);
};
interface PowerMonitorClient {
diff --git a/chromium/services/device/screen_orientation/BUILD.gn b/chromium/services/device/screen_orientation/BUILD.gn
new file mode 100644
index 00000000000..6aa31af0198
--- /dev/null
+++ b/chromium/services/device/screen_orientation/BUILD.gn
@@ -0,0 +1,53 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/features.gni")
+
+if (is_android) {
+ import("//build/config/android/rules.gni") # For generate_jni().
+}
+
+source_set("screen_orientation") {
+ visibility = [ "//services/device:lib" ]
+
+ sources = [
+ "screen_orientation_listener_android.cc",
+ "screen_orientation_listener_android.h",
+ ]
+
+ deps = [
+ "//base",
+ "//mojo/public/cpp/bindings",
+ ]
+
+ public_deps = [
+ "//device/screen_orientation/public/interfaces",
+ ]
+
+ if (is_android) {
+ deps += [ ":screen_orientation_jni_headers" ]
+ }
+}
+
+if (is_android) {
+ generate_jni("screen_orientation_jni_headers") {
+ visibility = [ ":screen_orientation" ]
+ sources = [
+ "android/java/src/org/chromium/device/screen_orientation/ScreenOrientationListener.java",
+ ]
+ jni_package = "screen_orientation"
+ }
+
+ android_library("java") {
+ # Conceptually, this should be visible only to //services/device:java.
+ # However, various generated targets also need to see this target as a
+ # result of //services/device:java depending on it.
+ visibility = [ "//services/device:*" ]
+ java_files = [ "android/java/src/org/chromium/device/screen_orientation/ScreenOrientationListener.java" ]
+ deps = [
+ "//base:base_java",
+ "//ui/android:ui_java",
+ ]
+ }
+}
diff --git a/chromium/services/device/screen_orientation/DEPS b/chromium/services/device/screen_orientation/DEPS
new file mode 100644
index 00000000000..dbaf05111e0
--- /dev/null
+++ b/chromium/services/device/screen_orientation/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+jni",
+ "+mojo/public/cpp/bindings",
+]
diff --git a/chromium/services/device/screen_orientation/OWNERS b/chromium/services/device/screen_orientation/OWNERS
new file mode 100644
index 00000000000..33ac3a28754
--- /dev/null
+++ b/chromium/services/device/screen_orientation/OWNERS
@@ -0,0 +1,2 @@
+file://device/screen_orientation/OWNERS
+
diff --git a/chromium/services/device/screen_orientation/android/java/DEPS b/chromium/services/device/screen_orientation/android/java/DEPS
new file mode 100644
index 00000000000..05f395ef21d
--- /dev/null
+++ b/chromium/services/device/screen_orientation/android/java/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/android/java",
+]
diff --git a/chromium/services/device/screen_orientation/screen_orientation_listener_android.cc b/chromium/services/device/screen_orientation/screen_orientation_listener_android.cc
new file mode 100644
index 00000000000..0c863d8b699
--- /dev/null
+++ b/chromium/services/device/screen_orientation/screen_orientation_listener_android.cc
@@ -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.
+
+#include "services/device/screen_orientation/screen_orientation_listener_android.h"
+
+#include "base/android/jni_android.h"
+#include "base/message_loop/message_loop.h"
+#include "jni/ScreenOrientationListener_jni.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace device {
+
+// static
+void ScreenOrientationListenerAndroid::Create(
+ mojom::ScreenOrientationListenerRequest request) {
+ mojo::MakeStrongBinding(
+ base::WrapUnique(new ScreenOrientationListenerAndroid()),
+ std::move(request));
+}
+
+ScreenOrientationListenerAndroid::ScreenOrientationListenerAndroid()
+ : listeners_count_(0) {}
+
+ScreenOrientationListenerAndroid::~ScreenOrientationListenerAndroid() {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ if (listeners_count_ > 0) {
+ Java_ScreenOrientationListener_startAccurateListening(
+ base::android::AttachCurrentThread());
+ }
+}
+
+void ScreenOrientationListenerAndroid::Start() {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ ++listeners_count_;
+ if (listeners_count_ == 1) {
+ // Ask the ScreenOrientationListener (Java) to start accurately listening to
+ // the screen orientation. It keep track of the number of start request if
+ // it is already running an accurate listening.
+ Java_ScreenOrientationListener_startAccurateListening(
+ base::android::AttachCurrentThread());
+ }
+}
+
+void ScreenOrientationListenerAndroid::Stop() {
+ DCHECK(base::MessageLoopForIO::IsCurrent());
+ DCHECK(listeners_count_ > 0);
+ --listeners_count_;
+ if (listeners_count_ == 0) {
+ // Ask the ScreenOrientationListener (Java) to stop accurately listening to
+ // the screen orientation. It will actually stop only if the number of stop
+ // requests matches the number of start requests.
+ Java_ScreenOrientationListener_stopAccurateListening(
+ base::android::AttachCurrentThread());
+ }
+}
+
+} // namespace device
diff --git a/chromium/services/device/screen_orientation/screen_orientation_listener_android.h b/chromium/services/device/screen_orientation/screen_orientation_listener_android.h
new file mode 100644
index 00000000000..4df873a4346
--- /dev/null
+++ b/chromium/services/device/screen_orientation/screen_orientation_listener_android.h
@@ -0,0 +1,34 @@
+// 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_DEVICE_SCREEN_ORIENTATION_SCREEN_ORIENTATION_LISTENER_ANDROID_H_
+#define SERVICES_DEVICE_SCREEN_ORIENTATION_SCREEN_ORIENTATION_LISTENER_ANDROID_H_
+
+#include "base/macros.h"
+#include "device/screen_orientation/public/interfaces/screen_orientation.mojom.h"
+
+namespace device {
+
+class ScreenOrientationListenerAndroid
+ : public mojom::ScreenOrientationListener {
+ public:
+ static void Create(mojom::ScreenOrientationListenerRequest request);
+
+ ~ScreenOrientationListenerAndroid() override;
+
+ private:
+ ScreenOrientationListenerAndroid();
+
+ // mojom::ScreenOrientationListener:
+ void Start() override;
+ void Stop() override;
+
+ int listeners_count_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenOrientationListenerAndroid);
+};
+
+} // namespace device
+
+#endif // SERVICES_DEVICE_SCREEN_ORIENTATION_SCREEN_ORIENTATION_LISTENER_ANDROID_H_
diff --git a/chromium/services/device/time_zone_monitor/BUILD.gn b/chromium/services/device/time_zone_monitor/BUILD.gn
index ecef1fc39f5..14cba6d90be 100644
--- a/chromium/services/device/time_zone_monitor/BUILD.gn
+++ b/chromium/services/device/time_zone_monitor/BUILD.gn
@@ -61,4 +61,15 @@ if (is_android) {
]
jni_package = "time_zone_monitor"
}
+
+ android_library("java") {
+ # Conceptually, this should be visible only to //services/device:java.
+ # However, various generated targets also need to see this target as a
+ # result of //services/device:java depending on it.
+ visibility = [ "//services/device:*" ]
+ java_files = [ "android/java/src/org/chromium/device/time_zone_monitor/TimeZoneMonitor.java" ]
+ deps = [
+ "//base:base_java",
+ ]
+ }
}
diff --git a/chromium/services/device/unittest_manifest.json b/chromium/services/device/unittest_manifest.json
new file mode 100644
index 00000000000..c743b7b94c4
--- /dev/null
+++ b/chromium/services/device/unittest_manifest.json
@@ -0,0 +1,16 @@
+{
+ "name": "device_unittests",
+ "display_name": "Device Service Unittests",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "service_manager:service_factory": [
+ "service_manager::mojom::ServiceFactory"
+ ]
+ },
+ "requires": {
+ "device": [ "device:vibration" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/device/vibration/vibration_manager_impl_unittest.cc b/chromium/services/device/vibration/vibration_manager_impl_unittest.cc
new file mode 100644
index 00000000000..d54a771cff3
--- /dev/null
+++ b/chromium/services/device/vibration/vibration_manager_impl_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 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 "base/run_loop.h"
+#include "device/vibration/vibration_manager.mojom.h"
+#include "services/device/device_service_test_base.h"
+#include "services/device/public/interfaces/constants.mojom.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/jni_android.h"
+#include "jni/VibrationManagerImpl_jni.h"
+#else
+#include "device/vibration/vibration_manager_impl.h"
+#endif
+
+namespace device {
+
+namespace {
+
+class VibrationManagerImplTest : public DeviceServiceTestBase {
+ public:
+ VibrationManagerImplTest() = default;
+ ~VibrationManagerImplTest() override = default;
+
+ protected:
+ void SetUp() override {
+ DeviceServiceTestBase::SetUp();
+
+ connector()->BindInterface(mojom::kServiceName, &vibration_manager_);
+ }
+
+ void Vibrate(int64_t milliseconds) {
+ base::RunLoop run_loop;
+ vibration_manager_->Vibrate(milliseconds, run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ void Cancel() {
+ base::RunLoop run_loop;
+ vibration_manager_->Cancel(run_loop.QuitClosure());
+ run_loop.Run();
+ }
+
+ int64_t GetVibrationMilliSeconds() {
+#if defined(OS_ANDROID)
+ return Java_VibrationManagerImpl_getVibrateMilliSecondsForTesting(
+ base::android::AttachCurrentThread());
+#else
+ return VibrationManagerImpl::milli_seconds_for_testing_;
+#endif
+ }
+
+ bool GetVibrationCancelled() {
+#if defined(OS_ANDROID)
+ return Java_VibrationManagerImpl_getVibrateCancelledForTesting(
+ base::android::AttachCurrentThread());
+#else
+ return VibrationManagerImpl::cancelled_for_testing_;
+#endif
+ }
+
+ private:
+ mojom::VibrationManagerPtr vibration_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(VibrationManagerImplTest);
+};
+
+TEST_F(VibrationManagerImplTest, VibrateThenCancel) {
+ EXPECT_NE(10000, GetVibrationMilliSeconds());
+ Vibrate(10000);
+ EXPECT_EQ(10000, GetVibrationMilliSeconds());
+
+ EXPECT_FALSE(GetVibrationCancelled());
+ Cancel();
+ EXPECT_TRUE(GetVibrationCancelled());
+}
+
+} // namespace
+
+} // namespace device
diff --git a/chromium/services/file/file_service.cc b/chromium/services/file/file_service.cc
index a8b7eee7128..219469215cd 100644
--- a/chromium/services/file/file_service.cc
+++ b/chromium/services/file/file_service.cc
@@ -12,8 +12,6 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/file/file_system.h"
#include "services/file/user_id_map.h"
-#include "services/service_manager/public/cpp/connection.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
namespace file {
@@ -85,7 +83,10 @@ FileService::FileService(
scoped_refptr<base::SingleThreadTaskRunner> file_service_runner,
scoped_refptr<base::SingleThreadTaskRunner> leveldb_service_runner)
: file_service_runner_(std::move(file_service_runner)),
- leveldb_service_runner_(std::move(leveldb_service_runner)) {}
+ leveldb_service_runner_(std::move(leveldb_service_runner)) {
+ registry_.AddInterface<leveldb::mojom::LevelDBService>(this);
+ registry_.AddInterface<mojom::FileSystem>(this);
+}
FileService::~FileService() {
file_service_runner_->DeleteSoon(FROM_HERE, file_system_objects_.release());
@@ -99,11 +100,12 @@ void FileService::OnStart() {
new FileService::LevelDBServiceObjects(file_service_runner_));
}
-bool FileService::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface<leveldb::mojom::LevelDBService>(this);
- registry->AddInterface<mojom::FileSystem>(this);
- return true;
+void FileService::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
void FileService::Create(const service_manager::Identity& remote_identity,
diff --git a/chromium/services/file/file_service.h b/chromium/services/file/file_service.h
index 357aa88dc63..c91490a69f6 100644
--- a/chromium/services/file/file_service.h
+++ b/chromium/services/file/file_service.h
@@ -11,6 +11,7 @@
#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/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
@@ -33,8 +34,9 @@ class FileService
private:
// |Service| override:
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// |InterfaceFactory<mojom::FileSystem>| implementation:
void Create(const service_manager::Identity& remote_identity,
@@ -57,6 +59,8 @@ class FileService
class LevelDBServiceObjects;
std::unique_ptr<LevelDBServiceObjects> leveldb_objects_;
+ service_manager::BinderRegistry registry_;
+
DISALLOW_COPY_AND_ASSIGN(FileService);
};
diff --git a/chromium/services/file/file_system.cc b/chromium/services/file/file_system.cc
index e022d4c2a7f..d4ff32f4166 100644
--- a/chromium/services/file/file_system.cc
+++ b/chromium/services/file/file_system.cc
@@ -14,7 +14,6 @@
#include "components/filesystem/lock_table.h"
#include "components/filesystem/public/interfaces/types.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/connection.h"
namespace file {
diff --git a/chromium/services/file/user_id_map.cc b/chromium/services/file/user_id_map.cc
index 1a6068b11fd..36b96817476 100644
--- a/chromium/services/file/user_id_map.cc
+++ b/chromium/services/file/user_id_map.cc
@@ -11,7 +11,7 @@
namespace file {
namespace {
-base::LazyInstance<std::map<std::string, base::FilePath>>
+base::LazyInstance<std::map<std::string, base::FilePath>>::DestructorAtExit
g_user_id_to_data_dir = LAZY_INSTANCE_INITIALIZER;
} // namespace
diff --git a/chromium/services/identity/BUILD.gn b/chromium/services/identity/BUILD.gn
new file mode 100644
index 00000000000..02a59b9203e
--- /dev/null
+++ b/chromium/services/identity/BUILD.gn
@@ -0,0 +1,29 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+
+source_set("lib") {
+ sources = [
+ "identity_manager.cc",
+ "identity_manager.h",
+ "identity_service.cc",
+ "identity_service.h",
+ ]
+
+ deps = [
+ "//base",
+ "//components/signin/core/account_id",
+ "//components/signin/core/browser",
+ "//services/identity/public/interfaces",
+ "//services/service_manager/public/cpp",
+ "//services/service_manager/public/interfaces",
+ ]
+}
+
+service_manifest("manifest") {
+ name = "identity"
+ source = "manifest.json"
+}
diff --git a/chromium/services/identity/DEPS b/chromium/services/identity/DEPS
new file mode 100644
index 00000000000..16041b02fef
--- /dev/null
+++ b/chromium/services/identity/DEPS
@@ -0,0 +1,6 @@
+include_rules = [
+ "+components/signin/core/account_id",
+ "+components/signin/core/browser/account_info.h",
+ "+components/signin/core/browser/signin_manager_base.h",
+ "+components/signin/public",
+]
diff --git a/chromium/services/identity/OWNERS b/chromium/services/identity/OWNERS
new file mode 100644
index 00000000000..2654e5303c7
--- /dev/null
+++ b/chromium/services/identity/OWNERS
@@ -0,0 +1,2 @@
+blundell@chromium.org
+msarda@chromium.org
diff --git a/chromium/services/identity/README.md b/chromium/services/identity/README.md
new file mode 100644
index 00000000000..59356b9397b
--- /dev/null
+++ b/chromium/services/identity/README.md
@@ -0,0 +1,8 @@
+The Identity Service maintains and provides access to the user's signed-in
+identities with Google.
+
+This service is currently in development. The design doc is here:
+
+https://docs.google.com/document/d/1EPLEJTZewjiShBemNP5Zyk3b_9sgdbrZlXn7j1fubW0
+
+The tracking bug is https://crbug.com/654990.
diff --git a/chromium/services/identity/identity_manager.cc b/chromium/services/identity/identity_manager.cc
new file mode 100644
index 00000000000..8ea9d7250cf
--- /dev/null
+++ b/chromium/services/identity/identity_manager.cc
@@ -0,0 +1,39 @@
+// 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/identity/identity_manager.h"
+
+#include "components/signin/core/account_id/account_id.h"
+#include "components/signin/core/browser/account_info.h"
+#include "components/signin/core/browser/signin_manager_base.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace identity {
+
+// static
+void IdentityManager::Create(mojom::IdentityManagerRequest request,
+ SigninManagerBase* signin_manager) {
+ mojo::MakeStrongBinding(base::MakeUnique<IdentityManager>(signin_manager),
+ std::move(request));
+}
+
+IdentityManager::IdentityManager(SigninManagerBase* signin_manager)
+ : signin_manager_(signin_manager) {}
+
+IdentityManager::~IdentityManager() {}
+
+void IdentityManager::GetPrimaryAccountId(
+ const GetPrimaryAccountIdCallback& callback) {
+ AccountId account_id = EmptyAccountId();
+
+ if (signin_manager_->IsAuthenticated()) {
+ AccountInfo account_info = signin_manager_->GetAuthenticatedAccountInfo();
+ account_id =
+ AccountId::FromUserEmailGaiaId(account_info.email, account_info.gaia);
+ }
+
+ callback.Run(account_id);
+}
+
+} // namespace identity
diff --git a/chromium/services/identity/identity_manager.h b/chromium/services/identity/identity_manager.h
new file mode 100644
index 00000000000..f024bf5b1a1
--- /dev/null
+++ b/chromium/services/identity/identity_manager.h
@@ -0,0 +1,32 @@
+// 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_IDENTITY_IDENTITY_MANAGER_H_
+#define SERVICES_IDENTITY_IDENTITY_MANAGER_H_
+
+#include "services/identity/public/interfaces/identity_manager.mojom.h"
+
+class SigninManagerBase;
+
+namespace identity {
+
+class IdentityManager : public mojom::IdentityManager {
+ public:
+ static void Create(mojom::IdentityManagerRequest request,
+ SigninManagerBase* signin_manager);
+
+ IdentityManager(SigninManagerBase* signin_manager);
+ ~IdentityManager() override;
+
+ private:
+ // mojom::IdentityManager:
+ void GetPrimaryAccountId(
+ const GetPrimaryAccountIdCallback& callback) override;
+
+ SigninManagerBase* signin_manager_;
+};
+
+} // namespace identity
+
+#endif // SERVICES_IDENTITY_IDENTITY_MANAGER_H_
diff --git a/chromium/services/identity/identity_service.cc b/chromium/services/identity/identity_service.cc
new file mode 100644
index 00000000000..dfdb742553d
--- /dev/null
+++ b/chromium/services/identity/identity_service.cc
@@ -0,0 +1,34 @@
+// 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/identity/identity_service.h"
+
+#include "services/identity/identity_manager.h"
+#include "services/service_manager/public/cpp/service_context.h"
+
+namespace identity {
+
+IdentityService::IdentityService(SigninManagerBase* signin_manager)
+ : signin_manager_(signin_manager) {
+ registry_.AddInterface<mojom::IdentityManager>(this);
+}
+
+IdentityService::~IdentityService() {}
+
+void IdentityService::OnStart() {}
+
+void IdentityService::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
+}
+
+void IdentityService::Create(const service_manager::Identity& remote_identity,
+ mojom::IdentityManagerRequest request) {
+ IdentityManager::Create(std::move(request), signin_manager_);
+}
+
+} // namespace identity
diff --git a/chromium/services/identity/identity_service.h b/chromium/services/identity/identity_service.h
new file mode 100644
index 00000000000..4d1192fdb4d
--- /dev/null
+++ b/chromium/services/identity/identity_service.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_IDENTITY_IDENTITY_SERVICE_H_
+#define SERVICES_IDENTITY_IDENTITY_SERVICE_H_
+
+#include "services/identity/public/interfaces/identity_manager.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/interface_factory.h"
+#include "services/service_manager/public/cpp/service.h"
+
+class SigninManagerBase;
+
+namespace identity {
+
+class IdentityService
+ : public service_manager::Service,
+ public service_manager::InterfaceFactory<mojom::IdentityManager> {
+ public:
+ IdentityService(SigninManagerBase* signin_manager);
+ ~IdentityService() override;
+
+ private:
+ // |Service| override:
+ void OnStart() override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
+
+ // InterfaceFactory<mojom::IdentityManager>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::IdentityManagerRequest request) override;
+
+ SigninManagerBase* signin_manager_;
+
+ service_manager::BinderRegistry registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(IdentityService);
+};
+
+} // namespace identity
+
+#endif // SERVICES_IDENTITY_IDENTITY_SERVICE_H_
diff --git a/chromium/services/identity/manifest.json b/chromium/services/identity/manifest.json
new file mode 100644
index 00000000000..0ebd6f8e5c9
--- /dev/null
+++ b/chromium/services/identity/manifest.json
@@ -0,0 +1,11 @@
+{
+ "name": "identity",
+ "display_name": "Identity Service",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "identity_manager" : [ "identity::mojom::IdentityManager" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/identity/public/interfaces/BUILD.gn b/chromium/services/identity/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..f2e15ffe96b
--- /dev/null
+++ b/chromium/services/identity/public/interfaces/BUILD.gn
@@ -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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("interfaces") {
+ sources = [
+ "identity_manager.mojom",
+ ]
+
+ public_deps = [
+ ":constants",
+ "//components/signin/public/interfaces",
+ ]
+}
+
+mojom("constants") {
+ sources = [
+ "constants.mojom",
+ ]
+}
diff --git a/chromium/services/identity/public/interfaces/OWNERS b/chromium/services/identity/public/interfaces/OWNERS
new file mode 100644
index 00000000000..08850f42120
--- /dev/null
+++ b/chromium/services/identity/public/interfaces/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/identity/public/interfaces/constants.mojom b/chromium/services/identity/public/interfaces/constants.mojom
new file mode 100644
index 00000000000..e4fbfce6b3d
--- /dev/null
+++ b/chromium/services/identity/public/interfaces/constants.mojom
@@ -0,0 +1,7 @@
+// 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 identity.mojom;
+
+const string kServiceName = "identity";
diff --git a/chromium/services/identity/public/interfaces/identity_manager.mojom b/chromium/services/identity/public/interfaces/identity_manager.mojom
new file mode 100644
index 00000000000..756f0c38b9a
--- /dev/null
+++ b/chromium/services/identity/public/interfaces/identity_manager.mojom
@@ -0,0 +1,17 @@
+// 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 identity.mojom;
+
+// TODO(blundell): Move account_id.mojom to
+// //services/identity/public/interfaces.
+import "components/signin/public/interfaces/account_id.mojom";
+
+// Gives access to information about the user's Google accounts.
+interface IdentityManager {
+ // Returns the AccountId for the Google account that serves as the user's
+ // primary account, or null if the user has no primary account (e.g., if they
+ // are not signed in).
+ GetPrimaryAccountId() => (signin.mojom.AccountId? account_id);
+};
diff --git a/chromium/services/image_decoder/README.md b/chromium/services/image_decoder/README.md
deleted file mode 100644
index 8b983626277..00000000000
--- a/chromium/services/image_decoder/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-The image_decoder service exists to facilitate safe image decoding within an
-isolated sandboxed process.
-
diff --git a/chromium/services/image_decoder/image_decoder_service.cc b/chromium/services/image_decoder/image_decoder_service.cc
deleted file mode 100644
index 4ad2a0b0f5a..00000000000
--- a/chromium/services/image_decoder/image_decoder_service.cc
+++ /dev/null
@@ -1,79 +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/image_decoder/image_decoder_service.h"
-
-#include "base/macros.h"
-#include "base/memory/ptr_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "base/time/time.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/image_decoder/image_decoder_impl.h"
-#include "services/image_decoder/public/interfaces/image_decoder.mojom.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
-#include "services/service_manager/public/cpp/service_context.h"
-
-namespace image_decoder {
-
-namespace {
-
-void OnConnectionLost(std::unique_ptr<service_manager::ServiceContextRef> ref) {
- // No-op. This merely takes ownership of |ref| so it can be destroyed when
- // this function is invoked.
-}
-
-void OnImageDecoderRequest(
- service_manager::ServiceContextRefFactory* ref_factory,
- mojom::ImageDecoderRequest request) {
- mojo::MakeStrongBinding(
- base::MakeUnique<ImageDecoderImpl>(ref_factory->CreateRef()),
- std::move(request));
-}
-
-} // namespace
-
-ImageDecoderService::ImageDecoderService() : weak_factory_(this) {}
-
-ImageDecoderService::~ImageDecoderService() = default;
-
-// static
-std::unique_ptr<service_manager::Service> ImageDecoderService::Create() {
- return base::MakeUnique<ImageDecoderService>();
-}
-
-void ImageDecoderService::OnStart() {
- ref_factory_.reset(new service_manager::ServiceContextRefFactory(
- base::Bind(&ImageDecoderService::MaybeRequestQuitDelayed,
- base::Unretained(this))));
-}
-
-bool ImageDecoderService::OnConnect(
- const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- // Add a reference to the service and tie it to the lifetime of the
- // InterfaceRegistry's connection.
- std::unique_ptr<service_manager::ServiceContextRef> connection_ref =
- ref_factory_->CreateRef();
- registry->AddConnectionLostClosure(
- base::Bind(&OnConnectionLost, base::Passed(&connection_ref)));
- registry->AddInterface(
- base::Bind(&OnImageDecoderRequest, ref_factory_.get()));
- return true;
-}
-
-void ImageDecoderService::MaybeRequestQuitDelayed() {
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ImageDecoderService::MaybeRequestQuit,
- weak_factory_.GetWeakPtr()),
- base::TimeDelta::FromSeconds(5));
-}
-
-void ImageDecoderService::MaybeRequestQuit() {
- DCHECK(ref_factory_);
- if (ref_factory_->HasNoRefs())
- context()->RequestQuit();
-}
-
-} // namespace image_decoder
diff --git a/chromium/services/image_decoder/image_decoder_service.h b/chromium/services/image_decoder/image_decoder_service.h
deleted file mode 100644
index a41006e053d..00000000000
--- a/chromium/services/image_decoder/image_decoder_service.h
+++ /dev/null
@@ -1,43 +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_IMAGE_DECODER_IMAGE_DECODER_SERVICE_H_
-#define SERVICES_IMAGE_DECODER_IMAGE_DECODER_SERVICE_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_context_ref.h"
-
-namespace image_decoder {
-
-class ImageDecoderService : public service_manager::Service {
- public:
- ImageDecoderService();
- ~ImageDecoderService() override;
-
- // Factory function for use as an embedded service.
- static std::unique_ptr<service_manager::Service> Create();
-
- // service_manager::Service:
- void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
-
- private:
- void MaybeRequestQuitDelayed();
- void MaybeRequestQuit();
-
- std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
- base::WeakPtrFactory<ImageDecoderService> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageDecoderService);
-};
-
-} // namespace image_decoder
-
-#endif // SERVICES_IMAGE_DECODER_IMAGE_DECODER_SERVICE_H_
diff --git a/chromium/services/navigation/navigation.cc b/chromium/services/navigation/navigation.cc
index 5f929cd5a08..0e923099340 100644
--- a/chromium/services/navigation/navigation.cc
+++ b/chromium/services/navigation/navigation.cc
@@ -38,26 +38,26 @@ std::unique_ptr<service_manager::Service> CreateNavigationService() {
Navigation::Navigation()
: view_task_runner_(base::ThreadTaskRunnerHandle::Get()),
- ref_factory_(base::MessageLoop::QuitWhenIdleClosure()),
- weak_factory_(this) {
+ ref_factory_(base::MessageLoop::QuitWhenIdleClosure()) {
bindings_.set_connection_error_handler(
base::Bind(&Navigation::ViewFactoryLost, base::Unretained(this)));
+ registry_.AddInterface<mojom::ViewFactory>(this);
}
Navigation::~Navigation() {}
-bool Navigation::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- std::string remote_user_id = remote_info.identity.user_id();
+void Navigation::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ std::string remote_user_id = source_info.identity.user_id();
if (!client_user_id_.empty() && client_user_id_ != remote_user_id) {
LOG(ERROR) << "Must have a separate Navigation service instance for "
<< "different BrowserContexts.";
- return false;
+ return;
}
client_user_id_ = remote_user_id;
-
- registry->AddInterface(
- base::Bind(&Navigation::CreateViewFactory, weak_factory_.GetWeakPtr()));
- return true;
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
void Navigation::CreateView(mojom::ViewClientPtr client,
@@ -73,7 +73,8 @@ void Navigation::CreateView(mojom::ViewClientPtr client,
base::Passed(&context_ref)));
}
-void Navigation::CreateViewFactory(mojom::ViewFactoryRequest request) {
+void Navigation::Create(const service_manager::Identity& remote_identity,
+ mojom::ViewFactoryRequest request) {
bindings_.AddBinding(this, std::move(request));
refs_.insert(ref_factory_.CreateRef());
}
diff --git a/chromium/services/navigation/navigation.h b/chromium/services/navigation/navigation.h
index af242e30257..181b73f24b6 100644
--- a/chromium/services/navigation/navigation.h
+++ b/chromium/services/navigation/navigation.h
@@ -6,11 +6,11 @@
#define SERVICES_NAVIGATION_NAVIGATION_H_
#include "base/memory/ref_counted.h"
-#include "base/memory/weak_ptr.h"
#include "base/sequenced_task_runner.h"
#include "content/public/common/connection_filter.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/navigation/public/interfaces/view.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context_ref.h"
@@ -19,21 +19,27 @@ namespace navigation {
std::unique_ptr<service_manager::Service> CreateNavigationService();
-class Navigation : public service_manager::Service, public mojom::ViewFactory {
+class Navigation
+ : public service_manager::Service,
+ public mojom::ViewFactory,
+ public service_manager::InterfaceFactory<mojom::ViewFactory> {
public:
Navigation();
~Navigation() override;
private:
// service_manager::Service:
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// mojom::ViewFactory:
void CreateView(mojom::ViewClientPtr client,
mojom::ViewRequest request) override;
- void CreateViewFactory(mojom::ViewFactoryRequest request);
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::ViewFactoryRequest request) override;
+
void ViewFactoryLost();
scoped_refptr<base::SequencedTaskRunner> view_task_runner_;
@@ -43,10 +49,9 @@ class Navigation : public service_manager::Service, public mojom::ViewFactory {
service_manager::ServiceContextRefFactory ref_factory_;
std::set<std::unique_ptr<service_manager::ServiceContextRef>> refs_;
+ service_manager::BinderRegistry registry_;
mojo::BindingSet<mojom::ViewFactory> bindings_;
- base::WeakPtrFactory<Navigation> weak_factory_;
-
DISALLOW_COPY_AND_ASSIGN(Navigation);
};
diff --git a/chromium/services/navigation/navigation_unittest.cc b/chromium/services/navigation/navigation_unittest.cc
index 5dfc8adbbb0..740cc6fecc3 100644
--- a/chromium/services/navigation/navigation_unittest.cc
+++ b/chromium/services/navigation/navigation_unittest.cc
@@ -24,7 +24,7 @@ class NavigationTest : public service_manager::test::ServiceTest,
protected:
void SetUp() override {
service_manager::test::ServiceTest::SetUp();
- window_manager_connection_ = connector()->Connect("test_wm");
+ connector()->StartService("test_wm");
}
mojom::ViewClientPtr GetViewClient() {
@@ -66,7 +66,6 @@ class NavigationTest : public service_manager::test::ServiceTest,
int load_count_ = 0;
mojo::Binding<mojom::ViewClient> binding_;
base::RunLoop* loop_ = nullptr;
- std::unique_ptr<service_manager::Connection> window_manager_connection_;
DISALLOW_COPY_AND_ASSIGN(NavigationTest);
};
diff --git a/chromium/services/preferences/BUILD.gn b/chromium/services/preferences/BUILD.gn
index 8640a9194ee..12b41820c89 100644
--- a/chromium/services/preferences/BUILD.gn
+++ b/chromium/services/preferences/BUILD.gn
@@ -2,9 +2,70 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-group("tests") {
+import("//services/catalog/public/tools/catalog.gni")
+import("//services/service_manager/public/service_manifest.gni")
+import("//testing/test.gni")
+
+service_manifest("manifest") {
+ name = "preferences"
+ source = "manifest.json"
+}
+
+source_set("preferences") {
+ visibility = [
+ ":*",
+ "//services/preferences/public/cpp:service_main",
+ ]
+ deps = [
+ "//components/prefs",
+ "//services/preferences/public/cpp",
+ "//services/preferences/public/interfaces",
+ "//services/preferences/tracked",
+ "//services/service_manager/public/cpp",
+ ]
+ sources = [
+ "persistent_pref_store_factory.cc",
+ "persistent_pref_store_factory.h",
+ "persistent_pref_store_impl.cc",
+ "persistent_pref_store_impl.h",
+ "pref_store_manager_impl.cc",
+ "pref_store_manager_impl.h",
+ ]
+}
+
+source_set("tests") {
testonly = true
deps = [
+ ":preferences",
+ "//base",
+ "//base/test:test_support",
+ "//components/prefs:test_support",
+ "//mojo/public/cpp/bindings:bindings",
+ "//services/preferences/public/cpp",
+ "//services/preferences/public/cpp:service_main",
"//services/preferences/public/cpp/tests",
+ "//services/preferences/public/interfaces",
+ "//services/preferences/tracked:unit_tests",
+ "//services/service_manager/public/cpp",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+ sources = [
+ "persistent_pref_store_impl_unittest.cc",
]
+ if (!is_ios) {
+ sources += [ "pref_service_factory_unittest.cc" ]
+ deps += [ "//services/service_manager/public/cpp:service_test_support" ]
+ }
+}
+
+service_manifest("unittest_manifest") {
+ name = "prefs_unittests"
+ source = "unittest_manifest.json"
+ packaged_services = [ ":manifest" ]
+}
+
+catalog("tests_catalog") {
+ testonly = true
+ embedded_services = [ ":unittest_manifest" ]
}
diff --git a/chromium/services/preferences/DEPS b/chromium/services/preferences/DEPS
new file mode 100644
index 00000000000..eac076192dc
--- /dev/null
+++ b/chromium/services/preferences/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+components/prefs",
+]
diff --git a/chromium/services/preferences/manifest.json b/chromium/services/preferences/manifest.json
new file mode 100644
index 00000000000..40473465595
--- /dev/null
+++ b/chromium/services/preferences/manifest.json
@@ -0,0 +1,19 @@
+{
+ "name": "preferences",
+ "display_name": "Preferences",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "pref_client": [
+ "prefs::mojom::PrefStoreConnector",
+ "prefs::mojom::PrefStoreRegistry"
+ ],
+ "pref_control": [
+ "prefs::mojom::PrefServiceControl"
+ ]
+ },
+ "requires": {
+ }
+ }
+ }
+}
diff --git a/chromium/services/preferences/persistent_pref_store_factory.cc b/chromium/services/preferences/persistent_pref_store_factory.cc
new file mode 100644
index 00000000000..587ac96d182
--- /dev/null
+++ b/chromium/services/preferences/persistent_pref_store_factory.cc
@@ -0,0 +1,51 @@
+// 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/preferences/persistent_pref_store_factory.h"
+
+#include <memory>
+#include <utility>
+
+#include "components/prefs/json_pref_store.h"
+#include "components/prefs/pref_filter.h"
+#include "services/preferences/persistent_pref_store_impl.h"
+#include "services/preferences/tracked/tracked_persistent_pref_store_factory.h"
+
+namespace prefs {
+namespace {
+
+std::unique_ptr<PersistentPrefStoreImpl> CreateSimplePersistentPrefStore(
+ mojom::SimplePersistentPrefStoreConfigurationPtr config,
+ base::SequencedWorkerPool* worker_pool,
+ base::Closure on_initialized) {
+ return base::MakeUnique<PersistentPrefStoreImpl>(
+ new JsonPrefStore(config->pref_filename,
+ JsonPrefStore::GetTaskRunnerForFile(
+ config->pref_filename.DirName(), worker_pool),
+ nullptr),
+ std::move(on_initialized));
+}
+
+} // namespace
+
+std::unique_ptr<PersistentPrefStoreImpl> CreatePersistentPrefStore(
+ mojom::PersistentPrefStoreConfigurationPtr configuration,
+ base::SequencedWorkerPool* worker_pool,
+ base::Closure on_initialized) {
+ if (configuration->is_simple_configuration()) {
+ return CreateSimplePersistentPrefStore(
+ std::move(configuration->get_simple_configuration()), worker_pool,
+ std::move(on_initialized));
+ }
+ if (configuration->is_tracked_configuration()) {
+ return base::MakeUnique<PersistentPrefStoreImpl>(
+ CreateTrackedPersistentPrefStore(
+ std::move(configuration->get_tracked_configuration()), worker_pool),
+ std::move(on_initialized));
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/persistent_pref_store_factory.h b/chromium/services/preferences/persistent_pref_store_factory.h
new file mode 100644
index 00000000000..06cf8f701b0
--- /dev/null
+++ b/chromium/services/preferences/persistent_pref_store_factory.h
@@ -0,0 +1,28 @@
+// 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_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
+#define SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
+
+#include <memory>
+
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+
+namespace base {
+class SequencedWorkerPool;
+}
+
+namespace prefs {
+class PersistentPrefStoreImpl;
+
+// Create a new mojom::PersistentPrefStore impl that runs on |worker_pool|
+// configured by |configuration|.
+std::unique_ptr<PersistentPrefStoreImpl> CreatePersistentPrefStore(
+ mojom::PersistentPrefStoreConfigurationPtr configuration,
+ base::SequencedWorkerPool* worker_pool,
+ base::Closure on_initialized);
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_FACTORY_H_
diff --git a/chromium/services/preferences/persistent_pref_store_impl.cc b/chromium/services/preferences/persistent_pref_store_impl.cc
new file mode 100644
index 00000000000..95930387654
--- /dev/null
+++ b/chromium/services/preferences/persistent_pref_store_impl.cc
@@ -0,0 +1,161 @@
+// 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/preferences/persistent_pref_store_impl.h"
+
+#include <utility>
+
+#include "base/auto_reset.h"
+#include "base/memory/ptr_util.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+#include "components/prefs/persistent_pref_store.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace prefs {
+
+class PersistentPrefStoreImpl::Connection : public mojom::PersistentPrefStore {
+ public:
+ Connection(PersistentPrefStoreImpl* pref_store,
+ mojom::PersistentPrefStoreRequest request,
+ mojom::PrefStoreObserverPtr observer,
+ ObservedPrefs observed_keys)
+ : pref_store_(pref_store),
+ binding_(this, std::move(request)),
+ observer_(std::move(observer)),
+ observed_keys_(std::move(observed_keys)) {
+ auto error_callback =
+ base::Bind(&PersistentPrefStoreImpl::Connection::OnConnectionError,
+ base::Unretained(this));
+ binding_.set_connection_error_handler(error_callback);
+ observer_.set_connection_error_handler(error_callback);
+ }
+
+ ~Connection() override = default;
+
+ void OnPrefValuesChanged(const std::vector<mojom::PrefUpdatePtr>& updates) {
+ if (write_in_progress_)
+ return;
+
+ std::vector<mojom::PrefUpdatePtr> filtered_updates;
+ for (const auto& update : updates) {
+ if (base::ContainsKey(observed_keys_, update->key)) {
+ filtered_updates.push_back(mojom::PrefUpdate::New(
+ update->key,
+ update->value ? update->value->CreateDeepCopy() : nullptr, 0));
+ }
+ }
+ if (!filtered_updates.empty())
+ observer_->OnPrefsChanged(std::move(filtered_updates));
+ }
+
+ private:
+ // mojom::PersistentPrefStore:
+ void SetValues(std::vector<mojom::PrefUpdatePtr> updates) override {
+ base::AutoReset<bool> scoped_call_in_progress(&write_in_progress_, true);
+ pref_store_->SetValues(std::move(updates));
+ }
+
+ void CommitPendingWrite() override { pref_store_->CommitPendingWrite(); }
+ void SchedulePendingLossyWrites() override {
+ pref_store_->SchedulePendingLossyWrites();
+ }
+ void ClearMutableValues() override { pref_store_->ClearMutableValues(); }
+
+ void OnConnectionError() { pref_store_->OnConnectionError(this); }
+
+ // Owns |this|.
+ PersistentPrefStoreImpl* const pref_store_;
+
+ mojo::Binding<mojom::PersistentPrefStore> binding_;
+ mojom::PrefStoreObserverPtr observer_;
+ const ObservedPrefs observed_keys_;
+
+ // If true then a write is in progress and any update notifications should be
+ // ignored, as those updates would originate from ourselves.
+ bool write_in_progress_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(Connection);
+};
+
+PersistentPrefStoreImpl::PersistentPrefStoreImpl(
+ scoped_refptr<PersistentPrefStore> backing_pref_store,
+ base::OnceClosure on_initialized)
+ : backing_pref_store_(backing_pref_store) {
+ if (!backing_pref_store_->IsInitializationComplete()) {
+ backing_pref_store_->AddObserver(this);
+ on_initialized_ = std::move(on_initialized);
+ initializing_ = true;
+ backing_pref_store_->ReadPrefsAsync(nullptr);
+ }
+}
+
+PersistentPrefStoreImpl::~PersistentPrefStoreImpl() = default;
+
+mojom::PersistentPrefStoreConnectionPtr
+PersistentPrefStoreImpl::CreateConnection(ObservedPrefs observed_prefs) {
+ DCHECK(!initializing_);
+ if (!backing_pref_store_->IsInitializationComplete()) {
+ // |backing_pref_store_| initialization failed.
+ return mojom::PersistentPrefStoreConnection::New(
+ nullptr, nullptr, backing_pref_store_->GetReadError(),
+ backing_pref_store_->ReadOnly());
+ }
+ mojom::PersistentPrefStorePtr pref_store_ptr;
+ mojom::PrefStoreObserverPtr observer;
+ mojom::PrefStoreObserverRequest observer_request =
+ mojo::MakeRequest(&observer);
+ auto connection = base::MakeUnique<Connection>(
+ this, mojo::MakeRequest(&pref_store_ptr), std::move(observer),
+ std::move(observed_prefs));
+ auto* connection_ptr = connection.get();
+ connections_.insert(std::make_pair(connection_ptr, std::move(connection)));
+ return mojom::PersistentPrefStoreConnection::New(
+ mojom::PrefStoreConnection::New(std::move(observer_request),
+ backing_pref_store_->GetValues(), true),
+ std::move(pref_store_ptr), backing_pref_store_->GetReadError(),
+ backing_pref_store_->ReadOnly());
+}
+
+void PersistentPrefStoreImpl::OnPrefValueChanged(const std::string& key) {}
+
+void PersistentPrefStoreImpl::OnInitializationCompleted(bool succeeded) {
+ DCHECK(initializing_);
+ backing_pref_store_->RemoveObserver(this);
+ initializing_ = false;
+ std::move(on_initialized_).Run();
+}
+
+void PersistentPrefStoreImpl::SetValues(
+ std::vector<mojom::PrefUpdatePtr> updates) {
+ for (auto& entry : connections_)
+ entry.first->OnPrefValuesChanged(updates);
+
+ for (auto& update : updates) {
+ if (update->value) {
+ backing_pref_store_->SetValue(update->key, std::move(update->value),
+ update->flags);
+ } else {
+ backing_pref_store_->RemoveValue(update->key, update->flags);
+ }
+ }
+}
+
+void PersistentPrefStoreImpl::CommitPendingWrite() {
+ backing_pref_store_->CommitPendingWrite();
+}
+
+void PersistentPrefStoreImpl::SchedulePendingLossyWrites() {
+ backing_pref_store_->SchedulePendingLossyWrites();
+}
+
+void PersistentPrefStoreImpl::ClearMutableValues() {
+ backing_pref_store_->ClearMutableValues();
+}
+
+void PersistentPrefStoreImpl::OnConnectionError(Connection* connection) {
+ connections_.erase(connection);
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/persistent_pref_store_impl.h b/chromium/services/preferences/persistent_pref_store_impl.h
new file mode 100644
index 00000000000..5111ed7f4e2
--- /dev/null
+++ b/chromium/services/preferences/persistent_pref_store_impl.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_PREFERENCES_PERSISTENT_PREF_STORE_IMPL_H_
+#define SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_IMPL_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "base/macros.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+
+namespace prefs {
+
+class PersistentPrefStoreImpl : public PrefStore::Observer {
+ public:
+ using ObservedPrefs = std::set<std::string>;
+
+ // If |initialized()| is false after construction, |on_initialized| will be
+ // called when it becomes true.
+ PersistentPrefStoreImpl(
+ scoped_refptr<PersistentPrefStore> backing_pref_store,
+ base::OnceClosure on_initialized);
+
+ ~PersistentPrefStoreImpl() override;
+
+ mojom::PersistentPrefStoreConnectionPtr CreateConnection(
+ ObservedPrefs observed_prefs);
+
+ bool initialized() { return !initializing_; }
+
+ private:
+ class Connection;
+
+ void SetValues(std::vector<mojom::PrefUpdatePtr> updates);
+
+ void CommitPendingWrite();
+ void SchedulePendingLossyWrites();
+ void ClearMutableValues();
+
+ // PrefStore::Observer:
+ void OnPrefValueChanged(const std::string& key) override;
+ void OnInitializationCompleted(bool succeeded) override;
+
+ void OnConnectionError(Connection* connection);
+
+ scoped_refptr<PersistentPrefStore> backing_pref_store_;
+
+ bool initializing_ = false;
+
+ std::unordered_map<Connection*, std::unique_ptr<Connection>> connections_;
+
+ base::OnceClosure on_initialized_;
+
+ DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreImpl);
+};
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PERSISTENT_PREF_STORE_IMPL_H_
diff --git a/chromium/services/preferences/persistent_pref_store_impl_unittest.cc b/chromium/services/preferences/persistent_pref_store_impl_unittest.cc
new file mode 100644
index 00000000000..7a326276c0a
--- /dev/null
+++ b/chromium/services/preferences/persistent_pref_store_impl_unittest.cc
@@ -0,0 +1,336 @@
+// 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/preferences/persistent_pref_store_impl.h"
+
+#include <utility>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#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 "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Invoke;
+using testing::WithoutArgs;
+
+namespace prefs {
+namespace {
+
+class PrefStoreObserverMock : public PrefStore::Observer {
+ public:
+ MOCK_METHOD1(OnPrefValueChanged, void(const std::string&));
+ MOCK_METHOD1(OnInitializationCompleted, void(bool));
+};
+
+class PersistentPrefStoreMock : public InMemoryPrefStore {
+ public:
+ MOCK_METHOD0(CommitPendingWrite, void());
+ MOCK_METHOD0(SchedulePendingLossyWrites, void());
+ MOCK_METHOD0(ClearMutableValues, void());
+
+ private:
+ ~PersistentPrefStoreMock() override = default;
+};
+
+void ExpectPrefChange(PrefStore* pref_store, base::StringPiece key) {
+ PrefStoreObserverMock observer;
+ pref_store->AddObserver(&observer);
+ base::RunLoop run_loop;
+ EXPECT_CALL(observer, OnPrefValueChanged(key.as_string()))
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ run_loop.Run();
+ pref_store->RemoveObserver(&observer);
+}
+
+class InitializationMockPersistentPrefStore : public InMemoryPrefStore {
+ public:
+ InitializationMockPersistentPrefStore(
+ bool success,
+ PersistentPrefStore::PrefReadError error,
+ bool read_only)
+ : success_(success), read_error_(error), read_only_(read_only) {}
+
+ bool IsInitializationComplete() const override {
+ return initialized_ && success_;
+ }
+
+ void AddObserver(PrefStore::Observer* observer) override {
+ observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(PrefStore::Observer* observer) override {
+ observers_.RemoveObserver(observer);
+ }
+
+ void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override {
+ DCHECK(!error_delegate);
+ DCHECK(!initialized_);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE,
+ base::Bind(&InitializationMockPersistentPrefStore::CompleteRead, this));
+ }
+
+ void CompleteRead() {
+ initialized_ = true;
+ for (auto& observer : observers_) {
+ observer.OnInitializationCompleted(success_);
+ }
+ }
+
+ PersistentPrefStore::PrefReadError GetReadError() const override {
+ return read_error_;
+ }
+ bool ReadOnly() const override { return read_only_; }
+
+ private:
+ ~InitializationMockPersistentPrefStore() override = default;
+
+ bool initialized_ = false;
+ bool success_;
+ PersistentPrefStore::PrefReadError read_error_;
+ bool read_only_;
+ base::ObserverList<PrefStore::Observer, true> observers_;
+};
+
+constexpr char kKey[] = "path.to.key";
+constexpr char kOtherKey[] = "path.to.other_key";
+
+class PersistentPrefStoreImplTest : public testing::Test {
+ public:
+ PersistentPrefStoreImplTest() = default;
+
+ // testing::Test:
+ void TearDown() override {
+ pref_store_ = nullptr;
+ base::RunLoop().RunUntilIdle();
+ impl_.reset();
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void CreateImpl(scoped_refptr<PersistentPrefStore> backing_pref_store) {
+ base::RunLoop run_loop;
+ bool initialized = backing_pref_store->IsInitializationComplete();
+ impl_ = base::MakeUnique<PersistentPrefStoreImpl>(
+ std::move(backing_pref_store), run_loop.QuitClosure());
+ if (!initialized)
+ run_loop.Run();
+ pref_store_ = CreateConnection();
+ }
+
+ scoped_refptr<PersistentPrefStore> CreateConnection(
+ PersistentPrefStoreImpl::ObservedPrefs observed_prefs =
+ PersistentPrefStoreImpl::ObservedPrefs()) {
+ if (observed_prefs.empty())
+ observed_prefs.insert({kKey, kOtherKey});
+ return make_scoped_refptr(new PersistentPrefStoreClient(
+ impl_->CreateConnection(std::move(observed_prefs))));
+ }
+
+ PersistentPrefStore* pref_store() { return pref_store_.get(); }
+
+ private:
+ base::MessageLoop message_loop_;
+
+ std::unique_ptr<PersistentPrefStoreImpl> impl_;
+
+ scoped_refptr<PersistentPrefStore> pref_store_;
+
+ DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreImplTest);
+};
+
+TEST_F(PersistentPrefStoreImplTest, InitializationSuccess) {
+ auto backing_pref_store =
+ make_scoped_refptr(new InitializationMockPersistentPrefStore(
+ true, PersistentPrefStore::PREF_READ_ERROR_NONE, false));
+ CreateImpl(backing_pref_store);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ pref_store()->GetReadError());
+ EXPECT_FALSE(pref_store()->ReadOnly());
+}
+
+TEST_F(PersistentPrefStoreImplTest, InitializationFailure) {
+ auto backing_pref_store =
+ make_scoped_refptr(new InitializationMockPersistentPrefStore(
+ false, PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE, true));
+ CreateImpl(backing_pref_store);
+ EXPECT_FALSE(pref_store()->IsInitializationComplete());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE,
+ pref_store()->GetReadError());
+ EXPECT_TRUE(pref_store()->ReadOnly());
+}
+
+TEST_F(PersistentPrefStoreImplTest, InitialValue) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+}
+
+TEST_F(PersistentPrefStoreImplTest, InitialValueWithoutPathExpansion) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(pref_store()->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+}
+
+TEST_F(PersistentPrefStoreImplTest, WriteObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ CreateImpl(backing_pref_store);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ auto other_pref_store = CreateConnection();
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ const base::Value value("value");
+ pref_store()->SetValueSilently(kKey, value.CreateDeepCopy(), 0);
+
+ ExpectPrefChange(other_pref_store.get(), kKey);
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+}
+
+TEST_F(PersistentPrefStoreImplTest, UnregisteredPrefNotObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ CreateImpl(backing_pref_store);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ PersistentPrefStoreImpl::ObservedPrefs observed_prefs;
+ observed_prefs.insert(kKey);
+
+ auto other_pref_store = CreateConnection(std::move(observed_prefs));
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ pref_store()->SetValue(kOtherKey, base::MakeUnique<base::Value>(123), 0);
+ pref_store()->SetValue(kKey, base::MakeUnique<base::Value>("value"), 0);
+
+ ExpectPrefChange(other_pref_store.get(), kKey);
+ EXPECT_FALSE(other_pref_store->GetValue(kOtherKey, nullptr));
+}
+
+TEST_F(PersistentPrefStoreImplTest,
+ WriteWithoutPathExpansionObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ CreateImpl(backing_pref_store);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ auto other_pref_store = CreateConnection();
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ pref_store()->SetValue(kKey, dict.CreateDeepCopy(), 0);
+
+ ExpectPrefChange(other_pref_store.get(), kKey);
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+}
+
+TEST_F(PersistentPrefStoreImplTest, RemoveObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ const base::Value value("value");
+ backing_pref_store->SetValue(kKey, value.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ auto other_pref_store = CreateConnection();
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ EXPECT_TRUE(value.Equals(output));
+ pref_store()->RemoveValue(kKey, 0);
+
+ // This should be a no-op and shouldn't trigger a notification for the other
+ // client.
+ pref_store()->RemoveValue(kKey, 0);
+
+ ExpectPrefChange(other_pref_store.get(), kKey);
+ EXPECT_FALSE(other_pref_store->GetValue(kKey, &output));
+}
+
+TEST_F(PersistentPrefStoreImplTest,
+ RemoveWithoutPathExpansionObservedByOtherClient) {
+ auto backing_pref_store = make_scoped_refptr(new InMemoryPrefStore());
+ base::DictionaryValue dict;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ backing_pref_store->SetValue(kKey, dict.CreateDeepCopy(), 0);
+ CreateImpl(backing_pref_store);
+ EXPECT_TRUE(pref_store()->IsInitializationComplete());
+
+ auto other_pref_store = CreateConnection();
+ EXPECT_TRUE(other_pref_store->IsInitializationComplete());
+
+ const base::Value* output = nullptr;
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ EXPECT_TRUE(dict.Equals(output));
+
+ base::Value* mutable_value = nullptr;
+ dict.SetStringWithoutPathExpansion(kKey, "value");
+ ASSERT_TRUE(pref_store()->GetMutableValue(kKey, &mutable_value));
+ base::DictionaryValue* mutable_dict = nullptr;
+ ASSERT_TRUE(mutable_value->GetAsDictionary(&mutable_dict));
+ mutable_dict->RemoveWithoutPathExpansion(kKey, nullptr);
+ pref_store()->ReportValueChanged(kKey, 0);
+
+ ExpectPrefChange(other_pref_store.get(), kKey);
+ ASSERT_TRUE(other_pref_store->GetValue(kKey, &output));
+ const base::DictionaryValue* dict_value = nullptr;
+ ASSERT_TRUE(output->GetAsDictionary(&dict_value));
+ EXPECT_TRUE(dict_value->empty());
+}
+
+TEST_F(PersistentPrefStoreImplTest, CommitPendingWrite) {
+ auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
+ CreateImpl(backing_store);
+ base::RunLoop run_loop;
+ EXPECT_CALL(*backing_store, CommitPendingWrite())
+ .Times(2)
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ pref_store()->CommitPendingWrite();
+ run_loop.Run();
+}
+
+TEST_F(PersistentPrefStoreImplTest, SchedulePendingLossyWrites) {
+ auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
+ CreateImpl(backing_store);
+ base::RunLoop run_loop;
+ EXPECT_CALL(*backing_store, SchedulePendingLossyWrites())
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1);
+ pref_store()->SchedulePendingLossyWrites();
+ run_loop.Run();
+}
+
+TEST_F(PersistentPrefStoreImplTest, ClearMutableValues) {
+ auto backing_store = make_scoped_refptr(new PersistentPrefStoreMock);
+ CreateImpl(backing_store);
+ base::RunLoop run_loop;
+ EXPECT_CALL(*backing_store, ClearMutableValues())
+ .WillOnce(WithoutArgs(Invoke([&run_loop]() { run_loop.Quit(); })));
+ EXPECT_CALL(*backing_store, CommitPendingWrite()).Times(1);
+ pref_store()->ClearMutableValues();
+ run_loop.Run();
+}
+
+} // namespace
+} // namespace prefs
diff --git a/chromium/services/preferences/pref_service_factory_unittest.cc b/chromium/services/preferences/pref_service_factory_unittest.cc
new file mode 100644
index 00000000000..21094e823ad
--- /dev/null
+++ b/chromium/services/preferences/pref_service_factory_unittest.cc
@@ -0,0 +1,269 @@
+// Copyright (c) 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/preferences/public/cpp/pref_service_factory.h"
+
+#include "base/files/scoped_temp_dir.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/test/sequenced_worker_pool_owner.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/value_map_pref_store.h"
+#include "components/prefs/writeable_pref_store.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/public/cpp/pref_service_main.h"
+#include "services/preferences/public/cpp/pref_store_impl.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/interface_factory.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"
+
+namespace prefs {
+namespace {
+
+class ServiceTestClient : public service_manager::test::ServiceTestClient,
+ public service_manager::mojom::ServiceFactory,
+ public service_manager::InterfaceFactory<
+ service_manager::mojom::ServiceFactory> {
+ public:
+ ServiceTestClient(service_manager::test::ServiceTest* test,
+ scoped_refptr<base::SequencedWorkerPool> worker_pool)
+ : service_manager::test::ServiceTestClient(test),
+ worker_pool_(std::move(worker_pool)) {
+ registry_.AddInterface<service_manager::mojom::ServiceFactory>(this);
+ }
+
+ protected:
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
+ }
+
+ void CreateService(service_manager::mojom::ServiceRequest request,
+ const std::string& name) override {
+ if (name == prefs::mojom::kServiceName) {
+ pref_service_context_.reset(new service_manager::ServiceContext(
+ CreatePrefService(
+ {PrefValueStore::COMMAND_LINE_STORE,
+ PrefValueStore::RECOMMENDED_STORE, PrefValueStore::USER_STORE,
+ PrefValueStore::DEFAULT_STORE},
+ worker_pool_),
+ std::move(request)));
+ }
+ }
+
+ void Create(const service_manager::Identity& remote_identity,
+ service_manager::mojom::ServiceFactoryRequest request) override {
+ service_factory_bindings_.AddBinding(this, std::move(request));
+ }
+
+ private:
+ scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+ service_manager::BinderRegistry registry_;
+ mojo::BindingSet<service_manager::mojom::ServiceFactory>
+ service_factory_bindings_;
+ std::unique_ptr<service_manager::ServiceContext> pref_service_context_;
+};
+
+constexpr int kInitialValue = 1;
+constexpr int kUpdatedValue = 2;
+constexpr char kKey[] = "some_key";
+constexpr char kOtherKey[] = "some_other_key";
+
+class PrefServiceFactoryTest : public base::MessageLoop::DestructionObserver,
+ public service_manager::test::ServiceTest {
+ public:
+ PrefServiceFactoryTest() : ServiceTest("prefs_unittests", false) {}
+
+ protected:
+ void SetUp() override {
+ ServiceTest::SetUp();
+ ASSERT_TRUE(profile_dir_.CreateUniqueTempDir());
+
+ // Init the pref service (in production Chrome startup would do this.)
+ mojom::PrefServiceControlPtr control;
+ connector()->BindInterface(mojom::kServiceName, &control);
+ auto config = mojom::PersistentPrefStoreConfiguration::New();
+ config->set_simple_configuration(
+ mojom::SimplePersistentPrefStoreConfiguration::New(
+ profile_dir_.GetPath().AppendASCII("Preferences")));
+ control->Init(std::move(config));
+ above_user_prefs_pref_store_ = new ValueMapPrefStore();
+ below_user_prefs_pref_store_ = new ValueMapPrefStore();
+ mojom::PrefStoreRegistryPtr registry;
+ connector()->BindInterface(mojom::kServiceName, &registry);
+ above_user_prefs_impl_ =
+ PrefStoreImpl::Create(registry.get(), above_user_prefs_pref_store_,
+ PrefValueStore::COMMAND_LINE_STORE);
+ below_user_prefs_impl_ =
+ PrefStoreImpl::Create(registry.get(), below_user_prefs_pref_store_,
+ PrefValueStore::RECOMMENDED_STORE);
+ }
+
+ // service_manager::test::ServiceTest:
+ std::unique_ptr<service_manager::Service> CreateService() override {
+ return base::MakeUnique<ServiceTestClient>(this,
+ worker_pool_owner_->pool());
+ }
+
+ std::unique_ptr<base::MessageLoop> CreateMessageLoop() override {
+ auto loop = ServiceTest::CreateMessageLoop();
+ worker_pool_owner_ = base::MakeUnique<base::SequencedWorkerPoolOwner>(
+ 2, "PrefServiceFactoryTest");
+ loop->AddDestructionObserver(this);
+ return loop;
+ }
+
+ // base::MessageLoop::DestructionObserver
+ void WillDestroyCurrentMessageLoop() override { worker_pool_owner_.reset(); }
+
+ // Create a fully initialized PrefService synchronously.
+ std::unique_ptr<PrefService> Create() {
+ std::unique_ptr<PrefService> pref_service;
+ base::RunLoop run_loop;
+ auto pref_registry = make_scoped_refptr(new PrefRegistrySimple());
+ pref_registry->RegisterIntegerPref(kKey, kInitialValue);
+ pref_registry->RegisterIntegerPref(kOtherKey, kInitialValue);
+ ConnectToPrefService(connector(), pref_registry,
+ std::vector<PrefValueStore::PrefStoreType>(),
+ base::Bind(&PrefServiceFactoryTest::OnCreate,
+ run_loop.QuitClosure(), &pref_service));
+ run_loop.Run();
+ return pref_service;
+ }
+
+ // Wait until first update of the pref |key| in |pref_service| synchronously.
+ void WaitForPrefChange(PrefService* pref_service, const std::string& key) {
+ PrefChangeRegistrar registrar;
+ registrar.Init(pref_service);
+ base::RunLoop run_loop;
+ registrar.Add(key, base::Bind(&OnPrefChanged, run_loop.QuitClosure(), key));
+ run_loop.Run();
+ }
+
+ WriteablePrefStore* above_user_prefs_pref_store() {
+ return above_user_prefs_pref_store_.get();
+ }
+ WriteablePrefStore* below_user_prefs_pref_store() {
+ return below_user_prefs_pref_store_.get();
+ }
+
+ private:
+ // Called when the PrefService has been initialized.
+ static void OnInit(const base::Closure& quit_closure, bool success) {
+ quit_closure.Run();
+ }
+
+ // Called when the PrefService has been created.
+ static void OnCreate(const base::Closure& quit_closure,
+ std::unique_ptr<PrefService>* out,
+ std::unique_ptr<PrefService> pref_service) {
+ DCHECK(pref_service);
+ *out = std::move(pref_service);
+ if ((*out)->GetInitializationStatus() ==
+ PrefService::INITIALIZATION_STATUS_WAITING) {
+ (*out)->AddPrefInitObserver(
+ base::Bind(PrefServiceFactoryTest::OnInit, quit_closure));
+ return;
+ }
+ quit_closure.Run();
+ }
+
+ static void OnPrefChanged(const base::Closure& quit_closure,
+ const std::string& expected_path,
+ const std::string& path) {
+ if (path == expected_path)
+ quit_closure.Run();
+ }
+
+ base::ScopedTempDir profile_dir_;
+ std::unique_ptr<base::SequencedWorkerPoolOwner> worker_pool_owner_;
+ scoped_refptr<WriteablePrefStore> above_user_prefs_pref_store_;
+ std::unique_ptr<PrefStoreImpl> above_user_prefs_impl_;
+ scoped_refptr<WriteablePrefStore> below_user_prefs_pref_store_;
+ std::unique_ptr<PrefStoreImpl> below_user_prefs_impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefServiceFactoryTest);
+};
+
+// Check that a single client can set and read back values.
+TEST_F(PrefServiceFactoryTest, Basic) {
+ auto pref_service = Create();
+
+ EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
+ pref_service->SetInteger(kKey, kUpdatedValue);
+ EXPECT_EQ(kUpdatedValue, pref_service->GetInteger(kKey));
+}
+
+// Check that updates in one client eventually propagates to the other.
+TEST_F(PrefServiceFactoryTest, MultipleClients) {
+ auto pref_service = Create();
+ auto pref_service2 = Create();
+
+ EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
+ EXPECT_EQ(kInitialValue, pref_service2->GetInteger(kKey));
+ pref_service->SetInteger(kKey, kUpdatedValue);
+ WaitForPrefChange(pref_service2.get(), kKey);
+ EXPECT_EQ(kUpdatedValue, pref_service2->GetInteger(kKey));
+}
+
+// Check that read-only pref store changes are observed.
+TEST_F(PrefServiceFactoryTest, ReadOnlyPrefStore) {
+ auto pref_service = Create();
+
+ EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
+
+ below_user_prefs_pref_store()->SetValue(
+ kKey, base::MakeUnique<base::Value>(kUpdatedValue), 0);
+ WaitForPrefChange(pref_service.get(), kKey);
+ EXPECT_EQ(kUpdatedValue, pref_service->GetInteger(kKey));
+ pref_service->SetInteger(kKey, 3);
+ EXPECT_EQ(3, pref_service->GetInteger(kKey));
+ above_user_prefs_pref_store()->SetValue(kKey,
+ base::MakeUnique<base::Value>(4), 0);
+ WaitForPrefChange(pref_service.get(), kKey);
+ EXPECT_EQ(4, pref_service->GetInteger(kKey));
+}
+
+// Check that updates to read-only pref stores are correctly layered.
+TEST_F(PrefServiceFactoryTest, ReadOnlyPrefStore_Layering) {
+ auto pref_service = Create();
+
+ above_user_prefs_pref_store()->SetValue(
+ kKey, base::MakeUnique<base::Value>(kInitialValue), 0);
+ WaitForPrefChange(pref_service.get(), kKey);
+ EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
+
+ below_user_prefs_pref_store()->SetValue(
+ kKey, base::MakeUnique<base::Value>(kUpdatedValue), 0);
+ // This update is needed to check that the change to kKey has propagated even
+ // though we will not observe it change.
+ below_user_prefs_pref_store()->SetValue(
+ kOtherKey, base::MakeUnique<base::Value>(kUpdatedValue), 0);
+ WaitForPrefChange(pref_service.get(), kOtherKey);
+ EXPECT_EQ(kInitialValue, pref_service->GetInteger(kKey));
+}
+
+// Check that writes to user prefs are correctly layered with read-only
+// pref stores.
+TEST_F(PrefServiceFactoryTest, ReadOnlyPrefStore_UserPrefStoreLayering) {
+ auto pref_service = Create();
+
+ above_user_prefs_pref_store()->SetValue(kKey,
+ base::MakeUnique<base::Value>(2), 0);
+ WaitForPrefChange(pref_service.get(), kKey);
+ EXPECT_EQ(2, pref_service->GetInteger(kKey));
+
+ pref_service->SetInteger(kKey, 3);
+ EXPECT_EQ(2, pref_service->GetInteger(kKey));
+}
+
+} // namespace
+} // namespace prefs
diff --git a/chromium/services/preferences/pref_store_manager_impl.cc b/chromium/services/preferences/pref_store_manager_impl.cc
new file mode 100644
index 00000000000..f418792f29e
--- /dev/null
+++ b/chromium/services/preferences/pref_store_manager_impl.cc
@@ -0,0 +1,280 @@
+// 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/preferences/pref_store_manager_impl.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "base/memory/ref_counted.h"
+#include "base/stl_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "components/prefs/default_pref_store.h"
+#include "components/prefs/pref_value_store.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/preferences/persistent_pref_store_factory.h"
+#include "services/preferences/persistent_pref_store_impl.h"
+#include "services/preferences/public/cpp/pref_store_impl.h"
+#include "services/service_manager/public/cpp/service_info.h"
+
+namespace prefs {
+namespace {
+
+using ConnectCallback = mojom::PrefStoreConnector::ConnectCallback;
+using PrefStorePtrs =
+ std::unordered_map<PrefValueStore::PrefStoreType, mojom::PrefStore*>;
+
+// Used to make sure all pref stores have been registered before replying to any
+// Connect calls.
+class ConnectionBarrier : public base::RefCounted<ConnectionBarrier> {
+ public:
+ static void Create(
+ const PrefStorePtrs& pref_store_ptrs,
+ mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection,
+ const std::vector<std::string>& observed_prefs,
+ const ConnectCallback& callback);
+
+ void Init(const PrefStorePtrs& pref_store_ptrs,
+ const std::vector<std::string>& observed_prefs);
+
+ private:
+ friend class base::RefCounted<ConnectionBarrier>;
+ ConnectionBarrier(
+ const PrefStorePtrs& pref_store_ptrs,
+ mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection,
+ const ConnectCallback& callback);
+ ~ConnectionBarrier() = default;
+
+ void OnConnect(PrefValueStore::PrefStoreType type,
+ mojom::PrefStoreConnectionPtr connection_ptr);
+
+ ConnectCallback callback_;
+
+ std::unordered_map<PrefValueStore::PrefStoreType,
+ mojom::PrefStoreConnectionPtr>
+ connections_;
+
+ const size_t expected_connections_;
+
+ mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectionBarrier);
+};
+
+// static
+void ConnectionBarrier::Create(
+ const PrefStorePtrs& pref_store_ptrs,
+ mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection,
+ const std::vector<std::string>& observed_prefs,
+ const ConnectCallback& callback) {
+ make_scoped_refptr(new ConnectionBarrier(
+ pref_store_ptrs,
+ std::move(persistent_pref_store_connection), callback))
+ ->Init(pref_store_ptrs, observed_prefs);
+}
+
+void ConnectionBarrier::Init(const PrefStorePtrs& pref_store_ptrs,
+ const std::vector<std::string>& observed_prefs) {
+ for (const auto& ptr : pref_store_ptrs) {
+ ptr.second->AddObserver(
+ observed_prefs,
+ base::Bind(&ConnectionBarrier::OnConnect, this, ptr.first));
+ }
+}
+
+ConnectionBarrier::ConnectionBarrier(
+ const PrefStorePtrs& pref_store_ptrs,
+ mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection,
+ const ConnectCallback& callback)
+ : callback_(callback),
+ expected_connections_(pref_store_ptrs.size()),
+ persistent_pref_store_connection_(
+ std::move(persistent_pref_store_connection)) {}
+
+void ConnectionBarrier::OnConnect(
+ PrefValueStore::PrefStoreType type,
+ mojom::PrefStoreConnectionPtr connection_ptr) {
+ connections_.insert(std::make_pair(type, std::move(connection_ptr)));
+ if (connections_.size() == expected_connections_) {
+ // After this method exits |this| will get destroyed so it's safe to move
+ // out the members.
+ callback_.Run(std::move(persistent_pref_store_connection_),
+ std::move(connections_));
+ }
+}
+
+} // namespace
+
+PrefStoreManagerImpl::PrefStoreManagerImpl(
+ std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
+ scoped_refptr<base::SequencedWorkerPool> worker_pool)
+ : expected_pref_stores_(std::move(expected_pref_stores)),
+ init_binding_(this),
+ defaults_(new DefaultPrefStore),
+ defaults_wrapper_(base::MakeUnique<PrefStoreImpl>(
+ defaults_,
+ mojo::MakeRequest(&pref_store_ptrs_[PrefValueStore::DEFAULT_STORE]))),
+ worker_pool_(std::move(worker_pool)) {
+ DCHECK(
+ base::ContainsValue(expected_pref_stores_, PrefValueStore::USER_STORE) &&
+ base::ContainsValue(expected_pref_stores_, PrefValueStore::DEFAULT_STORE))
+ << "expected_pref_stores must always include PrefValueStore::USER_STORE "
+ "and PrefValueStore::DEFAULT_STORE.";
+ // The user store is not actually connected to in the implementation, but
+ // accessed directly.
+ expected_pref_stores_.erase(PrefValueStore::USER_STORE);
+ registry_.AddInterface<prefs::mojom::PrefStoreConnector>(this);
+ registry_.AddInterface<prefs::mojom::PrefStoreRegistry>(this);
+ registry_.AddInterface<prefs::mojom::PrefServiceControl>(this);
+}
+
+PrefStoreManagerImpl::~PrefStoreManagerImpl() = default;
+
+struct PrefStoreManagerImpl::PendingConnect {
+ mojom::PrefRegistryPtr pref_registry;
+ // Pref stores the caller already is connected to (and hence we won't
+ // connect to these).
+ std::vector<PrefValueStore::PrefStoreType> already_connected_types;
+ ConnectCallback callback;
+};
+
+void PrefStoreManagerImpl::Register(PrefValueStore::PrefStoreType type,
+ mojom::PrefStorePtr pref_store_ptr) {
+ if (expected_pref_stores_.count(type) == 0) {
+ LOG(WARNING) << "Not registering unexpected pref store: " << type;
+ return;
+ }
+ DVLOG(1) << "Registering pref store: " << type;
+ pref_store_ptr.set_connection_error_handler(
+ base::Bind(&PrefStoreManagerImpl::OnPrefStoreDisconnect,
+ base::Unretained(this), type));
+ const bool success =
+ pref_store_ptrs_.insert(std::make_pair(type, std::move(pref_store_ptr)))
+ .second;
+ DCHECK(success) << "The same pref store registered twice: " << type;
+ if (AllConnected()) {
+ DVLOG(1) << "All pref stores registered.";
+ ProcessPendingConnects();
+ }
+}
+
+void PrefStoreManagerImpl::Connect(
+ mojom::PrefRegistryPtr pref_registry,
+ const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
+ const ConnectCallback& callback) {
+ if (AllConnected()) {
+ ConnectImpl(std::move(pref_registry), already_connected_types, callback);
+ } else {
+ pending_connects_.push_back(
+ {std::move(pref_registry), already_connected_types, callback});
+ }
+}
+
+void PrefStoreManagerImpl::Create(
+ const service_manager::Identity& remote_identity,
+ prefs::mojom::PrefStoreConnectorRequest request) {
+ connector_bindings_.AddBinding(this, std::move(request));
+}
+
+void PrefStoreManagerImpl::Create(
+ const service_manager::Identity& remote_identity,
+ prefs::mojom::PrefStoreRegistryRequest request) {
+ registry_bindings_.AddBinding(this, std::move(request));
+}
+
+void PrefStoreManagerImpl::Create(
+ const service_manager::Identity& remote_identity,
+ prefs::mojom::PrefServiceControlRequest request) {
+ if (init_binding_.is_bound()) {
+ LOG(ERROR)
+ << "Pref service received unexpected control interface connection from "
+ << remote_identity.name();
+ return;
+ }
+
+ init_binding_.Bind(std::move(request));
+}
+
+void PrefStoreManagerImpl::Init(
+ mojom::PersistentPrefStoreConfigurationPtr configuration) {
+ DCHECK(!persistent_pref_store_);
+
+ persistent_pref_store_ = CreatePersistentPrefStore(
+ std::move(configuration), worker_pool_.get(),
+ base::Bind(&PrefStoreManagerImpl::OnPersistentPrefStoreReady,
+ base::Unretained(this)));
+ DCHECK(persistent_pref_store_);
+ if (AllConnected())
+ ProcessPendingConnects();
+}
+
+void PrefStoreManagerImpl::OnStart() {}
+
+void PrefStoreManagerImpl::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
+}
+
+void PrefStoreManagerImpl::OnPrefStoreDisconnect(
+ PrefValueStore::PrefStoreType type) {
+ DVLOG(1) << "Deregistering pref store: " << type;
+ pref_store_ptrs_.erase(type);
+}
+
+bool PrefStoreManagerImpl::AllConnected() const {
+ return pref_store_ptrs_.size() == expected_pref_stores_.size() &&
+ persistent_pref_store_ && persistent_pref_store_->initialized();
+}
+
+void PrefStoreManagerImpl::ProcessPendingConnects() {
+ for (auto& connect : pending_connects_)
+ ConnectImpl(std::move(connect.pref_registry),
+ connect.already_connected_types, connect.callback);
+ pending_connects_.clear();
+}
+
+void PrefStoreManagerImpl::ConnectImpl(
+ mojom::PrefRegistryPtr pref_registry,
+ const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
+ const ConnectCallback& callback) {
+ std::vector<std::string> observed_prefs;
+ for (auto& registration : pref_registry->registrations) {
+ observed_prefs.push_back(registration.first);
+ const auto& key = registration.first;
+ auto& default_value = registration.second->default_value;
+ const base::Value* old_default = nullptr;
+ // TODO(sammc): Once non-owning registrations are supported, disallow
+ // multiple owners instead of just checking for consistent defaults.
+ if (defaults_->GetValue(key, &old_default))
+ DCHECK(old_default->Equals(default_value.get()));
+ else
+ defaults_->SetDefaultValue(key, std::move(default_value));
+ }
+
+ // Only connect to pref stores the client isn't already connected to.
+ PrefStorePtrs ptrs;
+ for (const auto& entry : pref_store_ptrs_) {
+ if (!base::ContainsValue(already_connected_types, entry.first)) {
+ ptrs.insert(std::make_pair(entry.first, entry.second.get()));
+ }
+ }
+ ConnectionBarrier::Create(
+ ptrs,
+ persistent_pref_store_->CreateConnection(
+ PersistentPrefStoreImpl::ObservedPrefs(observed_prefs.begin(),
+ observed_prefs.end())),
+ observed_prefs, callback);
+}
+
+void PrefStoreManagerImpl::OnPersistentPrefStoreReady() {
+ DVLOG(1) << "PersistentPrefStore ready";
+ if (AllConnected()) {
+ ProcessPendingConnects();
+ }
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/pref_store_manager_impl.h b/chromium/services/preferences/pref_store_manager_impl.h
new file mode 100644
index 00000000000..bc7eb1e6c45
--- /dev/null
+++ b/chromium/services/preferences/pref_store_manager_impl.h
@@ -0,0 +1,136 @@
+// 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_PREFERENCES_PREF_STORE_MANAGER_IMPL_H_
+#define SERVICES_PREFERENCES_PREF_STORE_MANAGER_IMPL_H_
+
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "components/prefs/pref_value_store.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/service_manager/public/cpp/interface_factory.h"
+#include "services/service_manager/public/cpp/service.h"
+
+class DefaultPrefStore;
+
+namespace base {
+class SequencedWorkerPool;
+}
+
+namespace prefs {
+class PersistentPrefStoreImpl;
+class PrefStoreImpl;
+
+// This class mediates the connection of clients who wants to read preferences
+// and the pref stores that store those preferences. Pref stores use the
+// |PrefStoreRegistry| interface to register themselves with the manager and
+// clients use the |PrefStoreConnector| interface to connect to these stores.
+class PrefStoreManagerImpl
+ : public mojom::PrefStoreRegistry,
+ public mojom::PrefStoreConnector,
+ public service_manager::InterfaceFactory<mojom::PrefStoreConnector>,
+ public service_manager::InterfaceFactory<mojom::PrefStoreRegistry>,
+ public mojom::PrefServiceControl,
+ public service_manager::InterfaceFactory<mojom::PrefServiceControl>,
+ public service_manager::Service {
+ public:
+ // Only replies to Connect calls when all |expected_pref_stores| have
+ // registered. |expected_pref_stores| must contain
+ // PrefValueStore::DEFAULT_STORE and PrefValueStore::USER_STORE for
+ // consistency, as the service always registers these
+ // internally. |worker_pool| is used for any I/O performed by the service.
+ PrefStoreManagerImpl(
+ std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
+ scoped_refptr<base::SequencedWorkerPool> worker_pool);
+ ~PrefStoreManagerImpl() override;
+
+ private:
+ struct PendingConnect;
+
+ // mojom::PrefStoreRegistry:
+ void Register(PrefValueStore::PrefStoreType type,
+ mojom::PrefStorePtr pref_store_ptr) override;
+
+ // mojom::PrefStoreConnector: |already_connected_types| must not include
+ // PrefValueStore::DEFAULT_STORE and PrefValueStore::USER_STORE as these must
+ // always be accessed through the service.
+ void Connect(
+ mojom::PrefRegistryPtr pref_registry,
+ const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
+ const ConnectCallback& callback) override;
+
+ // service_manager::InterfaceFactory<PrefStoreConnector>:
+ void Create(const service_manager::Identity& remote_identity,
+ prefs::mojom::PrefStoreConnectorRequest request) override;
+
+ // service_manager::InterfaceFactory<PrefStoreRegistry>:
+ void Create(const service_manager::Identity& remote_identity,
+ prefs::mojom::PrefStoreRegistryRequest request) override;
+
+ // service_manager::InterfaceFactory<PrefServiceControl>:
+ void Create(const service_manager::Identity& remote_identity,
+ prefs::mojom::PrefServiceControlRequest request) override;
+
+ // PrefServiceControl:
+ void Init(mojom::PersistentPrefStoreConfigurationPtr configuration) override;
+
+ // service_manager::Service:
+ void OnStart() override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
+
+ // Called when a PrefStore previously registered using |Register| disconnects.
+ void OnPrefStoreDisconnect(PrefValueStore::PrefStoreType type);
+
+ // Have all the expected PrefStores connected?
+ bool AllConnected() const;
+
+ void ProcessPendingConnects();
+
+ void ConnectImpl(
+ mojom::PrefRegistryPtr pref_registry,
+ const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
+ const ConnectCallback& callback);
+
+ void OnPersistentPrefStoreReady();
+
+ // PrefStores that need to register before replying to any Connect calls. This
+ // does not include the PersistentPrefStore, which is handled separately.
+ std::set<PrefValueStore::PrefStoreType> expected_pref_stores_;
+
+ // Registered pref stores.
+ std::unordered_map<PrefValueStore::PrefStoreType, mojom::PrefStorePtr>
+ pref_store_ptrs_;
+
+ // We hold on to the connection request callbacks until all expected
+ // PrefStores have registered.
+ std::vector<PendingConnect> pending_connects_;
+
+ mojo::BindingSet<mojom::PrefStoreConnector> connector_bindings_;
+ mojo::BindingSet<mojom::PrefStoreRegistry> registry_bindings_;
+ std::unique_ptr<PersistentPrefStoreImpl> persistent_pref_store_;
+ mojo::Binding<mojom::PrefServiceControl> init_binding_;
+
+ const scoped_refptr<DefaultPrefStore> defaults_;
+ const std::unique_ptr<PrefStoreImpl> defaults_wrapper_;
+
+ const scoped_refptr<base::SequencedWorkerPool> worker_pool_;
+
+ service_manager::BinderRegistry registry_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreManagerImpl);
+};
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PREF_STORE_MANAGER_IMPL_H_
diff --git a/chromium/services/preferences/public/cpp/BUILD.gn b/chromium/services/preferences/public/cpp/BUILD.gn
index 727169326a4..1499131617c 100644
--- a/chromium/services/preferences/public/cpp/BUILD.gn
+++ b/chromium/services/preferences/public/cpp/BUILD.gn
@@ -4,18 +4,43 @@
source_set("cpp") {
sources = [
- "pref_client_store.cc",
- "pref_client_store.h",
+ "persistent_pref_store_client.cc",
+ "persistent_pref_store_client.h",
+ "pref_registry_serializer.cc",
+ "pref_registry_serializer.h",
+ "pref_service_factory.cc",
+ "pref_service_factory.h",
+ "pref_store_adapter.cc",
+ "pref_store_adapter.h",
+ "pref_store_client.cc",
+ "pref_store_client.h",
+ "pref_store_client_mixin.cc",
+ "pref_store_client_mixin.h",
+ "pref_store_impl.cc",
+ "pref_store_impl.h",
]
public_deps = [
"//base",
- "//components/prefs:prefs",
+ "//components/prefs",
"//services/preferences/public/interfaces",
"//services/service_manager/public/cpp",
]
deps = [
- "//mojo/public/cpp/bindings:bindings",
+ "//mojo/public/cpp/bindings",
+ ]
+}
+
+source_set("service_main") {
+ deps = [
+ "//base",
+ "//components/prefs",
+ "//services/preferences",
+ "//services/service_manager/public/cpp",
+ ]
+ sources = [
+ "pref_service_main.cc",
+ "pref_service_main.h",
]
}
diff --git a/chromium/services/preferences/public/cpp/DEPS b/chromium/services/preferences/public/cpp/DEPS
index eac076192dc..45e227dd6d0 100644
--- a/chromium/services/preferences/public/cpp/DEPS
+++ b/chromium/services/preferences/public/cpp/DEPS
@@ -1,3 +1,10 @@
include_rules = [
"+components/prefs",
+ "-services/preferences",
+ "+services/preferences/public",
]
+specific_include_rules = {
+ "pref_service_main\.cc": [
+ "+services/preferences",
+ ],
+}
diff --git a/chromium/services/preferences/public/cpp/OWNERS b/chromium/services/preferences/public/cpp/OWNERS
new file mode 100644
index 00000000000..4df0c71cc7d
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/OWNERS
@@ -0,0 +1,4 @@
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_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.cc b/chromium/services/preferences/public/cpp/persistent_pref_store_client.cc
new file mode 100644
index 00000000000..9bcb92fb1b6
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/persistent_pref_store_client.cc
@@ -0,0 +1,184 @@
+// 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/preferences/public/cpp/persistent_pref_store_client.h"
+
+#include <utility>
+
+#include "base/values.h"
+#include "components/prefs/pref_registry.h"
+#include "mojo/public/cpp/bindings/sync_call_restrictions.h"
+#include "services/preferences/public/cpp/pref_registry_serializer.h"
+
+namespace prefs {
+
+PersistentPrefStoreClient::PersistentPrefStoreClient(
+ mojom::PrefStoreConnectorPtr connector,
+ scoped_refptr<PrefRegistry> pref_registry,
+ std::vector<PrefValueStore::PrefStoreType> already_connected_types)
+ : connector_(std::move(connector)),
+ pref_registry_(std::move(pref_registry)),
+ already_connected_types_(std::move(already_connected_types)),
+ weak_factory_(this) {
+ DCHECK(connector_);
+}
+
+PersistentPrefStoreClient::PersistentPrefStoreClient(
+ mojom::PersistentPrefStoreConnectionPtr connection)
+ : weak_factory_(this) {
+ OnConnect(std::move(connection),
+ std::unordered_map<PrefValueStore::PrefStoreType,
+ prefs::mojom::PrefStoreConnectionPtr>());
+}
+
+void PersistentPrefStoreClient::SetValue(const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) {
+ base::Value* old_value = nullptr;
+ GetMutableValues().Get(key, &old_value);
+ if (!old_value || !value->Equals(old_value)) {
+ GetMutableValues().Set(key, std::move(value));
+ ReportValueChanged(key, flags);
+ }
+}
+
+void PersistentPrefStoreClient::RemoveValue(const std::string& key,
+ uint32_t flags) {
+ if (GetMutableValues().RemovePath(key, nullptr))
+ ReportValueChanged(key, flags);
+}
+
+bool PersistentPrefStoreClient::GetMutableValue(const std::string& key,
+ base::Value** result) {
+ return GetMutableValues().Get(key, result);
+}
+
+void PersistentPrefStoreClient::ReportValueChanged(const std::string& key,
+ uint32_t flags) {
+ DCHECK(pref_store_);
+ const base::Value* local_value = nullptr;
+ GetMutableValues().Get(key, &local_value);
+
+ QueueWrite(key, flags);
+ ReportPrefValueChanged(key);
+}
+
+void PersistentPrefStoreClient::SetValueSilently(
+ const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) {
+ DCHECK(pref_store_);
+ QueueWrite(key, flags);
+ GetMutableValues().Set(key, std::move(value));
+}
+
+bool PersistentPrefStoreClient::ReadOnly() const {
+ return read_only_;
+}
+
+PersistentPrefStore::PrefReadError PersistentPrefStoreClient::GetReadError()
+ const {
+ return read_error_;
+}
+
+PersistentPrefStore::PrefReadError PersistentPrefStoreClient::ReadPrefs() {
+ mojom::PersistentPrefStoreConnectionPtr connection;
+ std::unordered_map<PrefValueStore::PrefStoreType,
+ prefs::mojom::PrefStoreConnectionPtr>
+ other_pref_stores;
+ mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_calls;
+ if (!connector_->Connect(SerializePrefRegistry(*pref_registry_),
+ already_connected_types_, &connection,
+ &other_pref_stores)) {
+ NOTREACHED();
+ }
+ pref_registry_ = nullptr;
+ OnConnect(std::move(connection), std::move(other_pref_stores));
+ return read_error_;
+}
+
+void PersistentPrefStoreClient::ReadPrefsAsync(
+ ReadErrorDelegate* error_delegate) {
+ error_delegate_.reset(error_delegate);
+ connector_->Connect(SerializePrefRegistry(*pref_registry_),
+ already_connected_types_,
+ base::Bind(&PersistentPrefStoreClient::OnConnect,
+ base::Unretained(this)));
+ pref_registry_ = nullptr;
+}
+
+void PersistentPrefStoreClient::CommitPendingWrite() {
+ DCHECK(pref_store_);
+ if (!pending_writes_.empty())
+ FlushPendingWrites();
+ pref_store_->CommitPendingWrite();
+}
+
+void PersistentPrefStoreClient::SchedulePendingLossyWrites() {
+ DCHECK(pref_store_);
+ return pref_store_->SchedulePendingLossyWrites();
+}
+
+void PersistentPrefStoreClient::ClearMutableValues() {
+ DCHECK(pref_store_);
+ return pref_store_->ClearMutableValues();
+}
+
+PersistentPrefStoreClient::~PersistentPrefStoreClient() {
+ if (!pref_store_)
+ return;
+
+ CommitPendingWrite();
+}
+
+void PersistentPrefStoreClient::OnConnect(
+ mojom::PersistentPrefStoreConnectionPtr connection,
+ std::unordered_map<PrefValueStore::PrefStoreType,
+ prefs::mojom::PrefStoreConnectionPtr>
+ other_pref_stores) {
+ connector_.reset();
+ read_error_ = connection->read_error;
+ read_only_ = connection->read_only;
+ pref_store_ = std::move(connection->pref_store);
+ if (error_delegate_ && read_error_ != PREF_READ_ERROR_NONE)
+ error_delegate_->OnError(read_error_);
+ error_delegate_.reset();
+
+ if (connection->pref_store_connection) {
+ Init(std::move(connection->pref_store_connection->initial_prefs), true,
+ std::move(connection->pref_store_connection->observer));
+ } else {
+ Init(nullptr, false, nullptr);
+ }
+}
+
+void PersistentPrefStoreClient::QueueWrite(const std::string& key,
+ uint32_t flags) {
+ if (pending_writes_.empty()) {
+ // Use a weak pointer since a pending write should not prolong the life of
+ // |this|. Instead, the destruction of |this| will flush any pending writes.
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
+ FROM_HERE, base::Bind(&PersistentPrefStoreClient::FlushPendingWrites,
+ weak_factory_.GetWeakPtr()));
+ }
+ pending_writes_.insert(std::make_pair(key, flags));
+}
+
+void PersistentPrefStoreClient::FlushPendingWrites() {
+ std::vector<mojom::PrefUpdatePtr> updates;
+ for (const auto& pref : pending_writes_) {
+ const base::Value* value = nullptr;
+ if (GetValue(pref.first, &value)) {
+ updates.push_back(mojom::PrefUpdate::New(
+ pref.first, value->CreateDeepCopy(), pref.second));
+ } else {
+ updates.push_back(
+ mojom::PrefUpdate::New(pref.first, nullptr, pref.second));
+ }
+ }
+ pref_store_->SetValues(std::move(updates));
+ pending_writes_.clear();
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/persistent_pref_store_client.h b/chromium/services/preferences/public/cpp/persistent_pref_store_client.h
new file mode 100644
index 00000000000..e317ec9f163
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/persistent_pref_store_client.h
@@ -0,0 +1,89 @@
+// 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_PREFERENCES_PUBLIC_CPP_PERSISTENT_PREF_STORE_CLIENT_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PERSISTENT_PREF_STORE_CLIENT_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#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"
+
+namespace base {
+class Value;
+}
+
+class PrefRegistry;
+
+namespace prefs {
+
+// An implementation of PersistentPrefStore backed by a
+// mojom::PersistentPrefStore and a mojom::PrefStoreObserver.
+class PersistentPrefStoreClient
+ : public PrefStoreClientMixin<PersistentPrefStore> {
+ public:
+ PersistentPrefStoreClient(
+ mojom::PrefStoreConnectorPtr connector,
+ scoped_refptr<PrefRegistry> pref_registry,
+ std::vector<PrefValueStore::PrefStoreType> already_connected_types);
+
+ explicit PersistentPrefStoreClient(
+ mojom::PersistentPrefStoreConnectionPtr connection);
+
+ // WriteablePrefStore:
+ void SetValue(const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) override;
+ void RemoveValue(const std::string& key, uint32_t flags) override;
+ bool GetMutableValue(const std::string& key, base::Value** result) override;
+ void ReportValueChanged(const std::string& key, uint32_t flags) override;
+ void SetValueSilently(const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) override;
+
+ // PersistentPrefStore:
+ bool ReadOnly() const override;
+ PrefReadError GetReadError() const override;
+ PrefReadError ReadPrefs() override;
+ void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
+ void CommitPendingWrite() override;
+ void SchedulePendingLossyWrites() override;
+ void ClearMutableValues() override;
+
+ protected:
+ // base::RefCounted<PrefStore>:
+ ~PersistentPrefStoreClient() override;
+
+ private:
+ void OnConnect(mojom::PersistentPrefStoreConnectionPtr connection,
+ std::unordered_map<PrefValueStore::PrefStoreType,
+ prefs::mojom::PrefStoreConnectionPtr>
+ other_pref_stores);
+
+ void QueueWrite(const std::string& key, uint32_t flags);
+ void FlushPendingWrites();
+
+ mojom::PrefStoreConnectorPtr connector_;
+ scoped_refptr<PrefRegistry> pref_registry_;
+ bool read_only_ = false;
+ PrefReadError read_error_ = PersistentPrefStore::PREF_READ_ERROR_NONE;
+ mojom::PersistentPrefStorePtr pref_store_;
+ std::map<std::string, uint32_t> pending_writes_;
+
+ std::unique_ptr<ReadErrorDelegate> error_delegate_;
+ std::vector<PrefValueStore::PrefStoreType> already_connected_types_;
+
+ base::WeakPtrFactory<PersistentPrefStoreClient> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(PersistentPrefStoreClient);
+};
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PERSISTENT_PREF_STORE_CLIENT_H_
diff --git a/chromium/services/preferences/public/cpp/pref_client_store.cc b/chromium/services/preferences/public/cpp/pref_client_store.cc
deleted file mode 100644
index 289aaaadd20..00000000000
--- a/chromium/services/preferences/public/cpp/pref_client_store.cc
+++ /dev/null
@@ -1,104 +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/preferences/public/cpp/pref_client_store.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/values.h"
-#include "services/service_manager/public/cpp/connector.h"
-
-namespace preferences {
-
-PrefClientStore::PrefClientStore(
- prefs::mojom::PreferencesServiceFactoryPtr pref_factory_ptr)
- : prefs_binding_(this),
- pref_factory_ptr_(std::move(pref_factory_ptr)),
- initialized_(false) {
- pref_factory_ptr_->Create(prefs_binding_.CreateInterfacePtrAndBind(),
- mojo::MakeRequest(&prefs_service_ptr_));
-}
-
-void PrefClientStore::Subscribe(const std::set<std::string>& keys) {
- keys_.insert(keys.begin(), keys.end());
-
- std::vector<std::string> pref_array;
- std::copy(keys_.begin(), keys_.end(), std::back_inserter(pref_array));
- prefs_service_ptr_->Subscribe(pref_array);
-}
-
-bool PrefClientStore::GetValue(const std::string& key,
- const base::Value** value) const {
- DCHECK(initialized_);
- DCHECK(keys_.find(key) != keys_.end());
-
- return ValueMapPrefStore::GetValue(key, value);
-}
-
-void PrefClientStore::SetValue(const std::string& key,
- std::unique_ptr<base::Value> value,
- uint32_t flags) {
- DCHECK(keys_.find(key) != keys_.end());
-
- // TODO(jonross): only notify the server if the value changed.
- SetValueOnPreferenceManager(key, *value);
- ValueMapPrefStore::SetValue(key, std::move(value), flags);
-}
-
-void PrefClientStore::RemoveValue(const std::string& key, uint32_t flags) {
- // TODO(jonross): add preference removal to preferences.mojom
- NOTIMPLEMENTED();
-}
-
-bool PrefClientStore::GetMutableValue(const std::string& key,
- base::Value** value) {
- DCHECK(initialized_);
- DCHECK(keys_.find(key) != keys_.end());
-
- return ValueMapPrefStore::GetMutableValue(key, value);
-}
-
-void PrefClientStore::ReportValueChanged(const std::string& key,
- uint32_t flags) {
- DCHECK(keys_.find(key) != keys_.end());
- const base::Value* value = nullptr;
- ValueMapPrefStore::GetValue(key, &value);
- SetValueOnPreferenceManager(key, *value);
- ValueMapPrefStore::ReportValueChanged(key, flags);
-}
-
-void PrefClientStore::SetValueSilently(const std::string& key,
- std::unique_ptr<base::Value> value,
- uint32_t flags) {
- SetValueOnPreferenceManager(key, *value);
- ValueMapPrefStore::SetValueSilently(key, std::move(value), flags);
-}
-
-PrefClientStore::~PrefClientStore() {}
-
-void PrefClientStore::SetValueOnPreferenceManager(const std::string& key,
- const base::Value& value) {
- if (keys_.find(key) == keys_.end())
- return;
-
- auto prefs = base::MakeUnique<base::DictionaryValue>();
- prefs->SetWithoutPathExpansion(key, value.CreateDeepCopy());
- prefs_service_ptr_->SetPreferences(std::move(prefs));
-}
-
-void PrefClientStore::OnPreferencesChanged(
- std::unique_ptr<base::DictionaryValue> preferences) {
- if (!initialized_) {
- initialized_ = true;
- NotifyInitializationCompleted();
- }
-
- for (base::DictionaryValue::Iterator it(*preferences); !it.IsAtEnd();
- it.Advance()) {
- if (keys_.find(it.key()) == keys_.end())
- continue;
- ValueMapPrefStore::SetValue(it.key(), it.value().CreateDeepCopy(), 0);
- }
-}
-
-} // namespace preferences
diff --git a/chromium/services/preferences/public/cpp/pref_client_store.h b/chromium/services/preferences/public/cpp/pref_client_store.h
deleted file mode 100644
index c2ac032366c..00000000000
--- a/chromium/services/preferences/public/cpp/pref_client_store.h
+++ /dev/null
@@ -1,82 +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_PREFERENCES_PUBLIC_CPP_PREFS_CLIENT_STORE_H_
-#define SERVICES_PREFERENCES_PUBLIC_CPP_PREFS_CLIENT_STORE_H_
-
-#include <set>
-
-#include "base/macros.h"
-#include "components/prefs/value_map_pref_store.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/preferences/public/interfaces/preferences.mojom.h"
-
-namespace preferences {
-
-class PrefClientStoreTest;
-
-// An implementation of PrefStore which uses prefs::mojom::PreferenceManager as
-// the backing of the preferences.
-//
-// PrefClientStore caches the values locally to provide synchronous access.
-// The cache is empty until the first notification of OnPreferencesChanged is
-// received from the prefs::mojom::PreferenceManager. Upon recieving an initial
-// OnPreferencesChanged initialization will be considered as completed, and any
-// PrefStore::Observer will be notified of OnInitializationCompleted.
-//
-// Currently this does not support RemoveValue.
-class PrefClientStore : public ValueMapPrefStore,
- public prefs::mojom::PreferencesServiceClient {
- public:
- explicit PrefClientStore(
- prefs::mojom::PreferencesServiceFactoryPtr pref_factory_ptr);
-
- // Adds a set of |keys| which PrefClientStore will handle. Begins listening
- // for changes to these from |prefs_service_|.
- void Subscribe(const std::set<std::string>& keys);
-
- // PrefStore:
- bool GetValue(const std::string& key,
- const base::Value** value) const override;
-
- // ValueMapPrefStore:
- void SetValue(const std::string& key,
- std::unique_ptr<base::Value> value,
- uint32_t flags) override;
- void RemoveValue(const std::string& key, uint32_t flags) override;
- bool GetMutableValue(const std::string& key, base::Value** value) override;
- void ReportValueChanged(const std::string& key, uint32_t flags) override;
- void SetValueSilently(const std::string& key,
- std::unique_ptr<base::Value> value,
- uint32_t flags) override;
-
- protected:
- // base::RefCounted<PrefStore>:
- ~PrefClientStore() override;
-
- private:
- friend class PrefClientStoreTest;
-
- // Notifies |prefs_service_| of the change in |key| - |value| pair.
- void SetValueOnPreferenceManager(const std::string& key,
- base::Value const& value);
-
- // prefs::mojom::PreferencesServiceClient:
- void OnPreferencesChanged(
- std::unique_ptr<base::DictionaryValue> preferences) override;
-
- mojo::Binding<prefs::mojom::PreferencesServiceClient> prefs_binding_;
- prefs::mojom::PreferencesServiceFactoryPtr pref_factory_ptr_;
- prefs::mojom::PreferencesServicePtr prefs_service_ptr_;
-
- std::set<std::string> keys_;
-
- // True upon the first OnPreferencesChanged received after Init.
- bool initialized_;
-
- DISALLOW_COPY_AND_ASSIGN(PrefClientStore);
-};
-
-} // namespace preferences
-#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREFS_CLIENT_STORE_H_
diff --git a/chromium/services/preferences/public/cpp/pref_registry_serializer.cc b/chromium/services/preferences/public/cpp/pref_registry_serializer.cc
new file mode 100644
index 00000000000..b64e2c787d4
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_registry_serializer.cc
@@ -0,0 +1,21 @@
+// 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/preferences/public/cpp/pref_registry_serializer.h"
+
+#include "components/prefs/pref_registry.h"
+
+namespace prefs {
+
+mojom::PrefRegistryPtr SerializePrefRegistry(PrefRegistry& pref_registry) {
+ auto registry = mojom::PrefRegistry::New();
+ for (auto& pref : pref_registry) {
+ registry->registrations[pref.first] = mojom::PrefRegistration::New(
+ pref.second->CreateDeepCopy(),
+ pref_registry.GetRegistrationFlags(pref.first));
+ }
+ return registry;
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_registry_serializer.h b/chromium/services/preferences/public/cpp/pref_registry_serializer.h
new file mode 100644
index 00000000000..4e016ce9519
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_registry_serializer.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_PREFERENCES_PUBLIC_CPP_PREF_REGISTRY_SERIALIZER_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_REGISTRY_SERIALIZER_H_
+
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+
+class PrefRegistry;
+
+namespace prefs {
+
+mojom::PrefRegistryPtr SerializePrefRegistry(PrefRegistry& pref_registry);
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_REGISTRY_SERIALIZER_H_
diff --git a/chromium/services/preferences/public/cpp/pref_service_factory.cc b/chromium/services/preferences/public/cpp/pref_service_factory.cc
new file mode 100644
index 00000000000..58ff031c081
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_service_factory.cc
@@ -0,0 +1,116 @@
+// 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/preferences/public/cpp/pref_service_factory.h"
+
+#include "base/callback_helpers.h"
+#include "components/prefs/persistent_pref_store.h"
+#include "components/prefs/pref_notifier_impl.h"
+#include "components/prefs/pref_registry.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/pref_value_store.h"
+#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/service_manager/public/cpp/connector.h"
+
+namespace prefs {
+namespace {
+
+// Used to implement a "fire and forget" pattern where we call an interface
+// method, with an attached error handler, but don't care to hold on to the
+// InterfacePtr after.
+template <typename Interface>
+class RefCountedInterfacePtr
+ : public base::RefCounted<RefCountedInterfacePtr<Interface>> {
+ public:
+ mojo::InterfacePtr<Interface>& get() { return ptr_; }
+ void reset() { ptr_.reset(); }
+
+ private:
+ friend class base::RefCounted<RefCountedInterfacePtr<Interface>>;
+ ~RefCountedInterfacePtr() = default;
+
+ mojo::InterfacePtr<Interface> ptr_;
+};
+
+void DoNothingHandleReadError(PersistentPrefStore::PrefReadError error) {}
+
+scoped_refptr<PrefStore> CreatePrefStore(
+ PrefValueStore::PrefStoreType store_type,
+ std::unordered_map<PrefValueStore::PrefStoreType,
+ mojom::PrefStoreConnectionPtr>* connections) {
+ auto pref_store_it = connections->find(store_type);
+ if (pref_store_it != connections->end()) {
+ return make_scoped_refptr(
+ new PrefStoreClient(std::move(pref_store_it->second)));
+ } else {
+ return nullptr;
+ }
+}
+
+void OnConnect(
+ scoped_refptr<RefCountedInterfacePtr<mojom::PrefStoreConnector>>
+ connector_ptr,
+ scoped_refptr<PrefRegistry> pref_registry,
+ ConnectCallback callback,
+ mojom::PersistentPrefStoreConnectionPtr persistent_pref_store_connection,
+ std::unordered_map<PrefValueStore::PrefStoreType,
+ mojom::PrefStoreConnectionPtr> connections) {
+ scoped_refptr<PrefStore> managed_prefs =
+ CreatePrefStore(PrefValueStore::MANAGED_STORE, &connections);
+ scoped_refptr<PrefStore> supervised_user_prefs =
+ CreatePrefStore(PrefValueStore::SUPERVISED_USER_STORE, &connections);
+ scoped_refptr<PrefStore> extension_prefs =
+ CreatePrefStore(PrefValueStore::EXTENSION_STORE, &connections);
+ scoped_refptr<PrefStore> command_line_prefs =
+ CreatePrefStore(PrefValueStore::COMMAND_LINE_STORE, &connections);
+ scoped_refptr<PrefStore> recommended_prefs =
+ CreatePrefStore(PrefValueStore::RECOMMENDED_STORE, &connections);
+ scoped_refptr<PrefStore> default_prefs =
+ CreatePrefStore(PrefValueStore::DEFAULT_STORE, &connections);
+ scoped_refptr<PersistentPrefStore> persistent_pref_store(
+ new PersistentPrefStoreClient(
+ std::move(persistent_pref_store_connection)));
+ PrefNotifierImpl* pref_notifier = new PrefNotifierImpl();
+ auto* pref_value_store = new PrefValueStore(
+ managed_prefs.get(), supervised_user_prefs.get(), extension_prefs.get(),
+ command_line_prefs.get(), persistent_pref_store.get(),
+ recommended_prefs.get(), default_prefs.get(), pref_notifier);
+ callback.Run(base::MakeUnique<::PrefService>(
+ pref_notifier, pref_value_store, persistent_pref_store.get(),
+ pref_registry.get(), base::Bind(&DoNothingHandleReadError), true));
+ connector_ptr->reset();
+}
+
+void OnConnectError(
+ scoped_refptr<RefCountedInterfacePtr<mojom::PrefStoreConnector>>
+ connector_ptr,
+ ConnectCallback callback) {
+ callback.Run(nullptr);
+ connector_ptr->reset();
+}
+
+} // namespace
+
+void ConnectToPrefService(
+ service_manager::Connector* connector,
+ scoped_refptr<PrefRegistry> pref_registry,
+ const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
+ ConnectCallback callback,
+ base::StringPiece service_name) {
+ auto connector_ptr = make_scoped_refptr(
+ new RefCountedInterfacePtr<mojom::PrefStoreConnector>());
+ connector->BindInterface(service_name.as_string(), &connector_ptr->get());
+ connector_ptr->get().set_connection_error_handler(base::Bind(
+ &OnConnectError, connector_ptr, base::Passed(ConnectCallback{callback})));
+ auto serialized_pref_registry = SerializePrefRegistry(*pref_registry);
+ connector_ptr->get()->Connect(
+ std::move(serialized_pref_registry), already_connected_types,
+ base::Bind(&OnConnect, connector_ptr, base::Passed(&pref_registry),
+ base::Passed(&callback)));
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_service_factory.h b/chromium/services/preferences/public/cpp/pref_service_factory.h
new file mode 100644
index 00000000000..d138ad3583d
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_service_factory.h
@@ -0,0 +1,48 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This provides a way for any service to connect to the pref service to access
+// the application's current preferences.
+
+// Access is provided through a synchronous interface, exposed using the
+// |PrefService| class.
+
+#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREF_SERVICE_FACTORY_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_SERVICE_FACTORY_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "components/prefs/pref_value_store.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+
+class PrefRegistry;
+class PrefService;
+
+namespace service_manager {
+class Connector;
+}
+
+namespace prefs {
+
+// Note that |PrefService| might not be fully initialized yet and thus you need
+// to call |AddPrefInitObserver| on it before using it. Passed |nullptr| on
+// failure.
+using ConnectCallback = base::Callback<void(std::unique_ptr<::PrefService>)>;
+
+// Create a |PrefService| object acting as a client library for the pref
+// service, by connecting to the service using |connector|. Connecting is
+// asynchronous and |callback| will be called when it has been established. All
+// preferences that will be accessed need to be registered in |pref_registry|
+// first.
+void ConnectToPrefService(
+ service_manager::Connector* connector,
+ scoped_refptr<PrefRegistry> pref_registry,
+ const std::vector<PrefValueStore::PrefStoreType>& already_connected_types,
+ ConnectCallback callback,
+ base::StringPiece service_name = mojom::kServiceName);
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_SERVICE_FACTORY_H_
diff --git a/chromium/services/preferences/public/cpp/pref_service_main.cc b/chromium/services/preferences/public/cpp/pref_service_main.cc
new file mode 100644
index 00000000000..b4c92c53060
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_service_main.cc
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#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"
+
+namespace prefs {
+
+std::unique_ptr<service_manager::Service> CreatePrefService(
+ std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
+ scoped_refptr<base::SequencedWorkerPool> worker_pool) {
+ return base::MakeUnique<PrefStoreManagerImpl>(expected_pref_stores,
+ std::move(worker_pool));
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_service_main.h b/chromium/services/preferences/public/cpp/pref_service_main.h
new file mode 100644
index 00000000000..6b51efaf3c1
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_service_main.h
@@ -0,0 +1,30 @@
+// 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_PREFERENCES_PUBLIC_CPP_PREF_SERVICE_MAIN_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_SERVICE_MAIN_H_
+
+#include <memory>
+#include <set>
+
+#include "base/memory/ref_counted.h"
+#include "components/prefs/pref_value_store.h"
+
+namespace base {
+class SequencedWorkerPool;
+}
+
+namespace service_manager {
+class Service;
+}
+
+namespace prefs {
+
+std::unique_ptr<service_manager::Service> CreatePrefService(
+ std::set<PrefValueStore::PrefStoreType> expected_pref_stores,
+ scoped_refptr<base::SequencedWorkerPool> worker_pool);
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_SERVICE_MAIN_H_
diff --git a/chromium/services/preferences/public/cpp/pref_store_adapter.cc b/chromium/services/preferences/public/cpp/pref_store_adapter.cc
new file mode 100644
index 00000000000..2cfe85a9167
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_store_adapter.cc
@@ -0,0 +1,40 @@
+// 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/preferences/public/cpp/pref_store_adapter.h"
+
+namespace prefs {
+
+PrefStoreAdapter::PrefStoreAdapter(scoped_refptr<PrefStore> pref_store,
+ std::unique_ptr<PrefStoreImpl> impl)
+ : pref_store_(std::move(pref_store)), impl_(std::move(impl)) {}
+
+void PrefStoreAdapter::AddObserver(PrefStore::Observer* observer) {
+ pref_store_->AddObserver(observer);
+}
+
+void PrefStoreAdapter::RemoveObserver(PrefStore::Observer* observer) {
+ pref_store_->RemoveObserver(observer);
+}
+
+bool PrefStoreAdapter::HasObservers() const {
+ return pref_store_->HasObservers();
+}
+
+bool PrefStoreAdapter::IsInitializationComplete() const {
+ return pref_store_->IsInitializationComplete();
+}
+
+bool PrefStoreAdapter::GetValue(const std::string& key,
+ const base::Value** result) const {
+ return pref_store_->GetValue(key, result);
+}
+
+std::unique_ptr<base::DictionaryValue> PrefStoreAdapter::GetValues() const {
+ return pref_store_->GetValues();
+}
+
+PrefStoreAdapter::~PrefStoreAdapter() = default;
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_store_adapter.h b/chromium/services/preferences/public/cpp/pref_store_adapter.h
new file mode 100644
index 00000000000..c734606344e
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_store_adapter.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_PREFERENCES_PUBLIC_CPP_PREF_STORE_ADAPTER_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_ADAPTER_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "components/prefs/pref_store.h"
+#include "services/preferences/public/cpp/pref_store_impl.h"
+
+namespace prefs {
+
+// Ties the lifetime of a |PrefStoreImpl| to a |PrefStore|. Otherwise acts as a
+// |PrefStore|, forwarding all calls to the wrapped |PrefStore|.
+class PrefStoreAdapter : public PrefStore {
+ public:
+ PrefStoreAdapter(scoped_refptr<PrefStore> pref_store,
+ std::unique_ptr<PrefStoreImpl> impl);
+
+ // PrefStore:
+ void AddObserver(PrefStore::Observer* observer) override;
+ void RemoveObserver(PrefStore::Observer* observer) override;
+ bool HasObservers() const override;
+ bool IsInitializationComplete() const override;
+ bool GetValue(const std::string& key,
+ const base::Value** result) const override;
+ std::unique_ptr<base::DictionaryValue> GetValues() const override;
+
+ private:
+ ~PrefStoreAdapter() override;
+
+ scoped_refptr<PrefStore> pref_store_;
+ std::unique_ptr<PrefStoreImpl> impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreAdapter);
+};
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_ADAPTER_H_
diff --git a/chromium/services/preferences/public/cpp/pref_store_client.cc b/chromium/services/preferences/public/cpp/pref_store_client.cc
new file mode 100644
index 00000000000..441e8154589
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_store_client.cc
@@ -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.
+
+#include "services/preferences/public/cpp/pref_store_client.h"
+
+#include <utility>
+
+namespace prefs {
+
+PrefStoreClient::PrefStoreClient(mojom::PrefStoreConnectionPtr connection) {
+ Init(std::move(connection->initial_prefs), connection->is_initialized,
+ std::move(connection->observer));
+}
+
+PrefStoreClient::~PrefStoreClient() = default;
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_store_client.h b/chromium/services/preferences/public/cpp/pref_store_client.h
new file mode 100644
index 00000000000..b4d82451100
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_store_client.h
@@ -0,0 +1,34 @@
+// 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_PREFERENCES_PUBLIC_CPP_PREF_STORE_CLIENT_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_CLIENT_H_
+
+#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"
+
+namespace prefs {
+
+// TODO(tibell): Make PrefObserverStore use PrefStoreClient as a base class.
+
+// An implementation of PrefStore which uses prefs::mojom::PrefStore as
+// the backing store of the preferences.
+//
+// PrefStoreClient provides synchronous access to the preferences stored by the
+// backing store by caching them locally.
+class PrefStoreClient : public PrefStoreClientMixin<::PrefStore> {
+ public:
+ explicit PrefStoreClient(mojom::PrefStoreConnectionPtr connection);
+
+ private:
+ ~PrefStoreClient() override;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreClient);
+};
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_CLIENT_H_
diff --git a/chromium/services/preferences/public/cpp/pref_store_client_mixin.cc b/chromium/services/preferences/public/cpp/pref_store_client_mixin.cc
new file mode 100644
index 00000000000..0387883265f
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_store_client_mixin.cc
@@ -0,0 +1,129 @@
+// 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/preferences/public/cpp/pref_store_client_mixin.h"
+
+#include <utility>
+
+#include "base/values.h"
+#include "services/preferences/public/cpp/pref_store_client.h"
+
+namespace prefs {
+
+template <typename BasePrefStore>
+PrefStoreClientMixin<BasePrefStore>::PrefStoreClientMixin()
+ : observer_binding_(this) {}
+
+template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::AddObserver(
+ PrefStore::Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::RemoveObserver(
+ PrefStore::Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+template <typename BasePrefStore>
+bool PrefStoreClientMixin<BasePrefStore>::HasObservers() const {
+ return observers_.might_have_observers();
+}
+
+template <typename BasePrefStore>
+bool PrefStoreClientMixin<BasePrefStore>::IsInitializationComplete() const {
+ return initialized_ && static_cast<bool>(cached_prefs_);
+}
+
+template <typename BasePrefStore>
+bool PrefStoreClientMixin<BasePrefStore>::GetValue(
+ const std::string& key,
+ const base::Value** result) const {
+ DCHECK(initialized_);
+ DCHECK(cached_prefs_);
+ return cached_prefs_->Get(key, result);
+}
+
+template <typename BasePrefStore>
+std::unique_ptr<base::DictionaryValue>
+PrefStoreClientMixin<BasePrefStore>::GetValues() const {
+ DCHECK(initialized_);
+ DCHECK(cached_prefs_);
+ return cached_prefs_->CreateDeepCopy();
+}
+
+template <typename BasePrefStore>
+PrefStoreClientMixin<BasePrefStore>::~PrefStoreClientMixin() = default;
+
+template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::Init(
+ std::unique_ptr<base::DictionaryValue> initial_prefs,
+ bool initialized,
+ mojom::PrefStoreObserverRequest observer_request) {
+ cached_prefs_ = std::move(initial_prefs);
+ observer_binding_.Bind(std::move(observer_request));
+ if (initialized)
+ OnInitializationCompleted(static_cast<bool>(cached_prefs_));
+}
+
+template <typename BasePrefStore>
+base::DictionaryValue& PrefStoreClientMixin<BasePrefStore>::GetMutableValues() {
+ DCHECK(cached_prefs_);
+ return *cached_prefs_;
+}
+
+template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::ReportPrefValueChanged(
+ const std::string& key) {
+ for (auto& observer : observers_)
+ observer.OnPrefValueChanged(key);
+}
+
+template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::OnPrefsChanged(
+ std::vector<mojom::PrefUpdatePtr> updates) {
+ for (const auto& update : updates)
+ OnPrefChanged(update->key, std::move(update->value));
+}
+
+template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::OnInitializationCompleted(
+ bool succeeded) {
+ if (!initialized_) {
+ initialized_ = true;
+ for (auto& observer : observers_)
+ observer.OnInitializationCompleted(succeeded);
+ }
+}
+
+template <typename BasePrefStore>
+void PrefStoreClientMixin<BasePrefStore>::OnPrefChanged(
+ const std::string& key,
+ std::unique_ptr<base::Value> value) {
+ DCHECK(cached_prefs_);
+ bool changed = false;
+ if (!value) { // Delete
+ if (cached_prefs_->RemovePath(key, nullptr))
+ changed = true;
+ } else {
+ const base::Value* prev;
+ if (cached_prefs_->Get(key, &prev)) {
+ if (!prev->Equals(value.get())) {
+ cached_prefs_->Set(key, std::move(value));
+ changed = true;
+ }
+ } else {
+ cached_prefs_->Set(key, std::move(value));
+ changed = true;
+ }
+ }
+ if (changed && initialized_)
+ ReportPrefValueChanged(key);
+}
+
+template class PrefStoreClientMixin<::PrefStore>;
+template class PrefStoreClientMixin<::PersistentPrefStore>;
+
+} // 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
new file mode 100644
index 00000000000..19cf250c586
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_store_client_mixin.h
@@ -0,0 +1,82 @@
+// 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_PREFERENCES_PUBLIC_CPP_PREF_STORE_CLIENT_MIXIN_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_CLIENT_MIXIN_H_
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/observer_list.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/preferences/public/interfaces/preferences.mojom.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+}
+
+namespace prefs {
+
+// An mixin implementation of PrefStore which uses prefs::mojom::PrefStore as
+// the backing store of the preferences.
+//
+// PrefStoreClientMixin provides synchronous access to the preferences stored by
+// the backing store by caching them locally.
+template <typename BasePrefStore>
+class PrefStoreClientMixin : public BasePrefStore,
+ public mojom::PrefStoreObserver {
+ public:
+ PrefStoreClientMixin();
+
+ // BasePrefStore:
+ void AddObserver(PrefStore::Observer* observer) override;
+ void RemoveObserver(PrefStore::Observer* observer) override;
+ bool HasObservers() const override;
+ bool IsInitializationComplete() const override;
+ bool GetValue(const std::string& key,
+ const base::Value** result) const override;
+ std::unique_ptr<base::DictionaryValue> GetValues() const override;
+
+ protected:
+ ~PrefStoreClientMixin() override;
+
+ // Initializes |this|. This must be called before any of the other public or
+ // protected member functions.
+ void Init(std::unique_ptr<base::DictionaryValue> initial_prefs,
+ bool initialized,
+ mojom::PrefStoreObserverRequest observer_request);
+
+ base::DictionaryValue& GetMutableValues();
+ void ReportPrefValueChanged(const std::string& key);
+
+ private:
+ // prefs::mojom::PreferenceObserver:
+ void OnPrefsChanged(std::vector<mojom::PrefUpdatePtr> updates) override;
+ void OnInitializationCompleted(bool succeeded) override;
+
+ void OnPrefChanged(const std::string& key,
+ std::unique_ptr<base::Value> value);
+
+ // Cached preferences.
+ // If null, indicates that initialization failed.
+ std::unique_ptr<base::DictionaryValue> cached_prefs_;
+
+ base::ObserverList<PrefStore::Observer, true> observers_;
+
+ // Has the PrefStore we're observing been initialized?
+ bool initialized_ = false;
+
+ mojo::Binding<mojom::PrefStoreObserver> observer_binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreClientMixin);
+};
+
+extern template class PrefStoreClientMixin<::PrefStore>;
+extern template class PrefStoreClientMixin<::PersistentPrefStore>;
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_CLIENT_MIXIN_H_
diff --git a/chromium/services/preferences/public/cpp/pref_store_impl.cc b/chromium/services/preferences/public/cpp/pref_store_impl.cc
new file mode 100644
index 00000000000..c2289621e7e
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_store_impl.cc
@@ -0,0 +1,113 @@
+// 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/preferences/public/cpp/pref_store_impl.h"
+
+#include <memory>
+#include <unordered_set>
+
+#include "base/stl_util.h"
+#include "base/values.h"
+
+namespace prefs {
+
+class PrefStoreImpl::Observer {
+ public:
+ Observer(mojom::PrefStoreObserverPtr observer,
+ std::unordered_set<std::string> prefs)
+ : observer_(std::move(observer)), prefs_(std::move(prefs)) {}
+
+ void OnInitializationCompleted(bool succeeded) {
+ observer_->OnInitializationCompleted(succeeded);
+ }
+
+ void OnPrefChanged(const std::string& key, const base::Value& value) const {
+ if (!base::ContainsKey(prefs_, key))
+ return;
+
+ std::vector<mojom::PrefUpdatePtr> updates;
+ updates.push_back(mojom::PrefUpdate::New(key, value.CreateDeepCopy(), 0));
+ observer_->OnPrefsChanged(std::move(updates));
+ }
+
+ void OnPrefRemoved(const std::string& key) const {
+ if (!base::ContainsKey(prefs_, key))
+ return;
+
+ std::vector<mojom::PrefUpdatePtr> updates;
+ updates.push_back(mojom::PrefUpdate::New(key, nullptr, 0));
+ observer_->OnPrefsChanged(std::move(updates));
+ }
+
+ private:
+ mojom::PrefStoreObserverPtr observer_;
+ const std::unordered_set<std::string> prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(Observer);
+};
+
+PrefStoreImpl::PrefStoreImpl(scoped_refptr<::PrefStore> pref_store,
+ mojom::PrefStoreRequest request)
+ : backing_pref_store_(std::move(pref_store)),
+ backing_pref_store_initialized_(false),
+ binding_(this, std::move(request)) {
+ DCHECK(backing_pref_store_);
+ if (backing_pref_store_->IsInitializationComplete())
+ OnInitializationCompleted(true);
+ backing_pref_store_->AddObserver(this);
+}
+
+PrefStoreImpl::~PrefStoreImpl() {
+ backing_pref_store_->RemoveObserver(this);
+}
+
+// static
+std::unique_ptr<PrefStoreImpl> PrefStoreImpl::Create(
+ mojom::PrefStoreRegistry* registry_ptr,
+ scoped_refptr<::PrefStore> pref_store,
+ PrefValueStore::PrefStoreType type) {
+ mojom::PrefStorePtr ptr;
+ auto impl = base::MakeUnique<PrefStoreImpl>(std::move(pref_store),
+ mojo::MakeRequest(&ptr));
+ registry_ptr->Register(type, std::move(ptr));
+ return impl;
+}
+
+void PrefStoreImpl::OnPrefValueChanged(const std::string& key) {
+ auto dictionary = base::MakeUnique<base::DictionaryValue>();
+ const base::Value* value = nullptr;
+ if (backing_pref_store_->GetValue(key, &value)) {
+ for (const auto& observer : observers_)
+ observer->OnPrefChanged(key, *value);
+ } else {
+ for (const auto& observer : observers_)
+ observer->OnPrefRemoved(key);
+ }
+}
+
+void PrefStoreImpl::OnInitializationCompleted(bool succeeded) {
+ // Some pref stores call this more than once. We just ignore all calls after
+ // the first.
+ if (backing_pref_store_initialized_)
+ DCHECK(succeeded);
+ backing_pref_store_initialized_ = succeeded;
+ for (const auto& observer : observers_)
+ observer->OnInitializationCompleted(succeeded);
+}
+
+void PrefStoreImpl::AddObserver(
+ const std::vector<std::string>& prefs_to_observe,
+ const AddObserverCallback& callback) {
+ mojom::PrefStoreObserverPtr observer_ptr;
+ auto request = mojo::MakeRequest(&observer_ptr);
+ observers_.push_back(base::MakeUnique<Observer>(
+ std::move(observer_ptr),
+ std::unordered_set<std::string>(prefs_to_observe.begin(),
+ prefs_to_observe.end())));
+ callback.Run(mojom::PrefStoreConnection::New(
+ std::move(request), backing_pref_store_->GetValues(),
+ backing_pref_store_->IsInitializationComplete()));
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/pref_store_impl.h b/chromium/services/preferences/public/cpp/pref_store_impl.h
new file mode 100644
index 00000000000..62146a648c7
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/pref_store_impl.h
@@ -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.
+
+#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#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"
+
+namespace prefs {
+
+// Wraps an actual PrefStore implementation and exposes it as a
+// mojom::PrefStore interface.
+class PrefStoreImpl : public ::PrefStore::Observer, public mojom::PrefStore {
+ public:
+ PrefStoreImpl(scoped_refptr<::PrefStore> pref_store,
+ mojom::PrefStoreRequest request);
+ ~PrefStoreImpl() override;
+
+ // The created instance is registered in and owned by the
+ // |mojom::PrefStoreRegistry|.
+ static std::unique_ptr<PrefStoreImpl> Create(
+ mojom::PrefStoreRegistry* registry_ptr,
+ scoped_refptr<::PrefStore> pref_store,
+ PrefValueStore::PrefStoreType type);
+
+ private:
+ class Observer;
+
+ // PrefStore::Observer:
+ void OnPrefValueChanged(const std::string& key) override;
+ void OnInitializationCompleted(bool succeeded) override;
+
+ // prefs::mojom::PrefStore:
+ void AddObserver(const std::vector<std::string>& prefs_to_observe,
+ const AddObserverCallback& callback) override;
+
+ // The backing store we observer for changes.
+ scoped_refptr<::PrefStore> backing_pref_store_;
+
+ // Observers we notify when |backing_pref_store_| changes.
+ std::vector<std::unique_ptr<Observer>> observers_;
+
+ // True when the |backing_pref_store_| is initialized, either because it was
+ // passed already initialized in the constructor or after
+ // OnInitializationCompleted was called.
+ bool backing_pref_store_initialized_;
+
+ mojo::Binding<mojom::PrefStore> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefStoreImpl);
+};
+
+} // namespace prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREF_STORE_IMPL_H_
diff --git a/chromium/services/preferences/public/cpp/preferences.typemap b/chromium/services/preferences/public/cpp/preferences.typemap
new file mode 100644
index 00000000000..d438bedb829
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/preferences.typemap
@@ -0,0 +1,22 @@
+# 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.
+
+mojom = "//services/preferences/public/interfaces/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" ]
+sources = [
+ "//services/preferences/public/cpp/preferences_struct_traits.cc",
+]
+deps = [
+ "//components/prefs",
+]
+
+type_mappings = [
+ "prefs.mojom.PersistentPrefStoreConnection.ReadError=::PersistentPrefStore::PrefReadError",
+ "prefs.mojom.PrefStoreType=::PrefValueStore::PrefStoreType",
+]
diff --git a/chromium/services/preferences/public/cpp/preferences_struct_traits.cc b/chromium/services/preferences/public/cpp/preferences_struct_traits.cc
new file mode 100644
index 00000000000..4d22db121f9
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/preferences_struct_traits.cc
@@ -0,0 +1,136 @@
+// 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/preferences/public/cpp/preferences_struct_traits.h"
+
+namespace mojo {
+
+using PrefStoreType = prefs::mojom::PrefStoreType;
+
+PrefStoreType EnumTraits<PrefStoreType, PrefValueStore::PrefStoreType>::ToMojom(
+ PrefValueStore::PrefStoreType input) {
+ switch (input) {
+ case PrefValueStore::INVALID_STORE:
+ break;
+ case PrefValueStore::MANAGED_STORE:
+ return PrefStoreType::MANAGED;
+ case PrefValueStore::SUPERVISED_USER_STORE:
+ return PrefStoreType::SUPERVISED_USER;
+ case PrefValueStore::EXTENSION_STORE:
+ return PrefStoreType::EXTENSION;
+ case PrefValueStore::COMMAND_LINE_STORE:
+ return PrefStoreType::COMMAND_LINE;
+ case PrefValueStore::USER_STORE:
+ return PrefStoreType::USER;
+ case PrefValueStore::RECOMMENDED_STORE:
+ return PrefStoreType::RECOMMENDED;
+ case PrefValueStore::DEFAULT_STORE:
+ return PrefStoreType::DEFAULT;
+ }
+ NOTREACHED();
+ return {};
+}
+
+bool EnumTraits<PrefStoreType, PrefValueStore::PrefStoreType>::FromMojom(
+ PrefStoreType input,
+ PrefValueStore::PrefStoreType* output) {
+ switch (input) {
+ case PrefStoreType::MANAGED:
+ *output = PrefValueStore::MANAGED_STORE;
+ return true;
+ case PrefStoreType::SUPERVISED_USER:
+ *output = PrefValueStore::SUPERVISED_USER_STORE;
+ return true;
+ case PrefStoreType::EXTENSION:
+ *output = PrefValueStore::EXTENSION_STORE;
+ return true;
+ case PrefStoreType::COMMAND_LINE:
+ *output = PrefValueStore::COMMAND_LINE_STORE;
+ return true;
+ case PrefStoreType::USER:
+ *output = PrefValueStore::USER_STORE;
+ return true;
+ case PrefStoreType::RECOMMENDED:
+ *output = PrefValueStore::RECOMMENDED_STORE;
+ return true;
+ case PrefStoreType::DEFAULT:
+ *output = PrefValueStore::DEFAULT_STORE;
+ return true;
+ }
+ return false;
+}
+
+using MojomReadError = prefs::mojom::PersistentPrefStoreConnection_ReadError;
+
+MojomReadError
+EnumTraits<MojomReadError, PersistentPrefStore::PrefReadError>::ToMojom(
+ PersistentPrefStore::PrefReadError input) {
+ switch (input) {
+ case PersistentPrefStore::PREF_READ_ERROR_NONE:
+ return MojomReadError::NONE;
+ case PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE:
+ return MojomReadError::JSON_PARSE;
+ case PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE:
+ return MojomReadError::JSON_TYPE;
+ case PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED:
+ return MojomReadError::ACCESS_DENIED;
+ case PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER:
+ return MojomReadError::FILE_OTHER;
+ case PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED:
+ return MojomReadError::FILE_LOCKED;
+ case PersistentPrefStore::PREF_READ_ERROR_NO_FILE:
+ return MojomReadError::NO_FILE;
+ case PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT:
+ return MojomReadError::JSON_REPEAT;
+ case PersistentPrefStore::PREF_READ_ERROR_FILE_NOT_SPECIFIED:
+ return MojomReadError::FILE_NOT_SPECIFIED;
+ case PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE:
+ return MojomReadError::ASYNCHRONOUS_TASK_INCOMPLETE;
+ case PersistentPrefStore::PREF_READ_ERROR_MAX_ENUM:
+ break;
+ }
+ NOTREACHED();
+ return {};
+}
+
+bool EnumTraits<MojomReadError, PersistentPrefStore::PrefReadError>::FromMojom(
+ MojomReadError input,
+ PersistentPrefStore::PrefReadError* output) {
+ switch (input) {
+ case MojomReadError::NONE:
+ *output = PersistentPrefStore::PREF_READ_ERROR_NONE;
+ return true;
+ case MojomReadError::JSON_PARSE:
+ *output = PersistentPrefStore::PREF_READ_ERROR_JSON_PARSE;
+ return true;
+ case MojomReadError::JSON_TYPE:
+ *output = PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE;
+ return true;
+ case MojomReadError::ACCESS_DENIED:
+ *output = PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED;
+ return true;
+ case MojomReadError::FILE_OTHER:
+ *output = PersistentPrefStore::PREF_READ_ERROR_FILE_OTHER;
+ return true;
+ case MojomReadError::FILE_LOCKED:
+ *output = PersistentPrefStore::PREF_READ_ERROR_FILE_LOCKED;
+ return true;
+ case MojomReadError::NO_FILE:
+ *output = PersistentPrefStore::PREF_READ_ERROR_NO_FILE;
+ return true;
+ case MojomReadError::JSON_REPEAT:
+ *output = PersistentPrefStore::PREF_READ_ERROR_JSON_REPEAT;
+ return true;
+ case MojomReadError::FILE_NOT_SPECIFIED:
+ *output = PersistentPrefStore::PREF_READ_ERROR_FILE_NOT_SPECIFIED;
+ return true;
+ case MojomReadError::ASYNCHRONOUS_TASK_INCOMPLETE:
+ *output =
+ PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE;
+ return true;
+ }
+ return false;
+}
+
+} // namespace mojo
diff --git a/chromium/services/preferences/public/cpp/preferences_struct_traits.h b/chromium/services/preferences/public/cpp/preferences_struct_traits.h
new file mode 100644
index 00000000000..194d2748b24
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/preferences_struct_traits.h
@@ -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.
+
+#ifndef SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_STRUCT_TRAITS_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_STRUCT_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"
+
+namespace mojo {
+
+template <>
+struct EnumTraits<::prefs::mojom::PrefStoreType,
+ ::PrefValueStore::PrefStoreType> {
+ static prefs::mojom::PrefStoreType ToMojom(
+ PrefValueStore::PrefStoreType input);
+
+ static bool FromMojom(prefs::mojom::PrefStoreType input,
+ PrefValueStore::PrefStoreType* output);
+};
+
+template <>
+struct EnumTraits<::prefs::mojom::PersistentPrefStoreConnection_ReadError,
+ ::PersistentPrefStore::PrefReadError> {
+ static prefs::mojom::PersistentPrefStoreConnection_ReadError ToMojom(
+ PersistentPrefStore::PrefReadError input);
+
+ static bool FromMojom(
+ prefs::mojom::PersistentPrefStoreConnection_ReadError input,
+ PersistentPrefStore::PrefReadError* output);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_PREFERENCES_STRUCT_TRAITS_H_
diff --git a/chromium/services/preferences/public/cpp/tests/BUILD.gn b/chromium/services/preferences/public/cpp/tests/BUILD.gn
index 1c818cbff4d..bbe7e02055a 100644
--- a/chromium/services/preferences/public/cpp/tests/BUILD.gn
+++ b/chromium/services/preferences/public/cpp/tests/BUILD.gn
@@ -2,28 +2,20 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/config/ui.gni")
-import("//testing/test.gni")
-
-group("tests") {
+source_set("tests") {
testonly = true
- deps = [
- ":preferences_unittests",
- ]
-}
-
-test("preferences_unittests") {
sources = [
- "pref_client_store_unittest.cc",
+ "pref_store_client_unittest.cc",
+ "pref_store_impl_unittest.cc",
]
deps = [
"//base",
"//base/test:test_support",
"//components/prefs:test_support",
- "//mojo/edk/test:run_all_unittests",
"//mojo/public/cpp/bindings:bindings",
"//services/preferences/public/cpp",
"//services/preferences/public/interfaces",
+ "//testing/gmock",
"//testing/gtest",
]
}
diff --git a/chromium/services/preferences/public/cpp/tracked/BUILD.gn b/chromium/services/preferences/public/cpp/tracked/BUILD.gn
new file mode 100644
index 00000000000..ddcc14d0e40
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/BUILD.gn
@@ -0,0 +1,33 @@
+# 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.
+
+static_library("tracked") {
+ sources = [
+ "configuration.cc",
+ "configuration.h",
+ "pref_names.cc",
+ "pref_names.h",
+ "tracked_preference_histogram_names.cc",
+ "tracked_preference_histogram_names.h",
+ ]
+ public_deps = [
+ "//services/preferences/public/interfaces",
+ ]
+ deps = [
+ "//base",
+ ]
+}
+
+static_library("test_support") {
+ testonly = true
+ sources = [
+ "mock_validation_delegate.cc",
+ "mock_validation_delegate.h",
+ ]
+
+ deps = [
+ "//base",
+ "//services/preferences/public/interfaces",
+ ]
+}
diff --git a/chromium/services/preferences/public/cpp/tracked/OWNERS b/chromium/services/preferences/public/cpp/tracked/OWNERS
new file mode 100644
index 00000000000..2845b0f366d
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/OWNERS
@@ -0,0 +1,2 @@
+bauerb@chromium.org
+gab@chromium.org
diff --git a/chromium/services/preferences/public/cpp/tracked/configuration.cc b/chromium/services/preferences/public/cpp/tracked/configuration.cc
new file mode 100644
index 00000000000..f49adeab640
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/configuration.cc
@@ -0,0 +1,25 @@
+// 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/preferences/public/cpp/tracked/configuration.h"
+
+namespace prefs {
+
+mojom::TrackedPreferenceMetadataPtr ConstructTrackedMetadata(
+ const TrackedPreferenceMetadata& metadata) {
+ return mojom::TrackedPreferenceMetadata::New(
+ metadata.reporting_id, metadata.name, metadata.enforcement_level,
+ metadata.strategy, metadata.value_type);
+}
+
+std::vector<mojom::TrackedPreferenceMetadataPtr> CloneTrackedConfiguration(
+ const std::vector<mojom::TrackedPreferenceMetadataPtr>& configuration) {
+ std::vector<mojom::TrackedPreferenceMetadataPtr> result;
+ for (const auto& metadata : configuration) {
+ result.push_back(metadata.Clone());
+ }
+ return result;
+}
+
+} // namespace prefs
diff --git a/chromium/services/preferences/public/cpp/tracked/configuration.h b/chromium/services/preferences/public/cpp/tracked/configuration.h
new file mode 100644
index 00000000000..bbb0ebff4ca
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/configuration.h
@@ -0,0 +1,37 @@
+// 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_PREFERENCES_PUBLIC_CPP_TRACKED_CONFIGURATION_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_CONFIGURATION_H_
+
+#include "services/preferences/public/interfaces/preferences_configuration.mojom.h"
+
+namespace prefs {
+
+struct TrackedPreferenceMetadata {
+ size_t reporting_id;
+ const char* name;
+ mojom::TrackedPreferenceMetadata::EnforcementLevel enforcement_level;
+ mojom::TrackedPreferenceMetadata::PrefTrackingStrategy strategy;
+ mojom::TrackedPreferenceMetadata::ValueType value_type;
+};
+
+mojom::TrackedPreferenceMetadataPtr ConstructTrackedMetadata(
+ const TrackedPreferenceMetadata& metadata);
+
+template <typename ConfigurationContainer>
+std::vector<mojom::TrackedPreferenceMetadataPtr> ConstructTrackedConfiguration(
+ const ConfigurationContainer& configuration) {
+ std::vector<mojom::TrackedPreferenceMetadataPtr> result;
+ for (auto metadata : configuration) {
+ result.push_back(ConstructTrackedMetadata(metadata));
+ }
+ return result;
+}
+
+std::vector<mojom::TrackedPreferenceMetadataPtr> CloneTrackedConfiguration(
+ const std::vector<mojom::TrackedPreferenceMetadataPtr>& configuration);
+
+} // namespace prefs
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_CONFIGURATION_H_
diff --git a/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.cc b/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.cc
new file mode 100644
index 00000000000..f26ff4f001f
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.cc
@@ -0,0 +1,84 @@
+// 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/preferences/public/cpp/tracked/mock_validation_delegate.h"
+
+MockValidationDelegateRecord::MockValidationDelegateRecord() = default;
+
+MockValidationDelegateRecord::~MockValidationDelegateRecord() = default;
+
+size_t MockValidationDelegateRecord::CountValidationsOfState(
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state)
+ const {
+ size_t count = 0;
+ for (size_t i = 0; i < validations_.size(); ++i) {
+ if (validations_[i].value_state == value_state)
+ ++count;
+ }
+ return count;
+}
+
+size_t MockValidationDelegateRecord::CountExternalValidationsOfState(
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state)
+ const {
+ size_t count = 0;
+ for (size_t i = 0; i < validations_.size(); ++i) {
+ if (validations_[i].external_validation_value_state == value_state)
+ ++count;
+ }
+ return count;
+}
+
+const MockValidationDelegateRecord::ValidationEvent*
+MockValidationDelegateRecord::GetEventForPath(
+ const std::string& pref_path) const {
+ for (size_t i = 0; i < validations_.size(); ++i) {
+ if (validations_[i].pref_path == pref_path)
+ return &validations_[i];
+ }
+ return NULL;
+}
+
+void MockValidationDelegateRecord::RecordValidation(
+ const std::string& pref_path,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_value_state,
+ bool is_personal,
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy strategy) {
+ validations_.push_back(ValidationEvent(pref_path, value_state,
+ external_validation_value_state,
+ is_personal, strategy));
+}
+
+MockValidationDelegate::MockValidationDelegate(
+ scoped_refptr<MockValidationDelegateRecord> record)
+ : record_(std::move(record)) {}
+
+MockValidationDelegate::~MockValidationDelegate() = default;
+
+void MockValidationDelegate::OnAtomicPreferenceValidation(
+ const std::string& pref_path,
+ std::unique_ptr<base::Value> value,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_value_state,
+ bool is_personal) {
+ record_->RecordValidation(
+ pref_path, value_state, external_validation_value_state, is_personal,
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy::ATOMIC);
+}
+
+void MockValidationDelegate::OnSplitPreferenceValidation(
+ const std::string& pref_path,
+ const std::vector<std::string>& invalid_keys,
+ const std::vector<std::string>& external_validation_invalid_keys,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_value_state,
+ bool is_personal) {
+ record_->RecordValidation(
+ pref_path, value_state, external_validation_value_state, is_personal,
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy::SPLIT);
+}
diff --git a/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h b/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h
new file mode 100644
index 00000000000..5538c69301f
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/mock_validation_delegate.h
@@ -0,0 +1,124 @@
+// 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_PREFERENCES_PUBLIC_CPP_TRACKED_MOCK_VALIDATION_DELEGATE_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_MOCK_VALIDATION_DELEGATE_H_
+
+#include <stddef.h>
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "services/preferences/public/interfaces/preferences_configuration.mojom.h"
+#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+
+class MockValidationDelegate;
+
+// A mock tracked preference validation delegate for use by tests.
+class MockValidationDelegateRecord
+ : public base::RefCounted<MockValidationDelegateRecord> {
+ public:
+ struct ValidationEvent {
+ ValidationEvent(
+ const std::string& path,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState state,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_state,
+ bool is_personal,
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy
+ tracking_strategy)
+ : pref_path(path),
+ value_state(state),
+ external_validation_value_state(external_validation_state),
+ is_personal(is_personal),
+ strategy(tracking_strategy) {}
+
+ std::string pref_path;
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state;
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_value_state;
+ bool is_personal;
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy strategy;
+ };
+
+ MockValidationDelegateRecord();
+
+ // Returns the number of recorded validations.
+ size_t recorded_validations_count() const { return validations_.size(); }
+
+ // Returns the number of validations of a given value state.
+ size_t CountValidationsOfState(
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state)
+ const;
+
+ // Returns the number of external validations of a given value state.
+ size_t CountExternalValidationsOfState(
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state)
+ const;
+
+ // Returns the event for the preference with a given path.
+ const ValidationEvent* GetEventForPath(const std::string& pref_path) const;
+
+ private:
+ friend class MockValidationDelegate;
+ friend class base::RefCounted<MockValidationDelegateRecord>;
+
+ ~MockValidationDelegateRecord();
+
+ // Adds a new validation event.
+ void RecordValidation(
+ const std::string& pref_path,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_value_state,
+ bool is_personal,
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy strategy);
+
+ std::vector<ValidationEvent> validations_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockValidationDelegateRecord);
+};
+
+class MockValidationDelegate
+ : public prefs::mojom::TrackedPreferenceValidationDelegate {
+ public:
+ explicit MockValidationDelegate(
+ scoped_refptr<MockValidationDelegateRecord> record);
+ ~MockValidationDelegate() override;
+
+ // TrackedPreferenceValidationDelegate implementation.
+ void OnAtomicPreferenceValidation(
+ const std::string& pref_path,
+ std::unique_ptr<base::Value> value,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_value_state,
+ bool is_personal) override;
+ void OnSplitPreferenceValidation(
+ const std::string& pref_path,
+ const std::vector<std::string>& invalid_keys,
+ const std::vector<std::string>& external_validation_invalid_keys,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_value_state,
+ bool is_personal) override;
+
+ private:
+ // Adds a new validation event.
+ void RecordValidation(
+ const std::string& pref_path,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state,
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ external_validation_value_state,
+ bool is_personal,
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy strategy);
+
+ scoped_refptr<MockValidationDelegateRecord> record_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockValidationDelegate);
+};
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_MOCK_VALIDATION_DELEGATE_H_
diff --git a/chromium/services/preferences/public/cpp/tracked/pref_names.cc b/chromium/services/preferences/public/cpp/tracked/pref_names.cc
new file mode 100644
index 00000000000..59446c8a3f5
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/pref_names.cc
@@ -0,0 +1,13 @@
+// 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/preferences/public/cpp/tracked/pref_names.h"
+
+namespace user_prefs {
+
+// A timestamp (stored in base::Time::ToInternalValue format) of the last time
+// a preference was reset.
+const char kPreferenceResetTime[] = "prefs.preference_reset_time";
+
+} // namespace user_prefs
diff --git a/chromium/services/preferences/public/cpp/tracked/pref_names.h b/chromium/services/preferences/public/cpp/tracked/pref_names.h
new file mode 100644
index 00000000000..2f594f5059f
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/pref_names.h
@@ -0,0 +1,14 @@
+// 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_PREFERENCES_PUBLIC_CPP_TRACKED_PREF_NAMES_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_PREF_NAMES_H_
+
+namespace user_prefs {
+
+extern const char kPreferenceResetTime[];
+
+} // namespace user_prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_PREF_NAMES_H_
diff --git a/chromium/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.cc b/chromium/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.cc
new file mode 100644
index 00000000000..7478db56b7f
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.cc
@@ -0,0 +1,31 @@
+// 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/preferences/public/cpp/tracked/tracked_preference_histogram_names.h"
+
+namespace user_prefs {
+namespace tracked {
+
+// Tracked pref histogram names.
+const char kTrackedPrefHistogramUnchanged[] =
+ "Settings.TrackedPreferenceUnchanged";
+const char kTrackedPrefHistogramCleared[] = "Settings.TrackedPreferenceCleared";
+const char kTrackedPrefHistogramMigratedLegacyDeviceId[] =
+ "Settings.TrackedPreferenceMigratedLegacyDeviceId";
+const char kTrackedPrefHistogramChanged[] = "Settings.TrackedPreferenceChanged";
+const char kTrackedPrefHistogramInitialized[] =
+ "Settings.TrackedPreferenceInitialized";
+const char kTrackedPrefHistogramTrustedInitialized[] =
+ "Settings.TrackedPreferenceTrustedInitialized";
+const char kTrackedPrefHistogramNullInitialized[] =
+ "Settings.TrackedPreferenceNullInitialized";
+const char kTrackedPrefHistogramWantedReset[] =
+ "Settings.TrackedPreferenceWantedReset";
+const char kTrackedPrefHistogramReset[] = "Settings.TrackedPreferenceReset";
+const char kTrackedSplitPrefHistogramChanged[] =
+ "Settings.TrackedSplitPreferenceChanged.";
+const char kTrackedPrefRegistryValidationSuffix[] = "FromRegistry";
+
+} // namespace tracked
+} // namespace user_prefs
diff --git a/chromium/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h b/chromium/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h
new file mode 100644
index 00000000000..ec0a219db58
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h
@@ -0,0 +1,26 @@
+// 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_PREFERENCES_PUBLIC_CPP_TRACKED_TRACKED_PREFERENCE_HISTOGRAM_NAMES_H_
+#define SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_TRACKED_PREFERENCE_HISTOGRAM_NAMES_H_
+
+namespace user_prefs {
+namespace tracked {
+
+extern const char kTrackedPrefHistogramUnchanged[];
+extern const char kTrackedPrefHistogramCleared[];
+extern const char kTrackedPrefHistogramMigratedLegacyDeviceId[];
+extern const char kTrackedPrefHistogramChanged[];
+extern const char kTrackedPrefHistogramInitialized[];
+extern const char kTrackedPrefHistogramTrustedInitialized[];
+extern const char kTrackedPrefHistogramNullInitialized[];
+extern const char kTrackedPrefHistogramWantedReset[];
+extern const char kTrackedPrefHistogramReset[];
+extern const char kTrackedSplitPrefHistogramChanged[];
+extern const char kTrackedPrefRegistryValidationSuffix[];
+
+} // namespace tracked
+} // namespace user_prefs
+
+#endif // SERVICES_PREFERENCES_PUBLIC_CPP_TRACKED_TRACKED_PREFERENCE_HISTOGRAM_NAMES_H_
diff --git a/chromium/services/preferences/public/cpp/typemaps.gni b/chromium/services/preferences/public/cpp/typemaps.gni
new file mode 100644
index 00000000000..2238fb6e9e7
--- /dev/null
+++ b/chromium/services/preferences/public/cpp/typemaps.gni
@@ -0,0 +1,5 @@
+# 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.
+
+typemaps = [ "//services/preferences/public/cpp/preferences.typemap" ]
diff --git a/chromium/services/preferences/public/interfaces/BUILD.gn b/chromium/services/preferences/public/interfaces/BUILD.gn
index c7e9091f046..8bc3749fe60 100644
--- a/chromium/services/preferences/public/interfaces/BUILD.gn
+++ b/chromium/services/preferences/public/interfaces/BUILD.gn
@@ -7,6 +7,8 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("interfaces") {
sources = [
"preferences.mojom",
+ "preferences_configuration.mojom",
+ "tracked_preference_validation_delegate.mojom",
]
public_deps = [
"//mojo/common:common_custom_types",
diff --git a/chromium/services/preferences/public/interfaces/preferences.mojom b/chromium/services/preferences/public/interfaces/preferences.mojom
index 1978e4b671f..47a79dc5386 100644
--- a/chromium/services/preferences/public/interfaces/preferences.mojom
+++ b/chromium/services/preferences/public/interfaces/preferences.mojom
@@ -5,25 +5,137 @@
module prefs.mojom;
import "mojo/common/values.mojom";
+import "services/preferences/public/interfaces/preferences_configuration.mojom";
const string kServiceName = "preferences";
+const string kForwarderServiceName = "preferences_forwarder";
-// Used for the creation of a PreferencesService and to ensure that the
-// PreferencesServiceClient is bound at creation time.
-interface PreferencesServiceFactory {
- // Creates a PreferencesService bound to the provided |observer|.
- Create(PreferencesServiceClient observer, PreferencesService& service);
+// The know pref store types.
+//
+// Should be kept in sync with PrefValueStore::PrefStoreType.
+enum PrefStoreType {
+ MANAGED,
+ SUPERVISED_USER,
+ EXTENSION,
+ COMMAND_LINE,
+ USER,
+ RECOMMENDED,
+ DEFAULT,
};
-// Used to subscribe to preference changes within PreferenceManager. After
-// requesting to observe, the current values for all requested keys are sent.
-interface PreferencesServiceClient {
- OnPreferencesChanged(mojo.common.mojom.DictionaryValue preferences);
+// Allows observing changes to prefs stored in a |PrefStore|.
+interface PrefStoreObserver {
+ // Preferences have been changed.
+ OnPrefsChanged(array<PrefUpdate> updates);
+
+ // The PrefStore has been initialized (asynchronously).
+ OnInitializationCompleted(bool succeeded);
+};
+
+// Captures the connections to a PrefStore by supplying the initial state of the
+// store and a handle to receive notifications on.
+struct PrefStoreConnection {
+ // Handle to receive updates on.
+ PrefStoreObserver& observer;
+
+ // Initial values of the PrefStore. These will not be communicated through
+ // OnPrefChanged.
+ mojo.common.mojom.DictionaryValue initial_prefs;
+
+ // Is the PrefStore initialized? If not it should not be used before
+ // OnInitializationCompleted has been called.
+ bool is_initialized;
+};
+
+struct PersistentPrefStoreConnection {
+ enum ReadError {
+ NONE = 0,
+ JSON_PARSE = 1,
+ JSON_TYPE = 2,
+ ACCESS_DENIED = 3,
+ FILE_OTHER = 4,
+ FILE_LOCKED = 5,
+ NO_FILE = 6,
+ JSON_REPEAT = 7,
+ // OTHER = 8, // Deprecated.
+ FILE_NOT_SPECIFIED = 9,
+ ASYNCHRONOUS_TASK_INCOMPLETE = 10,
+ };
+
+ PrefStoreConnection? pref_store_connection;
+ PersistentPrefStore? pref_store;
+ ReadError read_error;
+ bool read_only;
+};
+
+// Manages actual read of preference data. Accepts observers who subscribe to
+// preferences, notifying them of changes.
+interface PrefStore {
+ // Add an observer of changes to prefs contained in |prefs_to_observe|. This
+ // current values of all prefs will not be communicated through a call to
+ // |observer| but instead be returned in |initial_prefs|.
+ AddObserver(array<string> prefs_to_observe) => (
+ PrefStoreConnection connection);
+};
+
+// Manages a registry of all pref stores. Registered pref stores can be
+// connected to through the |PrefStoreConnector| interface.
+interface PrefStoreRegistry {
+ // Register a pref store.
+ Register(PrefStoreType type, PrefStore pref_store);
+};
+
+// Allows connections to pref stores registered with |PrefStoreRegistry|.
+interface PrefStoreConnector {
+ // Connect to all registered pref stores, retrieving the current values of all
+ // prefs in each store and an |observer| interfaces through which updates can
+ // be received. The client asserts that it is already connected to the
+ // |already_connected_types| pref stores through some other means, so the
+ // Connect call will not connect to those.
+ [Sync]
+ Connect(PrefRegistry pref_registry,
+ array<PrefStoreType> already_connected_types) =>
+ (PersistentPrefStoreConnection connection,
+ map<PrefStoreType, PrefStoreConnection> connections);
+};
+
+// An update to a pref.
+struct PrefUpdate {
+ // The key of the pref being updated.
+ string key;
+ // The new value; a null |value| indicates a delete.
+ mojo.common.mojom.Value? value;
+ //|flags| is a bitmask of WritablePrefStore::PrefWriteFlags.
+ uint32 flags;
+};
+
+// An interface providing mutation access to a PersistentPrefStore.
+interface PersistentPrefStore {
+ // Sets the values for prefs.
+ SetValues(array<PrefUpdate> updates);
+
+ // These mirror the C++ PersistentPrefStore methods.
+ CommitPendingWrite();
+ SchedulePendingLossyWrites();
+ ClearMutableValues();
+};
+
+// A registry of all prefs registered by a single client.
+struct PrefRegistry {
+ map<string, PrefRegistration> registrations;
+};
+
+struct PrefRegistration {
+ mojo.common.mojom.Value default_value;
+
+ // A bitfield of flags. Flag values are defined in
+ // PrefRegistry::PrefRegistrationFlags and
+ // PrefRegistrySyncable::PrefRegistrationFlags.
+ uint32 flags;
};
-// Manages actual read/write of preference data. Accepts observers who subscribe
-// to preferences, notifying them of changes.
-interface PreferencesService {
- SetPreferences(mojo.common.mojom.DictionaryValue preferences);
- Subscribe(array<string> preferences);
+interface PrefServiceControl {
+ // Initializes the pref service. This must be called before the service can
+ // be used.
+ Init(PersistentPrefStoreConfiguration configuration);
};
diff --git a/chromium/services/preferences/public/interfaces/preferences_configuration.mojom b/chromium/services/preferences/public/interfaces/preferences_configuration.mojom
new file mode 100644
index 00000000000..76f7785ae06
--- /dev/null
+++ b/chromium/services/preferences/public/interfaces/preferences_configuration.mojom
@@ -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.
+
+module prefs.mojom;
+
+import "mojo/common/file_path.mojom";
+import "mojo/common/string16.mojom";
+import "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom";
+
+union PersistentPrefStoreConfiguration {
+ SimplePersistentPrefStoreConfiguration simple_configuration;
+ TrackedPersistentPrefStoreConfiguration tracked_configuration;
+};
+
+struct SimplePersistentPrefStoreConfiguration {
+ mojo.common.mojom.FilePath pref_filename;
+};
+
+// These parameters are passed to prefs::CreateTrackedPersistentPrefStore() in
+// services/preferences/persistent_pref_store_factory.cc.
+struct TrackedPersistentPrefStoreConfiguration {
+ mojo.common.mojom.FilePath unprotected_pref_filename;
+ mojo.common.mojom.FilePath protected_pref_filename;
+ array<TrackedPreferenceMetadata> tracking_configuration;
+ uint64 reporting_ids_count;
+ string seed;
+ string legacy_device_id;
+ string registry_seed;
+ mojo.common.mojom.String16 registry_path;
+ TrackedPreferenceValidationDelegate? validation_delegate;
+ ResetOnLoadObserver? reset_on_load_observer;
+};
+
+struct TrackedPreferenceMetadata {
+ enum EnforcementLevel { NO_ENFORCEMENT, ENFORCE_ON_LOAD };
+
+ enum PrefTrackingStrategy {
+ // Atomic preferences are tracked as a whole.
+ ATOMIC,
+ // Split preferences are dictionaries for which each top-level entry is
+ // tracked independently. Note: preferences using this strategy must be kept
+ // in sync with TrackedSplitPreferences in histograms.xml.
+ SPLIT,
+ };
+
+ enum ValueType {
+ IMPERSONAL,
+ // The preference value may contain personal information.
+ PERSONAL,
+ };
+
+ uint64 reporting_id;
+ string name;
+ EnforcementLevel enforcement_level;
+ PrefTrackingStrategy strategy;
+ ValueType value_type;
+};
+
+interface ResetOnLoadObserver {
+ OnResetOnLoad();
+};
diff --git a/chromium/services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom b/chromium/services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom
new file mode 100644
index 00000000000..370f95f75d9
--- /dev/null
+++ b/chromium/services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom
@@ -0,0 +1,56 @@
+// 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 prefs.mojom;
+
+import "mojo/common/values.mojom";
+
+// A TrackedPreferenceValidationDelegate is notified of the results of each
+// tracked preference validation event.
+interface TrackedPreferenceValidationDelegate {
+ enum ValueState {
+ // The preference value corresponds to its stored hash.
+ UNCHANGED,
+ // The preference has been cleared since the last hash.
+ CLEARED,
+ // The preference value corresponds to its stored hash, but the hash was
+ // calculated using a deprecated hash algorithm which is just as safe as
+ // the current one.
+ SECURE_LEGACY,
+ // The preference value has been changed since the last hash.
+ CHANGED,
+ // No stored hash exists for the preference value.
+ UNTRUSTED_UNKNOWN_VALUE,
+ // No stored hash exists for the preference value, but the current set of
+ // hashes stored is trusted and thus this value can safely be seeded. This
+ // happens when all hashes are already properly seeded and a newly
+ // tracked value needs to be seeded).
+ TRUSTED_UNKNOWN_VALUE,
+ // Null values are inherently trusted.
+ TRUSTED_NULL_VALUE,
+ // This transaction's store type is not supported.
+ UNSUPPORTED,
+ };
+
+ // Notifies observes of the result (|value_state|) of checking the atomic
+ // |value| (which may be null) at |pref_path|. |is_personal| indicates whether
+ // or not the value may contain personal information.
+ OnAtomicPreferenceValidation(
+ string pref_path,
+ mojo.common.mojom.Value? value,
+ ValueState value_state,
+ ValueState external_validation_value_state,
+ bool is_personal);
+
+ // Notifies observes of the result (|value_state|) of checking the split
+ // value at |pref_path|. |is_personal| indicates whether or not the value may
+ // contain personal information.
+ OnSplitPreferenceValidation(
+ string pref_path,
+ array<string> invalid_keys,
+ array<string> external_validation_invalid_keys,
+ ValueState value_state,
+ ValueState external_validation_value_state,
+ bool is_personal);
+};
diff --git a/chromium/services/preferences/tracked/BUILD.gn b/chromium/services/preferences/tracked/BUILD.gn
new file mode 100644
index 00000000000..16be8a2d696
--- /dev/null
+++ b/chromium/services/preferences/tracked/BUILD.gn
@@ -0,0 +1,86 @@
+# 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.
+
+source_set("tracked") {
+ sources = [
+ "device_id.h",
+ "device_id_mac.cc",
+ "device_id_stub.cc",
+ "device_id_win.cc",
+ "dictionary_hash_store_contents.cc",
+ "dictionary_hash_store_contents.h",
+ "hash_store_contents.h",
+ "interceptable_pref_filter.cc",
+ "interceptable_pref_filter.h",
+ "pref_hash_calculator.cc",
+ "pref_hash_calculator.h",
+ "pref_hash_filter.cc",
+ "pref_hash_filter.h",
+ "pref_hash_store.h",
+ "pref_hash_store_impl.cc",
+ "pref_hash_store_impl.h",
+ "pref_hash_store_transaction.h",
+ "registry_hash_store_contents_win.cc",
+ "registry_hash_store_contents_win.h",
+ "segregated_pref_store.cc",
+ "segregated_pref_store.h",
+ "tracked_atomic_preference.cc",
+ "tracked_atomic_preference.h",
+ "tracked_persistent_pref_store_factory.cc",
+ "tracked_persistent_pref_store_factory.h",
+ "tracked_preference.h",
+ "tracked_preference_helper.cc",
+ "tracked_preference_helper.h",
+ "tracked_preferences_migration.cc",
+ "tracked_preferences_migration.h",
+ "tracked_split_preference.cc",
+ "tracked_split_preference.h",
+ ]
+
+ if (is_win || is_mac) {
+ sources -= [ "device_id_stub.cc" ]
+ }
+
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
+ public_deps = [
+ "//services/preferences/public/cpp/tracked",
+ "//services/preferences/public/interfaces",
+ ]
+
+ deps = [
+ "//base",
+ "//components/pref_registry",
+ "//components/prefs",
+ "//crypto",
+ ]
+
+ if (is_mac) {
+ libs = [ "IOKit.framework" ]
+ }
+}
+
+source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "device_id_unittest.cc",
+ "interceptable_pref_filter_unittest.cc",
+ "pref_hash_calculator_unittest.cc",
+ "pref_hash_filter_unittest.cc",
+ "pref_hash_store_impl_unittest.cc",
+ "registry_hash_store_contents_win_unittest.cc",
+ "segregated_pref_store_unittest.cc",
+ "tracked_preferences_migration_unittest.cc",
+ ]
+
+ deps = [
+ ":tracked",
+ "//base",
+ "//base/test:test_support",
+ "//components/prefs:test_support",
+ "//services/preferences/public/cpp/tracked:test_support",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/services/preferences/tracked/DEPS b/chromium/services/preferences/tracked/DEPS
new file mode 100644
index 00000000000..6ccb05e9fab
--- /dev/null
+++ b/chromium/services/preferences/tracked/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+components/pref_registry",
+ "+crypto/hmac.h",
+]
diff --git a/chromium/services/preferences/tracked/OWNERS b/chromium/services/preferences/tracked/OWNERS
new file mode 100644
index 00000000000..2845b0f366d
--- /dev/null
+++ b/chromium/services/preferences/tracked/OWNERS
@@ -0,0 +1,2 @@
+bauerb@chromium.org
+gab@chromium.org
diff --git a/chromium/services/preferences/tracked/device_id.h b/chromium/services/preferences/tracked/device_id.h
new file mode 100644
index 00000000000..04355628c7d
--- /dev/null
+++ b/chromium/services/preferences/tracked/device_id.h
@@ -0,0 +1,23 @@
+// 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_PREFERENCES_TRACKED_DEVICE_ID_H_
+#define SERVICES_PREFERENCES_TRACKED_DEVICE_ID_H_
+
+#include <string>
+
+enum class MachineIdStatus {
+ SUCCESS = 0,
+ FAILURE, // Returned if attempt to obtain a machine-specific ID fails.
+ NOT_IMPLEMENTED // Returned if the method for obtaining a machine-specific ID
+ // is not implemented for the system.
+};
+
+// Populates |machine_id| with a deterministic ID for this machine. |machine_id|
+// must not be null. Returns |FAILURE| if a machine ID cannot be obtained or
+// |NOT_IMPLEMENTED| on systems for which this feature is not supported (in both
+// cases |machine_id| is left untouched).
+MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id);
+
+#endif // SERVICES_PREFERENCES_TRACKED_DEVICE_ID_H_
diff --git a/chromium/services/preferences/tracked/device_id_mac.cc b/chromium/services/preferences/tracked/device_id_mac.cc
new file mode 100644
index 00000000000..38dfb340c7e
--- /dev/null
+++ b/chromium/services/preferences/tracked/device_id_mac.cc
@@ -0,0 +1,32 @@
+// 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/preferences/tracked/device_id.h"
+
+#include <IOKit/IOKitLib.h>
+
+#include "base/mac/foundation_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_ioobject.h"
+#include "base/strings/sys_string_conversions.h"
+
+MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id) {
+ base::mac::ScopedIOObject<io_service_t> platform_expert(
+ IOServiceGetMatchingService(kIOMasterPortDefault,
+ IOServiceMatching("IOPlatformExpertDevice")));
+ if (!platform_expert.get())
+ return MachineIdStatus::FAILURE;
+
+ base::ScopedCFTypeRef<CFTypeRef> uuid(IORegistryEntryCreateCFProperty(
+ platform_expert, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0));
+ if (!uuid.get())
+ return MachineIdStatus::FAILURE;
+
+ CFStringRef uuid_string = base::mac::CFCast<CFStringRef>(uuid);
+ if (!uuid_string)
+ return MachineIdStatus::FAILURE;
+
+ *machine_id = base::SysCFStringRefToUTF8(uuid_string);
+ return MachineIdStatus::SUCCESS;
+}
diff --git a/chromium/services/preferences/tracked/device_id_stub.cc b/chromium/services/preferences/tracked/device_id_stub.cc
new file mode 100644
index 00000000000..9db4d503863
--- /dev/null
+++ b/chromium/services/preferences/tracked/device_id_stub.cc
@@ -0,0 +1,11 @@
+// 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 "base/logging.h"
+#include "services/preferences/tracked/device_id.h"
+
+MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id) {
+ DCHECK(machine_id);
+ return MachineIdStatus::NOT_IMPLEMENTED;
+}
diff --git a/chromium/services/preferences/tracked/device_id_unittest.cc b/chromium/services/preferences/tracked/device_id_unittest.cc
new file mode 100644
index 00000000000..297cf42e618
--- /dev/null
+++ b/chromium/services/preferences/tracked/device_id_unittest.cc
@@ -0,0 +1,35 @@
+// 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/preferences/tracked/device_id.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(GetDeterministicMachineSpecificIdTest, IsDeterministic) {
+ std::string first_machine_id;
+ std::string second_machine_id;
+
+ const MachineIdStatus kExpectedStatus =
+#if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS))
+ MachineIdStatus::SUCCESS;
+#else
+ MachineIdStatus::NOT_IMPLEMENTED;
+#endif
+
+ ASSERT_EQ(kExpectedStatus,
+ GetDeterministicMachineSpecificId(&first_machine_id));
+ ASSERT_EQ(kExpectedStatus,
+ GetDeterministicMachineSpecificId(&second_machine_id));
+
+ // The reason for using |EXPECT_TRUE| with one argument instead of |EXPECT_EQ|
+ // with two arguments is a compiler bug in gcc that results in a "converting
+ // 'false' to pointer type" error when the first argument to |EXPECT_EQ| is a
+ // compile-time const false value. See also the following bug reports:
+ // https://code.google.com/p/googletest/issues/detail?id=322
+ // https://code.google.com/p/googletest/issues/detail?id=458
+ EXPECT_TRUE((kExpectedStatus == MachineIdStatus::SUCCESS) ==
+ !first_machine_id.empty());
+ EXPECT_EQ(first_machine_id, second_machine_id);
+}
diff --git a/chromium/services/preferences/tracked/device_id_win.cc b/chromium/services/preferences/tracked/device_id_win.cc
new file mode 100644
index 00000000000..9dbd110674a
--- /dev/null
+++ b/chromium/services/preferences/tracked/device_id_win.cc
@@ -0,0 +1,73 @@
+// 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/preferences/tracked/device_id.h"
+
+#include <windows.h>
+
+#include <sddl.h> // For ConvertSidToStringSidA.
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/macros.h"
+
+MachineIdStatus GetDeterministicMachineSpecificId(std::string* machine_id) {
+ DCHECK(machine_id);
+
+ wchar_t computer_name[MAX_COMPUTERNAME_LENGTH + 1] = {};
+ DWORD computer_name_size = arraysize(computer_name);
+
+ if (!::GetComputerNameW(computer_name, &computer_name_size))
+ return MachineIdStatus::FAILURE;
+
+ DWORD sid_size = SECURITY_MAX_SID_SIZE;
+ char sid_buffer[SECURITY_MAX_SID_SIZE];
+ SID* sid = reinterpret_cast<SID*>(sid_buffer);
+ DWORD domain_size = 128; // Will expand below if needed.
+ std::unique_ptr<wchar_t[]> domain_buffer(new wchar_t[domain_size]);
+ SID_NAME_USE sid_name_use;
+
+ // Although the fifth argument to |LookupAccountNameW()|,
+ // |ReferencedDomainName|, is annotated as |_Out_opt_|, if a null
+ // value is passed in, zero is returned and |GetLastError()| will
+ // return |ERROR_INSUFFICIENT_BUFFER| (assuming that nothing else went
+ // wrong). In order to ensure that the call to |LookupAccountNameW()|
+ // has succeeded, it is necessary to include the following logic and
+ // obtain the domain name.
+ if (!::LookupAccountNameW(nullptr, computer_name, sid, &sid_size,
+ domain_buffer.get(), &domain_size, &sid_name_use)) {
+ // If the initial size of |domain_buffer| was too small, the
+ // required size is now found in |domain_size|. Resize and try
+ // again.
+ if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return MachineIdStatus::FAILURE;
+
+ domain_buffer.reset(new wchar_t[domain_size]);
+ if (!::LookupAccountNameW(nullptr, computer_name, sid, &sid_size,
+ domain_buffer.get(), &domain_size,
+ &sid_name_use)) {
+ return MachineIdStatus::FAILURE;
+ }
+ }
+
+ // Ensure that the correct type of SID was obtained. The
+ // |LookupAccountNameW()| function seems to always return
+ // |SidTypeDomain| instead of |SidTypeComputer| when the computer name
+ // is passed in as its second argument and therefore both enum values
+ // will be considered acceptable. If the computer name and user name
+ // coincide, |LookupAccountNameW()| seems to always return the machine
+ // SID and set the returned enum to |SidTypeDomain|.
+ DCHECK(sid_name_use == SID_NAME_USE::SidTypeComputer ||
+ sid_name_use == SID_NAME_USE::SidTypeDomain);
+
+ char* sid_string = nullptr;
+ if (!::ConvertSidToStringSidA(sid, &sid_string))
+ return MachineIdStatus::FAILURE;
+
+ *machine_id = sid_string;
+ ::LocalFree(sid_string);
+
+ return MachineIdStatus::SUCCESS;
+}
diff --git a/chromium/services/preferences/tracked/dictionary_hash_store_contents.cc b/chromium/services/preferences/tracked/dictionary_hash_store_contents.cc
new file mode 100644
index 00000000000..3cef69b05a1
--- /dev/null
+++ b/chromium/services/preferences/tracked/dictionary_hash_store_contents.cc
@@ -0,0 +1,133 @@
+// Copyright (c) 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/preferences/tracked/dictionary_hash_store_contents.h"
+
+#include "base/callback.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/values.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/persistent_pref_store.h"
+
+namespace {
+const char kPreferenceMACs[] = "protection.macs";
+const char kSuperMACPref[] = "protection.super_mac";
+}
+
+DictionaryHashStoreContents::DictionaryHashStoreContents(
+ base::DictionaryValue* storage)
+ : storage_(storage) {}
+
+// static
+void DictionaryHashStoreContents::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterDictionaryPref(kPreferenceMACs);
+ registry->RegisterStringPref(kSuperMACPref, std::string());
+}
+
+bool DictionaryHashStoreContents::IsCopyable() const {
+ return false;
+}
+
+std::unique_ptr<HashStoreContents> DictionaryHashStoreContents::MakeCopy()
+ const {
+ NOTREACHED() << "DictionaryHashStoreContents does not support MakeCopy";
+ return nullptr;
+}
+
+base::StringPiece DictionaryHashStoreContents::GetUMASuffix() const {
+ // To stay consistent with existing reported data, do not append a suffix
+ // when reporting UMA stats for this content.
+ return base::StringPiece();
+}
+
+void DictionaryHashStoreContents::Reset() {
+ storage_->Remove(kPreferenceMACs, NULL);
+}
+
+bool DictionaryHashStoreContents::GetMac(const std::string& path,
+ std::string* out_value) {
+ const base::DictionaryValue* macs_dict = GetContents();
+ if (macs_dict)
+ return macs_dict->GetString(path, out_value);
+
+ return false;
+}
+
+bool DictionaryHashStoreContents::GetSplitMacs(
+ const std::string& path,
+ std::map<std::string, std::string>* split_macs) {
+ DCHECK(split_macs);
+ DCHECK(split_macs->empty());
+
+ const base::DictionaryValue* macs_dict = GetContents();
+ const base::DictionaryValue* split_macs_dict = NULL;
+ if (!macs_dict || !macs_dict->GetDictionary(path, &split_macs_dict))
+ return false;
+ for (base::DictionaryValue::Iterator it(*split_macs_dict); !it.IsAtEnd();
+ it.Advance()) {
+ std::string mac_string;
+ if (!it.value().GetAsString(&mac_string)) {
+ NOTREACHED();
+ continue;
+ }
+ split_macs->insert(make_pair(it.key(), mac_string));
+ }
+ return true;
+}
+
+void DictionaryHashStoreContents::SetMac(const std::string& path,
+ const std::string& value) {
+ base::DictionaryValue* macs_dict = GetMutableContents(true);
+ macs_dict->SetString(path, value);
+}
+
+void DictionaryHashStoreContents::SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) {
+ // DictionaryValue handles a '.' delimiter.
+ SetMac(path + '.' + split_path, value);
+}
+
+void DictionaryHashStoreContents::ImportEntry(const std::string& path,
+ const base::Value* in_value) {
+ base::DictionaryValue* macs_dict = GetMutableContents(true);
+ macs_dict->Set(path, in_value->DeepCopy());
+}
+
+bool DictionaryHashStoreContents::RemoveEntry(const std::string& path) {
+ base::DictionaryValue* macs_dict = GetMutableContents(false);
+ if (macs_dict)
+ return macs_dict->RemovePath(path, NULL);
+
+ return false;
+}
+
+std::string DictionaryHashStoreContents::GetSuperMac() const {
+ std::string super_mac_string;
+ storage_->GetString(kSuperMACPref, &super_mac_string);
+ return super_mac_string;
+}
+
+void DictionaryHashStoreContents::SetSuperMac(const std::string& super_mac) {
+ storage_->SetString(kSuperMACPref, super_mac);
+}
+
+const base::DictionaryValue* DictionaryHashStoreContents::GetContents() const {
+ const base::DictionaryValue* macs_dict = NULL;
+ storage_->GetDictionary(kPreferenceMACs, &macs_dict);
+ return macs_dict;
+}
+
+base::DictionaryValue* DictionaryHashStoreContents::GetMutableContents(
+ bool create_if_null) {
+ base::DictionaryValue* macs_dict = NULL;
+ storage_->GetDictionary(kPreferenceMACs, &macs_dict);
+ if (!macs_dict && create_if_null) {
+ macs_dict = new base::DictionaryValue;
+ storage_->Set(kPreferenceMACs, macs_dict);
+ }
+ return macs_dict;
+}
diff --git a/chromium/services/preferences/tracked/dictionary_hash_store_contents.h b/chromium/services/preferences/tracked/dictionary_hash_store_contents.h
new file mode 100644
index 00000000000..16fe628ad81
--- /dev/null
+++ b/chromium/services/preferences/tracked/dictionary_hash_store_contents.h
@@ -0,0 +1,62 @@
+// 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_PREFERENCES_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_
+#define SERVICES_PREFERENCES_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_
+
+#include "base/macros.h"
+#include "services/preferences/tracked/hash_store_contents.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+} // namespace base
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+} // namespace user_prefs
+
+// Implements HashStoreContents by storing MACs in a DictionaryValue. The
+// DictionaryValue is presumed to be the contents of a PrefStore.
+// RegisterProfilePrefs() may be used to register all of the preferences used by
+// this object.
+class DictionaryHashStoreContents : public HashStoreContents {
+ public:
+ // Constructs a DictionaryHashStoreContents that reads from and writes to
+ // |storage|.
+ explicit DictionaryHashStoreContents(base::DictionaryValue* storage);
+
+ // Registers required preferences.
+ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+ // HashStoreContents implementation
+ bool IsCopyable() const override;
+ std::unique_ptr<HashStoreContents> MakeCopy() const override;
+ base::StringPiece GetUMASuffix() const override;
+ void Reset() override;
+ bool GetMac(const std::string& path, std::string* out_value) override;
+ bool GetSplitMacs(const std::string& path,
+ std::map<std::string, std::string>* split_macs) override;
+ void SetMac(const std::string& path, const std::string& value) override;
+ void SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) override;
+ void ImportEntry(const std::string& path,
+ const base::Value* in_value) override;
+ bool RemoveEntry(const std::string& path) override;
+ const base::DictionaryValue* GetContents() const override;
+ std::string GetSuperMac() const override;
+ void SetSuperMac(const std::string& super_mac) override;
+
+ private:
+ base::DictionaryValue* storage_;
+
+ // Helper function to get a mutable version of the macs from |storage_|,
+ // creating it if needed and |create_if_null| is true.
+ base::DictionaryValue* GetMutableContents(bool create_if_null);
+
+ DISALLOW_COPY_AND_ASSIGN(DictionaryHashStoreContents);
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_DICTIONARY_HASH_STORE_CONTENTS_H_
diff --git a/chromium/services/preferences/tracked/hash_store_contents.h b/chromium/services/preferences/tracked/hash_store_contents.h
new file mode 100644
index 00000000000..5486514bf23
--- /dev/null
+++ b/chromium/services/preferences/tracked/hash_store_contents.h
@@ -0,0 +1,90 @@
+// 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_PREFERENCES_TRACKED_HASH_STORE_CONTENTS_H_
+#define SERVICES_PREFERENCES_TRACKED_HASH_STORE_CONTENTS_H_
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include "base/strings/string_piece.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+} // namespace base
+
+// Provides access to the contents of a preference hash store. The store
+// contains the following data:
+// Contents: a client-defined dictionary that should map preference names to
+// MACs.
+// Version: a client-defined version number for the format of Contents.
+// Super MAC: a MAC that authenticates the entirety of Contents.
+class HashStoreContents {
+ public:
+ virtual ~HashStoreContents() {}
+
+ // Returns true if this implementation of HashStoreContents can be copied via
+ // MakeCopy().
+ virtual bool IsCopyable() const = 0;
+
+ // Returns a copy of this HashStoreContents. Must only be called on
+ // lightweight implementations (which return true from IsCopyable()) and only
+ // in scenarios where a copy cannot be avoided.
+ virtual std::unique_ptr<HashStoreContents> MakeCopy() const = 0;
+
+ // Returns the suffix to be appended to UMA histograms for this store type.
+ // The returned value must either be an empty string or one of the values in
+ // histograms.xml's TrackedPreferencesExternalValidators.
+ virtual base::StringPiece GetUMASuffix() const = 0;
+
+ // Discards all data related to this hash store.
+ virtual void Reset() = 0;
+
+ // Outputs the MAC validating the preference at path. Returns true if a MAC
+ // was successfully read and false otherwise.
+ virtual bool GetMac(const std::string& path, std::string* out_value) = 0;
+
+ // Outputs the MACS validating the split preference at path. Returns true if
+ // MACS were successfully read and false otherwise.
+ virtual bool GetSplitMacs(const std::string& path,
+ std::map<std::string, std::string>* out_value) = 0;
+
+ // Set the MAC validating the preference at path.
+ virtual void SetMac(const std::string& path, const std::string& value) = 0;
+
+ // Set the MAC validating the split preference at path and split_path.
+ // For example, |path| is 'extension' and |split_path| is some extenson id.
+ virtual void SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) = 0;
+
+ // Sets the MAC for the preference at |path|.
+ // If |path| is a split preference |in_value| must be a DictionaryValue whose
+ // keys are keys in the split preference and whose values are MACs of the
+ // corresponding values in the split preference.
+ // If |path| is an atomic preference |in_value| must be a StringValue
+ // containing a MAC of the preference value.
+ virtual void ImportEntry(const std::string& path,
+ const base::Value* in_value) = 0;
+
+ // Removes the MAC (for atomic preferences) or MACs (for split preferences)
+ // at |path|. Returns true if there was an entry at |path| which was
+ // successfully removed.
+ virtual bool RemoveEntry(const std::string& path) = 0;
+
+ // Only needed if this store supports super MACs.
+ virtual const base::DictionaryValue* GetContents() const = 0;
+
+ // Retrieves the super MAC value previously stored by SetSuperMac. May be
+ // empty if no super MAC has been stored or if this store does not support
+ // super MACs.
+ virtual std::string GetSuperMac() const = 0;
+
+ // Stores a super MAC value for this hash store.
+ virtual void SetSuperMac(const std::string& super_mac) = 0;
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_HASH_STORE_CONTENTS_H_
diff --git a/chromium/services/preferences/tracked/interceptable_pref_filter.cc b/chromium/services/preferences/tracked/interceptable_pref_filter.cc
new file mode 100644
index 00000000000..81f2783558e
--- /dev/null
+++ b/chromium/services/preferences/tracked/interceptable_pref_filter.cc
@@ -0,0 +1,39 @@
+// 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/preferences/tracked/interceptable_pref_filter.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+
+InterceptablePrefFilter::InterceptablePrefFilter() {}
+InterceptablePrefFilter::~InterceptablePrefFilter() {}
+
+void InterceptablePrefFilter::FilterOnLoad(
+ const PostFilterOnLoadCallback& post_filter_on_load_callback,
+ std::unique_ptr<base::DictionaryValue> pref_store_contents) {
+ if (filter_on_load_interceptor_.is_null()) {
+ FinalizeFilterOnLoad(post_filter_on_load_callback,
+ std::move(pref_store_contents), false);
+ } else {
+ // Note, in practice (in the implementation as it was in May 2014) it would
+ // be okay to pass an unretained |this| pointer below, but in order to avoid
+ // having to augment the API everywhere to explicitly enforce the ownership
+ // model as it happens to currently be: make the relationship simpler by
+ // weakly binding the FinalizeFilterOnLoadCallback below to |this|.
+ const FinalizeFilterOnLoadCallback finalize_filter_on_load(
+ base::Bind(&InterceptablePrefFilter::FinalizeFilterOnLoad, AsWeakPtr(),
+ post_filter_on_load_callback));
+ base::ResetAndReturn(&filter_on_load_interceptor_)
+ .Run(finalize_filter_on_load, std::move(pref_store_contents));
+ }
+}
+
+void InterceptablePrefFilter::InterceptNextFilterOnLoad(
+ const FilterOnLoadInterceptor& filter_on_load_interceptor) {
+ DCHECK(filter_on_load_interceptor_.is_null());
+ filter_on_load_interceptor_ = filter_on_load_interceptor;
+}
diff --git a/chromium/services/preferences/tracked/interceptable_pref_filter.h b/chromium/services/preferences/tracked/interceptable_pref_filter.h
new file mode 100644
index 00000000000..7971c8da8f1
--- /dev/null
+++ b/chromium/services/preferences/tracked/interceptable_pref_filter.h
@@ -0,0 +1,68 @@
+// 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_PREFERENCES_TRACKED_INTERCEPTABLE_PREF_FILTER_H_
+#define SERVICES_PREFERENCES_TRACKED_INTERCEPTABLE_PREF_FILTER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/values.h"
+#include "components/prefs/pref_filter.h"
+
+// A partial implementation of a PrefFilter whose FilterOnLoad call may be
+// intercepted by a FilterOnLoadInterceptor. Implementations of
+// InterceptablePrefFilter are expected to override FinalizeFilterOnLoad rather
+// than re-overriding FilterOnLoad.
+class InterceptablePrefFilter
+ : public PrefFilter,
+ public base::SupportsWeakPtr<InterceptablePrefFilter> {
+ public:
+ // A callback to be invoked by a FilterOnLoadInterceptor when its ready to
+ // hand back the |prefs| it was handed for early filtering. |prefs_altered|
+ // indicates whether the |prefs| were actually altered by the
+ // FilterOnLoadInterceptor before being handed back.
+ typedef base::Callback<void(std::unique_ptr<base::DictionaryValue> prefs,
+ bool prefs_altered)>
+ FinalizeFilterOnLoadCallback;
+
+ // A callback to be invoked from FilterOnLoad. It takes ownership of prefs
+ // and may modify them before handing them back to this
+ // InterceptablePrefFilter via |finalize_filter_on_load|.
+ typedef base::Callback<void(
+ const FinalizeFilterOnLoadCallback& finalize_filter_on_load,
+ std::unique_ptr<base::DictionaryValue> prefs)>
+ FilterOnLoadInterceptor;
+
+ InterceptablePrefFilter();
+ ~InterceptablePrefFilter() override;
+
+ // PrefFilter partial implementation.
+ void FilterOnLoad(
+ const PostFilterOnLoadCallback& post_filter_on_load_callback,
+ std::unique_ptr<base::DictionaryValue> pref_store_contents) override;
+
+ // Registers |filter_on_load_interceptor| to intercept the next FilterOnLoad
+ // event. At most one FilterOnLoadInterceptor should be registered per
+ // PrefFilter.
+ void InterceptNextFilterOnLoad(
+ const FilterOnLoadInterceptor& filter_on_load_interceptor);
+
+ private:
+ // Does any extra filtering required by the implementation of this
+ // InterceptablePrefFilter and hands back the |pref_store_contents| to the
+ // initial caller of FilterOnLoad.
+ virtual void FinalizeFilterOnLoad(
+ const PostFilterOnLoadCallback& post_filter_on_load_callback,
+ std::unique_ptr<base::DictionaryValue> pref_store_contents,
+ bool prefs_altered) = 0;
+
+ // Callback to be invoked only once (and subsequently reset) on the next
+ // FilterOnLoad event. It will be allowed to modify the |prefs| handed to
+ // FilterOnLoad before handing them back to this PrefHashFilter.
+ FilterOnLoadInterceptor filter_on_load_interceptor_;
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_INTERCEPTABLE_PREF_FILTER_H_
diff --git a/chromium/services/preferences/tracked/interceptable_pref_filter_unittest.cc b/chromium/services/preferences/tracked/interceptable_pref_filter_unittest.cc
new file mode 100644
index 00000000000..cdaaadb37d4
--- /dev/null
+++ b/chromium/services/preferences/tracked/interceptable_pref_filter_unittest.cc
@@ -0,0 +1,55 @@
+// 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/preferences/tracked/interceptable_pref_filter.h"
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/memory/ptr_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+class TestInterceptablePrefFilter : public InterceptablePrefFilter {
+ public:
+ void FinalizeFilterOnLoad(
+ const PostFilterOnLoadCallback& post_filter_on_load_callback,
+ std::unique_ptr<base::DictionaryValue> pref_store_contents,
+ bool prefs_altered) override {
+ post_filter_on_load_callback.Run(std::move(pref_store_contents),
+ prefs_altered);
+ }
+
+ void FilterUpdate(const std::string& path) override {}
+
+ OnWriteCallbackPair FilterSerializeData(
+ base::DictionaryValue* pref_store_contents) override {
+ return {};
+ }
+};
+
+void NoOpIntercept(const InterceptablePrefFilter::FinalizeFilterOnLoadCallback&
+ finalize_filter_on_load,
+ std::unique_ptr<base::DictionaryValue> prefs) {
+ finalize_filter_on_load.Run(std::move(prefs), false);
+}
+
+void DeleteFilter(std::unique_ptr<TestInterceptablePrefFilter>* filter,
+ std::unique_ptr<base::DictionaryValue> prefs,
+ bool schedule_write) {
+ filter->reset();
+}
+
+TEST(InterceptablePrefFilterTest, CallbackDeletes) {
+ auto filter = base::MakeUnique<TestInterceptablePrefFilter>();
+ filter->InterceptNextFilterOnLoad(base::Bind(&NoOpIntercept));
+ filter->FilterOnLoad(base::Bind(&DeleteFilter, &filter),
+ base::MakeUnique<base::DictionaryValue>());
+ EXPECT_FALSE(filter);
+}
+
+} // namespace
diff --git a/chromium/services/preferences/tracked/pref_hash_calculator.cc b/chromium/services/preferences/tracked/pref_hash_calculator.cc
new file mode 100644
index 00000000000..207221c5688
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_calculator.cc
@@ -0,0 +1,112 @@
+// Copyright 2013 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/preferences/tracked/pref_hash_calculator.h"
+
+#include <stdint.h>
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/json/json_string_value_serializer.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "crypto/hmac.h"
+
+namespace {
+
+// Calculates an HMAC of |message| using |key|, encoded as a hexadecimal string.
+std::string GetDigestString(const std::string& key,
+ const std::string& message) {
+ crypto::HMAC hmac(crypto::HMAC::SHA256);
+ std::vector<uint8_t> digest(hmac.DigestLength());
+ if (!hmac.Init(key) || !hmac.Sign(message, &digest[0], digest.size())) {
+ NOTREACHED();
+ return std::string();
+ }
+ return base::HexEncode(&digest[0], digest.size());
+}
+
+// Verifies that |digest_string| is a valid HMAC of |message| using |key|.
+// |digest_string| must be encoded as a hexadecimal string.
+bool VerifyDigestString(const std::string& key,
+ const std::string& message,
+ const std::string& digest_string) {
+ crypto::HMAC hmac(crypto::HMAC::SHA256);
+ std::vector<uint8_t> digest;
+ return base::HexStringToBytes(digest_string, &digest) && hmac.Init(key) &&
+ hmac.Verify(message,
+ base::StringPiece(reinterpret_cast<char*>(&digest[0]),
+ digest.size()));
+}
+
+// Renders |value| as a string. |value| may be NULL, in which case the result
+// is an empty string. This method can be expensive and its result should be
+// re-used rather than recomputed where possible.
+std::string ValueAsString(const base::Value* value) {
+ // Dictionary values may contain empty lists and sub-dictionaries. Make a
+ // deep copy with those removed to make the hash more stable.
+ const base::DictionaryValue* dict_value;
+ std::unique_ptr<base::DictionaryValue> canonical_dict_value;
+ if (value && value->GetAsDictionary(&dict_value)) {
+ canonical_dict_value = dict_value->DeepCopyWithoutEmptyChildren();
+ value = canonical_dict_value.get();
+ }
+
+ std::string value_as_string;
+ if (value) {
+ JSONStringValueSerializer serializer(&value_as_string);
+ serializer.Serialize(*value);
+ }
+
+ return value_as_string;
+}
+
+// Concatenates |device_id|, |path|, and |value_as_string| to give the hash
+// input.
+std::string GetMessage(const std::string& device_id,
+ const std::string& path,
+ const std::string& value_as_string) {
+ std::string message;
+ message.reserve(device_id.size() + path.size() + value_as_string.size());
+ message.append(device_id);
+ message.append(path);
+ message.append(value_as_string);
+ return message;
+}
+
+} // namespace
+
+PrefHashCalculator::PrefHashCalculator(const std::string& seed,
+ const std::string& device_id,
+ const std::string& legacy_device_id)
+ : seed_(seed), device_id_(device_id), legacy_device_id_(legacy_device_id) {}
+
+PrefHashCalculator::~PrefHashCalculator() {}
+
+std::string PrefHashCalculator::Calculate(const std::string& path,
+ const base::Value* value) const {
+ return GetDigestString(seed_,
+ GetMessage(device_id_, path, ValueAsString(value)));
+}
+
+PrefHashCalculator::ValidationResult PrefHashCalculator::Validate(
+ const std::string& path,
+ const base::Value* value,
+ const std::string& digest_string) const {
+ const std::string value_as_string(ValueAsString(value));
+ if (VerifyDigestString(seed_, GetMessage(device_id_, path, value_as_string),
+ digest_string)) {
+ return VALID;
+ }
+ if (VerifyDigestString(seed_,
+ GetMessage(legacy_device_id_, path, value_as_string),
+ digest_string)) {
+ return VALID_SECURE_LEGACY;
+ }
+ return INVALID;
+}
diff --git a/chromium/services/preferences/tracked/pref_hash_calculator.h b/chromium/services/preferences/tracked/pref_hash_calculator.h
new file mode 100644
index 00000000000..1fc14a180aa
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_calculator.h
@@ -0,0 +1,55 @@
+// Copyright 2013 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_PREFERENCES_TRACKED_PREF_HASH_CALCULATOR_H_
+#define SERVICES_PREFERENCES_TRACKED_PREF_HASH_CALCULATOR_H_
+
+#include <string>
+
+#include "base/macros.h"
+
+namespace base {
+class Value;
+} // namespace base
+
+// Calculates and validates preference value hashes.
+class PrefHashCalculator {
+ public:
+ enum ValidationResult {
+ INVALID,
+ VALID,
+ // Valid under a deprecated but as secure algorithm.
+ VALID_SECURE_LEGACY,
+ };
+
+ // Constructs a PrefHashCalculator using |seed|, |device_id| and
+ // |legacy_device_id|. The same parameters must be used in order to
+ // successfully validate generated hashes. |_device_id| or |legacy_device_id|
+ // may be empty.
+ PrefHashCalculator(const std::string& seed,
+ const std::string& device_id,
+ const std::string& legacy_device_id);
+
+ ~PrefHashCalculator();
+
+ // Calculates a hash value for the supplied preference |path| and |value|.
+ // |value| may be null if the preference has no value.
+ std::string Calculate(const std::string& path,
+ const base::Value* value) const;
+
+ // Validates the provided preference hash using current and legacy hashing
+ // algorithms.
+ ValidationResult Validate(const std::string& path,
+ const base::Value* value,
+ const std::string& hash) const;
+
+ private:
+ const std::string seed_;
+ const std::string device_id_;
+ const std::string legacy_device_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefHashCalculator);
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_PREF_HASH_CALCULATOR_H_
diff --git a/chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc b/chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc
new file mode 100644
index 00000000000..df3746a09e0
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_calculator_unittest.cc
@@ -0,0 +1,196 @@
+// Copyright 2013 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/preferences/tracked/pref_hash_calculator.h"
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/strings/string_util.h"
+#include "base/values.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(PrefHashCalculatorTest, TestCurrentAlgorithm) {
+ base::Value string_value_1("string value 1");
+ base::Value string_value_2("string value 2");
+ base::DictionaryValue dictionary_value_1;
+ dictionary_value_1.SetInteger("int value", 1);
+ dictionary_value_1.Set("nested empty map", new base::DictionaryValue);
+ base::DictionaryValue dictionary_value_1_equivalent;
+ dictionary_value_1_equivalent.SetInteger("int value", 1);
+ base::DictionaryValue dictionary_value_2;
+ dictionary_value_2.SetInteger("int value", 2);
+
+ PrefHashCalculator calc1("seed1", "deviceid", "legacydeviceid");
+ PrefHashCalculator calc1_dup("seed1", "deviceid", "legacydeviceid");
+ PrefHashCalculator calc2("seed2", "deviceid", "legacydeviceid");
+ PrefHashCalculator calc3("seed1", "deviceid2", "legacydeviceid");
+
+ // Two calculators with same seed produce same hash.
+ ASSERT_EQ(calc1.Calculate("pref_path", &string_value_1),
+ calc1_dup.Calculate("pref_path", &string_value_1));
+ ASSERT_EQ(PrefHashCalculator::VALID,
+ calc1_dup.Validate("pref_path", &string_value_1,
+ calc1.Calculate("pref_path", &string_value_1)));
+
+ // Different seeds, different hashes.
+ ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
+ calc2.Calculate("pref_path", &string_value_1));
+ ASSERT_EQ(PrefHashCalculator::INVALID,
+ calc2.Validate("pref_path", &string_value_1,
+ calc1.Calculate("pref_path", &string_value_1)));
+
+ // Different device IDs, different hashes.
+ ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
+ calc3.Calculate("pref_path", &string_value_1));
+
+ // Different values, different hashes.
+ ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
+ calc1.Calculate("pref_path", &string_value_2));
+
+ // Different paths, different hashes.
+ ASSERT_NE(calc1.Calculate("pref_path", &string_value_1),
+ calc1.Calculate("pref_path_2", &string_value_1));
+
+ // Works for dictionaries.
+ ASSERT_EQ(calc1.Calculate("pref_path", &dictionary_value_1),
+ calc1.Calculate("pref_path", &dictionary_value_1));
+ ASSERT_NE(calc1.Calculate("pref_path", &dictionary_value_1),
+ calc1.Calculate("pref_path", &dictionary_value_2));
+
+ // Empty dictionary children are pruned.
+ ASSERT_EQ(calc1.Calculate("pref_path", &dictionary_value_1),
+ calc1.Calculate("pref_path", &dictionary_value_1_equivalent));
+
+ // NULL value is supported.
+ ASSERT_FALSE(calc1.Calculate("pref_path", NULL).empty());
+}
+
+// Tests the output against a known value to catch unexpected algorithm changes.
+// The test hashes below must NEVER be updated, the serialization algorithm used
+// must always be able to generate data that will produce these exact hashes.
+TEST(PrefHashCalculatorTest, CatchHashChanges) {
+ static const char kSeed[] = "0123456789ABCDEF0123456789ABCDEF";
+ static const char kDeviceId[] = "test_device_id1";
+
+ auto null_value = base::MakeUnique<base::Value>();
+ std::unique_ptr<base::Value> bool_value(new base::Value(false));
+ std::unique_ptr<base::Value> int_value(new base::Value(1234567890));
+ std::unique_ptr<base::Value> double_value(new base::Value(123.0987654321));
+ std::unique_ptr<base::Value> string_value(
+ new base::Value("testing with special chars:\n<>{}:^^@#$\\/"));
+
+ // For legacy reasons, we have to support pruning of empty lists/dictionaries
+ // and nested empty ists/dicts in the hash generation algorithm.
+ std::unique_ptr<base::DictionaryValue> nested_empty_dict(
+ new base::DictionaryValue);
+ nested_empty_dict->Set("a", new base::DictionaryValue);
+ nested_empty_dict->Set("b", new base::ListValue);
+ std::unique_ptr<base::ListValue> nested_empty_list(new base::ListValue);
+ nested_empty_list->Append(base::MakeUnique<base::DictionaryValue>());
+ nested_empty_list->Append(base::MakeUnique<base::ListValue>());
+ nested_empty_list->Append(nested_empty_dict->CreateDeepCopy());
+
+ // A dictionary with an empty dictionary, an empty list, and nested empty
+ // dictionaries/lists in it.
+ std::unique_ptr<base::DictionaryValue> dict_value(new base::DictionaryValue);
+ dict_value->Set("a", new base::Value("foo"));
+ dict_value->Set("d", new base::ListValue);
+ dict_value->Set("b", new base::DictionaryValue);
+ dict_value->Set("c", new base::Value("baz"));
+ dict_value->Set("e", nested_empty_dict.release());
+ dict_value->Set("f", nested_empty_list.release());
+
+ std::unique_ptr<base::ListValue> list_value(new base::ListValue);
+ list_value->AppendBoolean(true);
+ list_value->AppendInteger(100);
+ list_value->AppendDouble(1.0);
+
+ ASSERT_EQ(base::Value::Type::NONE, null_value->GetType());
+ ASSERT_EQ(base::Value::Type::BOOLEAN, bool_value->GetType());
+ ASSERT_EQ(base::Value::Type::INTEGER, int_value->GetType());
+ ASSERT_EQ(base::Value::Type::DOUBLE, double_value->GetType());
+ ASSERT_EQ(base::Value::Type::STRING, string_value->GetType());
+ ASSERT_EQ(base::Value::Type::DICTIONARY, dict_value->GetType());
+ ASSERT_EQ(base::Value::Type::LIST, list_value->GetType());
+
+ // Test every value type independently. Intentionally omits Type::BINARY which
+ // isn't even allowed in JSONWriter's input.
+ static const char kExpectedNullValue[] =
+ "82A9F3BBC7F9FF84C76B033C854E79EEB162783FA7B3E99FF9372FA8E12C44F7";
+ EXPECT_EQ(PrefHashCalculator::VALID,
+ PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
+ .Validate("pref.path", null_value.get(), kExpectedNullValue));
+
+ static const char kExpectedBooleanValue[] =
+ "A520D8F43EA307B0063736DC9358C330539D0A29417580514C8B9862632C4CCC";
+ EXPECT_EQ(
+ PrefHashCalculator::VALID,
+ PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
+ .Validate("pref.path", bool_value.get(), kExpectedBooleanValue));
+
+ static const char kExpectedIntegerValue[] =
+ "8D60DA1F10BF5AA29819D2D66D7CCEF9AABC5DA93C11A0D2BD21078D63D83682";
+ EXPECT_EQ(PrefHashCalculator::VALID,
+ PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
+ .Validate("pref.path", int_value.get(), kExpectedIntegerValue));
+
+ static const char kExpectedDoubleValue[] =
+ "C9D94772516125BEEDAE68C109D44BC529E719EE020614E894CC7FB4098C545D";
+ EXPECT_EQ(
+ PrefHashCalculator::VALID,
+ PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
+ .Validate("pref.path", double_value.get(), kExpectedDoubleValue));
+
+ static const char kExpectedStringValue[] =
+ "05ACCBD3B05C45C36CD06190F63EC577112311929D8380E26E5F13182EB68318";
+ EXPECT_EQ(
+ PrefHashCalculator::VALID,
+ PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
+ .Validate("pref.path", string_value.get(), kExpectedStringValue));
+
+ static const char kExpectedDictValue[] =
+ "7A84DCC710D796C771F789A4DA82C952095AA956B6F1667EE42D0A19ECAA3C4A";
+ EXPECT_EQ(PrefHashCalculator::VALID,
+ PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
+ .Validate("pref.path", dict_value.get(), kExpectedDictValue));
+
+ static const char kExpectedListValue[] =
+ "8D5A25972DF5AE20D041C780E7CA54E40F614AD53513A0724EE8D62D4F992740";
+ EXPECT_EQ(PrefHashCalculator::VALID,
+ PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
+ .Validate("pref.path", list_value.get(), kExpectedListValue));
+
+ // Also test every value type together in the same dictionary.
+ base::DictionaryValue everything;
+ everything.Set("null", null_value.release());
+ everything.Set("bool", bool_value.release());
+ everything.Set("int", int_value.release());
+ everything.Set("double", double_value.release());
+ everything.Set("string", string_value.release());
+ everything.Set("list", list_value.release());
+ everything.Set("dict", dict_value.release());
+ static const char kExpectedEverythingValue[] =
+ "B97D09BE7005693574DCBDD03D8D9E44FB51F4008B73FB56A49A9FA671A1999B";
+ EXPECT_EQ(PrefHashCalculator::VALID,
+ PrefHashCalculator(kSeed, kDeviceId, "legacydeviceid")
+ .Validate("pref.path", &everything, kExpectedEverythingValue));
+}
+
+TEST(PrefHashCalculatorTest, TestCompatibilityWithLegacyDeviceId) {
+ static const char kSeed[] = "0123456789ABCDEF0123456789ABCDEF";
+ static const char kNewDeviceId[] = "new_test_device_id1";
+ static const char kLegacyDeviceId[] = "test_device_id1";
+
+ // As in PrefHashCalculatorTest.CatchHashChanges.
+ const base::Value string_value("testing with special chars:\n<>{}:^^@#$\\/");
+ static const char kExpectedValue[] =
+ "05ACCBD3B05C45C36CD06190F63EC577112311929D8380E26E5F13182EB68318";
+
+ EXPECT_EQ(PrefHashCalculator::VALID_SECURE_LEGACY,
+ PrefHashCalculator(kSeed, kNewDeviceId, kLegacyDeviceId)
+ .Validate("pref.path", &string_value, kExpectedValue));
+}
diff --git a/chromium/services/preferences/tracked/pref_hash_filter.cc b/chromium/services/preferences/tracked/pref_hash_filter.cc
new file mode 100644
index 00000000000..29d6b9ab830
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_filter.cc
@@ -0,0 +1,366 @@
+// Copyright 2013 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/preferences/tracked/pref_hash_filter.h"
+
+#include <stdint.h>
+#include <algorithm>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_macros.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "base/values.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "components/prefs/pref_service.h"
+#include "components/prefs/pref_store.h"
+#include "services/preferences/public/cpp/tracked/pref_names.h"
+#include "services/preferences/tracked/dictionary_hash_store_contents.h"
+#include "services/preferences/tracked/pref_hash_store.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+#include "services/preferences/tracked/tracked_atomic_preference.h"
+#include "services/preferences/tracked/tracked_split_preference.h"
+
+namespace {
+
+void CleanupDeprecatedTrackedPreferences(
+ base::DictionaryValue* pref_store_contents,
+ PrefHashStoreTransaction* hash_store_transaction) {
+ // Add deprecated previously tracked preferences below for them to be cleaned
+ // up from both the pref files and the hash store.
+ static const char* const kDeprecatedTrackedPreferences[] = {
+ // TODO(a-v-y): Remove in M60+,
+ "default_search_provider.search_url", "default_search_provider.name",
+ "default_search_provider.keyword"};
+
+ for (size_t i = 0; i < arraysize(kDeprecatedTrackedPreferences); ++i) {
+ const char* key = kDeprecatedTrackedPreferences[i];
+ pref_store_contents->Remove(key, NULL);
+ hash_store_transaction->ClearHash(key);
+ }
+}
+
+} // namespace
+
+using PrefTrackingStrategy =
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy;
+
+PrefHashFilter::PrefHashFilter(
+ std::unique_ptr<PrefHashStore> pref_hash_store,
+ StoreContentsPair external_validation_hash_store_pair,
+ const std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>&
+ tracked_preferences,
+ prefs::mojom::ResetOnLoadObserverPtr reset_on_load_observer,
+ prefs::mojom::TrackedPreferenceValidationDelegate* delegate,
+ size_t reporting_ids_count,
+ bool report_super_mac_validity)
+ : pref_hash_store_(std::move(pref_hash_store)),
+ external_validation_hash_store_pair_(
+ external_validation_hash_store_pair.first
+ ? base::make_optional(
+ std::move(external_validation_hash_store_pair))
+ : base::nullopt),
+ reset_on_load_observer_(std::move(reset_on_load_observer)),
+ report_super_mac_validity_(report_super_mac_validity) {
+ DCHECK(pref_hash_store_);
+ DCHECK_GE(reporting_ids_count, tracked_preferences.size());
+ // Verify that, if |external_validation_hash_store_pair_| is present, both its
+ // items are non-null.
+ DCHECK(!external_validation_hash_store_pair_.has_value() ||
+ (external_validation_hash_store_pair_->first &&
+ external_validation_hash_store_pair_->second));
+
+ for (size_t i = 0; i < tracked_preferences.size(); ++i) {
+ const prefs::mojom::TrackedPreferenceMetadata& metadata =
+ *tracked_preferences[i];
+
+ std::unique_ptr<TrackedPreference> tracked_preference;
+ switch (metadata.strategy) {
+ case PrefTrackingStrategy::ATOMIC:
+ tracked_preference.reset(new TrackedAtomicPreference(
+ metadata.name, metadata.reporting_id, reporting_ids_count,
+ metadata.enforcement_level, metadata.value_type, delegate));
+ break;
+ case PrefTrackingStrategy::SPLIT:
+ tracked_preference.reset(new TrackedSplitPreference(
+ metadata.name, metadata.reporting_id, reporting_ids_count,
+ metadata.enforcement_level, metadata.value_type, delegate));
+ break;
+ }
+ DCHECK(tracked_preference);
+
+ bool is_new = tracked_paths_
+ .insert(std::make_pair(metadata.name,
+ std::move(tracked_preference)))
+ .second;
+ DCHECK(is_new);
+ }
+}
+
+PrefHashFilter::~PrefHashFilter() {
+ // Ensure new values for all |changed_paths_| have been flushed to
+ // |pref_hash_store_| already.
+ DCHECK(changed_paths_.empty());
+}
+
+// static
+void PrefHashFilter::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ // See GetResetTime for why this is a StringPref and not Int64Pref.
+ registry->RegisterStringPref(
+ user_prefs::kPreferenceResetTime,
+ base::Int64ToString(base::Time().ToInternalValue()));
+}
+
+// static
+base::Time PrefHashFilter::GetResetTime(PrefService* user_prefs) {
+ // Provide our own implementation (identical to the PrefService::GetInt64) in
+ // order to ensure it remains consistent with the way we store this value
+ // (which we do via a PrefStore, preventing us from reusing
+ // PrefService::SetInt64).
+ int64_t internal_value = base::Time().ToInternalValue();
+ if (!base::StringToInt64(
+ user_prefs->GetString(user_prefs::kPreferenceResetTime),
+ &internal_value)) {
+ // Somehow the value stored on disk is not a valid int64_t.
+ NOTREACHED();
+ return base::Time();
+ }
+ return base::Time::FromInternalValue(internal_value);
+}
+
+// static
+void PrefHashFilter::ClearResetTime(PrefService* user_prefs) {
+ user_prefs->ClearPref(user_prefs::kPreferenceResetTime);
+}
+
+void PrefHashFilter::Initialize(base::DictionaryValue* pref_store_contents) {
+ DictionaryHashStoreContents dictionary_contents(pref_store_contents);
+ std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
+ pref_hash_store_->BeginTransaction(&dictionary_contents));
+ for (auto it = tracked_paths_.begin(); it != tracked_paths_.end(); ++it) {
+ const std::string& initialized_path = it->first;
+ const TrackedPreference* initialized_preference = it->second.get();
+ const base::Value* value = nullptr;
+ pref_store_contents->Get(initialized_path, &value);
+ initialized_preference->OnNewValue(value, hash_store_transaction.get());
+ }
+}
+
+// Marks |path| has having changed if it is part of |tracked_paths_|. A new hash
+// will be stored for it the next time FilterSerializeData() is invoked.
+void PrefHashFilter::FilterUpdate(const std::string& path) {
+ auto it = tracked_paths_.find(path);
+ if (it != tracked_paths_.end())
+ changed_paths_.insert(std::make_pair(path, it->second.get()));
+}
+
+// Updates the stored hashes for |changed_paths_| before serializing data to
+// disk. This is required as storing the hash everytime a pref's value changes
+// is too expensive (see perf regression @ http://crbug.com/331273).
+PrefFilter::OnWriteCallbackPair PrefHashFilter::FilterSerializeData(
+ base::DictionaryValue* pref_store_contents) {
+ // Generate the callback pair before clearing |changed_paths_|.
+ PrefFilter::OnWriteCallbackPair callback_pair =
+ GetOnWriteSynchronousCallbacks(pref_store_contents);
+
+ if (!changed_paths_.empty()) {
+ base::TimeTicks checkpoint = base::TimeTicks::Now();
+ {
+ DictionaryHashStoreContents dictionary_contents(pref_store_contents);
+ std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
+ pref_hash_store_->BeginTransaction(&dictionary_contents));
+
+ std::unique_ptr<PrefHashStoreTransaction>
+ external_validation_hash_store_transaction;
+ if (external_validation_hash_store_pair_) {
+ external_validation_hash_store_transaction =
+ external_validation_hash_store_pair_->first->BeginTransaction(
+ external_validation_hash_store_pair_->second.get());
+ }
+
+ for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
+ it != changed_paths_.end(); ++it) {
+ const std::string& changed_path = it->first;
+ const TrackedPreference* changed_preference = it->second;
+ const base::Value* value = nullptr;
+ pref_store_contents->Get(changed_path, &value);
+ changed_preference->OnNewValue(value, hash_store_transaction.get());
+ }
+ changed_paths_.clear();
+ }
+ UMA_HISTOGRAM_TIMES("Settings.FilterSerializeDataTime",
+ base::TimeTicks::Now() - checkpoint);
+ }
+
+ return callback_pair;
+}
+
+void PrefHashFilter::FinalizeFilterOnLoad(
+ const PostFilterOnLoadCallback& post_filter_on_load_callback,
+ std::unique_ptr<base::DictionaryValue> pref_store_contents,
+ bool prefs_altered) {
+ DCHECK(pref_store_contents);
+ base::TimeTicks checkpoint = base::TimeTicks::Now();
+
+ bool did_reset = false;
+ {
+ DictionaryHashStoreContents dictionary_contents(pref_store_contents.get());
+ std::unique_ptr<PrefHashStoreTransaction> hash_store_transaction(
+ pref_hash_store_->BeginTransaction(&dictionary_contents));
+
+ std::unique_ptr<PrefHashStoreTransaction>
+ external_validation_hash_store_transaction;
+ if (external_validation_hash_store_pair_) {
+ external_validation_hash_store_transaction =
+ external_validation_hash_store_pair_->first->BeginTransaction(
+ external_validation_hash_store_pair_->second.get());
+ }
+
+ CleanupDeprecatedTrackedPreferences(pref_store_contents.get(),
+ hash_store_transaction.get());
+
+ if (report_super_mac_validity_) {
+ UMA_HISTOGRAM_BOOLEAN("Settings.HashesDictionaryTrusted",
+ hash_store_transaction->IsSuperMACValid());
+ }
+
+ for (auto it = tracked_paths_.begin(); it != tracked_paths_.end(); ++it) {
+ if (it->second->EnforceAndReport(
+ pref_store_contents.get(), hash_store_transaction.get(),
+ external_validation_hash_store_transaction.get())) {
+ did_reset = true;
+ prefs_altered = true;
+ }
+ }
+ if (hash_store_transaction->StampSuperMac())
+ prefs_altered = true;
+ }
+
+ if (did_reset) {
+ pref_store_contents->Set(user_prefs::kPreferenceResetTime,
+ new base::Value(base::Int64ToString(
+ base::Time::Now().ToInternalValue())));
+ FilterUpdate(user_prefs::kPreferenceResetTime);
+
+ if (reset_on_load_observer_)
+ reset_on_load_observer_->OnResetOnLoad();
+ }
+ reset_on_load_observer_.reset();
+
+ UMA_HISTOGRAM_TIMES("Settings.FilterOnLoadTime",
+ base::TimeTicks::Now() - checkpoint);
+
+ post_filter_on_load_callback.Run(std::move(pref_store_contents),
+ prefs_altered);
+}
+
+// static
+void PrefHashFilter::ClearFromExternalStore(
+ HashStoreContents* external_validation_hash_store_contents,
+ const base::DictionaryValue* changed_paths_and_macs) {
+ DCHECK(!changed_paths_and_macs->empty());
+
+ for (base::DictionaryValue::Iterator it(*changed_paths_and_macs);
+ !it.IsAtEnd(); it.Advance()) {
+ external_validation_hash_store_contents->RemoveEntry(it.key());
+ }
+}
+
+// static
+void PrefHashFilter::FlushToExternalStore(
+ std::unique_ptr<HashStoreContents> external_validation_hash_store_contents,
+ std::unique_ptr<base::DictionaryValue> changed_paths_and_macs,
+ bool write_success) {
+ DCHECK(!changed_paths_and_macs->empty());
+ DCHECK(external_validation_hash_store_contents);
+ if (!write_success)
+ return;
+
+ for (base::DictionaryValue::Iterator it(*changed_paths_and_macs);
+ !it.IsAtEnd(); it.Advance()) {
+ const std::string& changed_path = it.key();
+
+ const base::DictionaryValue* split_values = nullptr;
+ if (it.value().GetAsDictionary(&split_values)) {
+ for (base::DictionaryValue::Iterator inner_it(*split_values);
+ !inner_it.IsAtEnd(); inner_it.Advance()) {
+ std::string mac;
+ bool is_string = inner_it.value().GetAsString(&mac);
+ DCHECK(is_string);
+
+ external_validation_hash_store_contents->SetSplitMac(
+ changed_path, inner_it.key(), mac);
+ }
+ } else {
+ const base::Value* value_as_string;
+ bool is_string = it.value().GetAsString(&value_as_string);
+ DCHECK(is_string);
+
+ external_validation_hash_store_contents->SetMac(
+ changed_path, value_as_string->GetString());
+ }
+ }
+}
+
+PrefFilter::OnWriteCallbackPair PrefHashFilter::GetOnWriteSynchronousCallbacks(
+ base::DictionaryValue* pref_store_contents) {
+ if (changed_paths_.empty() || !external_validation_hash_store_pair_) {
+ return std::make_pair(base::Closure(),
+ base::Callback<void(bool success)>());
+ }
+
+ std::unique_ptr<base::DictionaryValue> changed_paths_macs =
+ base::MakeUnique<base::DictionaryValue>();
+
+ for (ChangedPathsMap::const_iterator it = changed_paths_.begin();
+ it != changed_paths_.end(); ++it) {
+ const std::string& changed_path = it->first;
+ const TrackedPreference* changed_preference = it->second;
+
+ switch (changed_preference->GetType()) {
+ case TrackedPreferenceType::ATOMIC: {
+ const base::Value* new_value = nullptr;
+ pref_store_contents->Get(changed_path, &new_value);
+ changed_paths_macs->SetStringWithoutPathExpansion(
+ changed_path,
+ external_validation_hash_store_pair_->first->ComputeMac(
+ changed_path, new_value));
+ break;
+ }
+ case TrackedPreferenceType::SPLIT: {
+ const base::DictionaryValue* dict_value = nullptr;
+ pref_store_contents->GetDictionary(changed_path, &dict_value);
+ changed_paths_macs->SetWithoutPathExpansion(
+ changed_path,
+ external_validation_hash_store_pair_->first->ComputeSplitMacs(
+ changed_path, dict_value));
+ break;
+ }
+ }
+ }
+
+ DCHECK(external_validation_hash_store_pair_->second->IsCopyable())
+ << "External HashStoreContents must be copyable as it needs to be used "
+ "off-thread";
+
+ std::unique_ptr<HashStoreContents> hash_store_contents_copy =
+ external_validation_hash_store_pair_->second->MakeCopy();
+
+ // We can use raw pointers for the first callback instead of making more
+ // copies as it will be executed in sequence before the second callback,
+ // which owns the pointers.
+ HashStoreContents* raw_contents = hash_store_contents_copy.get();
+ base::DictionaryValue* raw_changed_paths_macs = changed_paths_macs.get();
+
+ return std::make_pair(
+ base::Bind(&ClearFromExternalStore, base::Unretained(raw_contents),
+ base::Unretained(raw_changed_paths_macs)),
+ base::Bind(&FlushToExternalStore, base::Passed(&hash_store_contents_copy),
+ base::Passed(&changed_paths_macs)));
+}
diff --git a/chromium/services/preferences/tracked/pref_hash_filter.h b/chromium/services/preferences/tracked/pref_hash_filter.h
new file mode 100644
index 00000000000..4c3cdaa4996
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_filter.h
@@ -0,0 +1,157 @@
+// Copyright 2013 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_PREFERENCES_TRACKED_PREF_HASH_FILTER_H_
+#define SERVICES_PREFERENCES_TRACKED_PREF_HASH_FILTER_H_
+
+#include <stddef.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/optional.h"
+#include "services/preferences/public/interfaces/preferences_configuration.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"
+
+class PrefHashStore;
+class PrefService;
+
+namespace base {
+class DictionaryValue;
+class Time;
+} // namespace base
+
+namespace prefs {
+namespace mojom {
+class TrackedPreferenceValidationDelegate;
+}
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+} // namespace user_prefs
+
+// Intercepts preference values as they are loaded from disk and verifies them
+// using a PrefHashStore. Keeps the PrefHashStore contents up to date as values
+// are changed.
+class PrefHashFilter : public InterceptablePrefFilter {
+ public:
+ using StoreContentsPair = std::pair<std::unique_ptr<PrefHashStore>,
+ std::unique_ptr<HashStoreContents>>;
+
+ // Constructs a PrefHashFilter tracking the specified |tracked_preferences|
+ // using |pref_hash_store| to check/store hashes. An optional |delegate| is
+ // notified of the status of each preference as it is checked.
+ // If |reset_on_load_observer| is provided, it will be notified if a reset
+ // occurs in FilterOnLoad.
+ // |reporting_ids_count| is the count of all possible IDs (possibly greater
+ // than |tracked_preferences.size()|). If |report_super_mac_validity| is true,
+ // the state of the super MAC will be reported via UMA during
+ // FinalizeFilterOnLoad.
+ // |external_validation_hash_store_pair_| will be used (if non-null) to
+ // perform extra validations without triggering resets.
+ PrefHashFilter(std::unique_ptr<PrefHashStore> pref_hash_store,
+ StoreContentsPair external_validation_hash_store_pair_,
+ const std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>&
+ tracked_preferences,
+ prefs::mojom::ResetOnLoadObserverPtr reset_on_load_observer,
+ prefs::mojom::TrackedPreferenceValidationDelegate* delegate,
+ size_t reporting_ids_count,
+ bool report_super_mac_validity);
+
+ ~PrefHashFilter() override;
+
+ // Registers required user preferences.
+ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+ // Retrieves the time of the last reset event, if any, for the provided user
+ // preferences. If no reset has occurred, Returns a null |Time|.
+ static base::Time GetResetTime(PrefService* user_prefs);
+
+ // Clears the time of the last reset event, if any, for the provided user
+ // preferences.
+ static void ClearResetTime(PrefService* user_prefs);
+
+ // Initializes the PrefHashStore with hashes of the tracked preferences in
+ // |pref_store_contents|. |pref_store_contents| will be the |storage| passed
+ // to PrefHashStore::BeginTransaction().
+ void Initialize(base::DictionaryValue* pref_store_contents);
+
+ // PrefFilter remaining implementation.
+ void FilterUpdate(const std::string& path) override;
+ OnWriteCallbackPair FilterSerializeData(
+ base::DictionaryValue* pref_store_contents) override;
+
+ private:
+ // InterceptablePrefFilter implementation.
+ void FinalizeFilterOnLoad(
+ const PostFilterOnLoadCallback& post_filter_on_load_callback,
+ std::unique_ptr<base::DictionaryValue> pref_store_contents,
+ bool prefs_altered) override;
+
+ // Helper function to generate FilterSerializeData()'s pre-write and
+ // post-write callbacks. The returned callbacks are thread-safe.
+ OnWriteCallbackPair GetOnWriteSynchronousCallbacks(
+ base::DictionaryValue* pref_store_contents);
+
+ // Clears the MACs contained in |external_validation_hash_store_contents|
+ // which are present in |paths_to_clear|.
+ static void ClearFromExternalStore(
+ HashStoreContents* external_validation_hash_store_contents,
+ const base::DictionaryValue* changed_paths_and_macs);
+
+ // Flushes the MACs contained in |changed_paths_and_mac| to
+ // external_hash_store_contents if |write_success|, otherwise discards the
+ // changes.
+ static void FlushToExternalStore(
+ std::unique_ptr<HashStoreContents> external_hash_store_contents,
+ std::unique_ptr<base::DictionaryValue> changed_paths_and_macs,
+ bool write_success);
+
+ // Callback to be invoked only once (and subsequently reset) on the next
+ // FilterOnLoad event. It will be allowed to modify the |prefs| handed to
+ // FilterOnLoad before handing them back to this PrefHashFilter.
+ FilterOnLoadInterceptor filter_on_load_interceptor_;
+
+ // A map of paths to TrackedPreferences; this map owns this individual
+ // TrackedPreference objects.
+ using TrackedPreferencesMap =
+ std::unordered_map<std::string, std::unique_ptr<TrackedPreference>>;
+
+ // A map from changed paths to their corresponding TrackedPreferences (which
+ // aren't owned by this map).
+ using ChangedPathsMap = std::map<std::string, const TrackedPreference*>;
+
+ std::unique_ptr<PrefHashStore> pref_hash_store_;
+
+ // A store and contents on which to perform extra validations without
+ // triggering resets.
+ // Will be null if the platform does not support external validation.
+ const base::Optional<StoreContentsPair> external_validation_hash_store_pair_;
+
+ // Notified if a reset occurs in a call to FilterOnLoad.
+ prefs::mojom::ResetOnLoadObserverPtr reset_on_load_observer_;
+
+ TrackedPreferencesMap tracked_paths_;
+
+ // The set of all paths whose value has changed since the last call to
+ // FilterSerializeData.
+ ChangedPathsMap changed_paths_;
+
+ // Whether to report the validity of the super MAC at load time (via UMA).
+ bool report_super_mac_validity_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefHashFilter);
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_PREF_HASH_FILTER_H_
diff --git a/chromium/services/preferences/tracked/pref_hash_filter_unittest.cc b/chromium/services/preferences/tracked/pref_hash_filter_unittest.cc
new file mode 100644
index 00000000000..5c288dcc77d
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_filter_unittest.cc
@@ -0,0 +1,1355 @@
+// Copyright 2013 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/preferences/tracked/pref_hash_filter.h"
+
+#include <stddef.h>
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram_base.h"
+#include "base/metrics/histogram_samples.h"
+#include "base/metrics/statistics_recorder.h"
+#include "base/run_loop.h"
+#include "base/values.h"
+#include "components/prefs/testing_pref_store.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/preferences/public/cpp/tracked/configuration.h"
+#include "services/preferences/public/cpp/tracked/mock_validation_delegate.h"
+#include "services/preferences/public/cpp/tracked/pref_names.h"
+#include "services/preferences/tracked/hash_store_contents.h"
+#include "services/preferences/tracked/pref_hash_store.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using EnforcementLevel =
+ prefs::mojom::TrackedPreferenceMetadata::EnforcementLevel;
+using PrefTrackingStrategy =
+ prefs::mojom::TrackedPreferenceMetadata::PrefTrackingStrategy;
+using ValueType = prefs::mojom::TrackedPreferenceMetadata::ValueType;
+using ValueState =
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
+
+const char kAtomicPref[] = "atomic_pref";
+const char kAtomicPref2[] = "atomic_pref2";
+const char kAtomicPref3[] = "pref3";
+const char kAtomicPref4[] = "pref4";
+const char kReportOnlyPref[] = "report_only";
+const char kReportOnlySplitPref[] = "report_only_split_pref";
+const char kSplitPref[] = "split_pref";
+
+const prefs::TrackedPreferenceMetadata kTestTrackedPrefs[] = {
+ {0, kAtomicPref, EnforcementLevel::ENFORCE_ON_LOAD,
+ PrefTrackingStrategy::ATOMIC, ValueType::PERSONAL},
+ {1, kReportOnlyPref, EnforcementLevel::NO_ENFORCEMENT,
+ PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL},
+ {2, kSplitPref, EnforcementLevel::ENFORCE_ON_LOAD,
+ PrefTrackingStrategy::SPLIT, ValueType::IMPERSONAL},
+ {3, kReportOnlySplitPref, EnforcementLevel::NO_ENFORCEMENT,
+ PrefTrackingStrategy::SPLIT, ValueType::IMPERSONAL},
+ {4, kAtomicPref2, EnforcementLevel::ENFORCE_ON_LOAD,
+ PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL},
+ {5, kAtomicPref3, EnforcementLevel::ENFORCE_ON_LOAD,
+ PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL},
+ {6, kAtomicPref4, EnforcementLevel::ENFORCE_ON_LOAD,
+ PrefTrackingStrategy::ATOMIC, ValueType::IMPERSONAL},
+};
+
+} // namespace
+
+// A PrefHashStore that allows simulation of CheckValue results and captures
+// checked and stored values.
+class MockPrefHashStore : public PrefHashStore {
+ public:
+ typedef std::pair<const void*, PrefTrackingStrategy> ValuePtrStrategyPair;
+
+ MockPrefHashStore()
+ : stamp_super_mac_result_(false),
+ is_super_mac_valid_result_(false),
+ transactions_performed_(0),
+ transaction_active_(false) {}
+
+ ~MockPrefHashStore() override { EXPECT_FALSE(transaction_active_); }
+
+ // Set the result that will be returned when |path| is passed to
+ // |CheckValue/CheckSplitValue|.
+ void SetCheckResult(const std::string& path, ValueState result);
+
+ // Set the invalid_keys that will be returned when |path| is passed to
+ // |CheckSplitValue|. SetCheckResult should already have been called for
+ // |path| with |result == CHANGED| for this to make any sense.
+ void SetInvalidKeysResult(
+ const std::string& path,
+ const std::vector<std::string>& invalid_keys_result);
+
+ // Sets the value that will be returned from
+ // PrefHashStoreTransaction::StampSuperMAC().
+ void set_stamp_super_mac_result(bool result) {
+ stamp_super_mac_result_ = result;
+ }
+
+ // Sets the value that will be returned from
+ // PrefHashStoreTransaction::IsSuperMACValid().
+ void set_is_super_mac_valid_result(bool result) {
+ is_super_mac_valid_result_ = result;
+ }
+
+ // Returns the number of transactions that were performed.
+ size_t transactions_performed() { return transactions_performed_; }
+
+ // Returns the number of paths checked.
+ size_t checked_paths_count() const { return checked_values_.size(); }
+
+ // Returns the number of paths stored.
+ size_t stored_paths_count() const { return stored_values_.size(); }
+
+ // Returns the pointer value and strategy that was passed to
+ // |CheckHash/CheckSplitHash| for |path|. The returned pointer could since
+ // have been freed and is thus not safe to dereference.
+ ValuePtrStrategyPair checked_value(const std::string& path) const {
+ std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
+ checked_values_.find(path);
+ if (value != checked_values_.end())
+ return value->second;
+ return std::make_pair(reinterpret_cast<void*>(0xBAD),
+ static_cast<PrefTrackingStrategy>(-1));
+ }
+
+ // Returns the pointer value that was passed to |StoreHash/StoreSplitHash| for
+ // |path|. The returned pointer could since have been freed and is thus not
+ // safe to dereference.
+ ValuePtrStrategyPair stored_value(const std::string& path) const {
+ std::map<std::string, ValuePtrStrategyPair>::const_iterator value =
+ stored_values_.find(path);
+ if (value != stored_values_.end())
+ return value->second;
+ return std::make_pair(reinterpret_cast<void*>(0xBAD),
+ static_cast<PrefTrackingStrategy>(-1));
+ }
+
+ // PrefHashStore implementation.
+ std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
+ HashStoreContents* storage) override;
+ std::string ComputeMac(const std::string& path,
+ const base::Value* new_value) override;
+ std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) override;
+
+ private:
+ // A MockPrefHashStoreTransaction is handed to the caller on
+ // MockPrefHashStore::BeginTransaction(). It then stores state in its
+ // underlying MockPrefHashStore about calls it receives from that same caller
+ // which can later be verified in tests.
+ class MockPrefHashStoreTransaction : public PrefHashStoreTransaction {
+ public:
+ explicit MockPrefHashStoreTransaction(MockPrefHashStore* outer)
+ : outer_(outer) {}
+
+ ~MockPrefHashStoreTransaction() override {
+ outer_->transaction_active_ = false;
+ ++outer_->transactions_performed_;
+ }
+
+ // PrefHashStoreTransaction implementation.
+ base::StringPiece GetStoreUMASuffix() const override;
+ ValueState CheckValue(const std::string& path,
+ const base::Value* value) const override;
+ void StoreHash(const std::string& path,
+ const base::Value* new_value) override;
+ ValueState CheckSplitValue(
+ const std::string& path,
+ const base::DictionaryValue* initial_split_value,
+ std::vector<std::string>* invalid_keys) const override;
+ void StoreSplitHash(const std::string& path,
+ const base::DictionaryValue* split_value) override;
+ bool HasHash(const std::string& path) const override;
+ void ImportHash(const std::string& path, const base::Value* hash) override;
+ void ClearHash(const std::string& path) override;
+ bool IsSuperMACValid() const override;
+ bool StampSuperMac() override;
+
+ private:
+ MockPrefHashStore* outer_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPrefHashStoreTransaction);
+ };
+
+ // Records a call to this mock's CheckValue/CheckSplitValue methods.
+ ValueState RecordCheckValue(const std::string& path,
+ const base::Value* value,
+ PrefTrackingStrategy strategy);
+
+ // Records a call to this mock's StoreHash/StoreSplitHash methods.
+ void RecordStoreHash(const std::string& path,
+ const base::Value* new_value,
+ PrefTrackingStrategy strategy);
+
+ std::map<std::string, ValueState> check_results_;
+ std::map<std::string, std::vector<std::string>> invalid_keys_results_;
+
+ bool stamp_super_mac_result_;
+ bool is_super_mac_valid_result_;
+
+ std::map<std::string, ValuePtrStrategyPair> checked_values_;
+ std::map<std::string, ValuePtrStrategyPair> stored_values_;
+
+ // Number of transactions that were performed via this MockPrefHashStore.
+ size_t transactions_performed_;
+
+ // Whether a transaction is currently active (only one transaction should be
+ // active at a time).
+ bool transaction_active_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockPrefHashStore);
+};
+
+void MockPrefHashStore::SetCheckResult(const std::string& path,
+ ValueState result) {
+ check_results_.insert(std::make_pair(path, result));
+}
+
+void MockPrefHashStore::SetInvalidKeysResult(
+ const std::string& path,
+ const std::vector<std::string>& invalid_keys_result) {
+ // Ensure |check_results_| has a CHANGED entry for |path|.
+ std::map<std::string, ValueState>::const_iterator result =
+ check_results_.find(path);
+ ASSERT_TRUE(result != check_results_.end());
+ ASSERT_EQ(ValueState::CHANGED, result->second);
+
+ invalid_keys_results_.insert(std::make_pair(path, invalid_keys_result));
+}
+
+std::unique_ptr<PrefHashStoreTransaction> MockPrefHashStore::BeginTransaction(
+ HashStoreContents* storage) {
+ EXPECT_FALSE(transaction_active_);
+ return std::unique_ptr<PrefHashStoreTransaction>(
+ new MockPrefHashStoreTransaction(this));
+}
+
+std::string MockPrefHashStore::ComputeMac(const std::string& path,
+ const base::Value* new_value) {
+ return "atomic mac for: " + path;
+};
+
+std::unique_ptr<base::DictionaryValue> MockPrefHashStore::ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) {
+ std::unique_ptr<base::DictionaryValue> macs_dict(new base::DictionaryValue);
+ for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd();
+ it.Advance()) {
+ macs_dict->SetStringWithoutPathExpansion(
+ it.key(), "split mac for: " + path + "/" + it.key());
+ }
+ return macs_dict;
+};
+
+ValueState MockPrefHashStore::RecordCheckValue(const std::string& path,
+ const base::Value* value,
+ PrefTrackingStrategy strategy) {
+ // Record that |path| was checked and validate that it wasn't previously
+ // checked.
+ EXPECT_TRUE(checked_values_
+ .insert(std::make_pair(path, std::make_pair(value, strategy)))
+ .second);
+ std::map<std::string, ValueState>::const_iterator result =
+ check_results_.find(path);
+ if (result != check_results_.end())
+ return result->second;
+ return ValueState::UNCHANGED;
+}
+
+void MockPrefHashStore::RecordStoreHash(const std::string& path,
+ const base::Value* new_value,
+ PrefTrackingStrategy strategy) {
+ EXPECT_TRUE(
+ stored_values_
+ .insert(std::make_pair(path, std::make_pair(new_value, strategy)))
+ .second);
+}
+
+base::StringPiece
+MockPrefHashStore::MockPrefHashStoreTransaction ::GetStoreUMASuffix() const {
+ return "unused";
+}
+
+ValueState MockPrefHashStore::MockPrefHashStoreTransaction::CheckValue(
+ const std::string& path,
+ const base::Value* value) const {
+ return outer_->RecordCheckValue(path, value, PrefTrackingStrategy::ATOMIC);
+}
+
+void MockPrefHashStore::MockPrefHashStoreTransaction::StoreHash(
+ const std::string& path,
+ const base::Value* new_value) {
+ outer_->RecordStoreHash(path, new_value, PrefTrackingStrategy::ATOMIC);
+}
+
+ValueState MockPrefHashStore::MockPrefHashStoreTransaction::CheckSplitValue(
+ const std::string& path,
+ const base::DictionaryValue* initial_split_value,
+ std::vector<std::string>* invalid_keys) const {
+ EXPECT_TRUE(invalid_keys && invalid_keys->empty());
+
+ std::map<std::string, std::vector<std::string>>::const_iterator
+ invalid_keys_result = outer_->invalid_keys_results_.find(path);
+ if (invalid_keys_result != outer_->invalid_keys_results_.end()) {
+ invalid_keys->insert(invalid_keys->begin(),
+ invalid_keys_result->second.begin(),
+ invalid_keys_result->second.end());
+ }
+
+ return outer_->RecordCheckValue(path, initial_split_value,
+ PrefTrackingStrategy::SPLIT);
+}
+
+void MockPrefHashStore::MockPrefHashStoreTransaction::StoreSplitHash(
+ const std::string& path,
+ const base::DictionaryValue* new_value) {
+ outer_->RecordStoreHash(path, new_value, PrefTrackingStrategy::SPLIT);
+}
+
+bool MockPrefHashStore::MockPrefHashStoreTransaction::HasHash(
+ const std::string& path) const {
+ ADD_FAILURE() << "Unexpected call.";
+ return false;
+}
+
+void MockPrefHashStore::MockPrefHashStoreTransaction::ImportHash(
+ const std::string& path,
+ const base::Value* hash) {
+ ADD_FAILURE() << "Unexpected call.";
+}
+
+void MockPrefHashStore::MockPrefHashStoreTransaction::ClearHash(
+ const std::string& path) {
+ // Allow this to be called by PrefHashFilter's deprecated tracked prefs
+ // cleanup tasks.
+}
+
+bool MockPrefHashStore::MockPrefHashStoreTransaction::IsSuperMACValid() const {
+ return outer_->is_super_mac_valid_result_;
+}
+
+bool MockPrefHashStore::MockPrefHashStoreTransaction::StampSuperMac() {
+ return outer_->stamp_super_mac_result_;
+}
+
+std::vector<prefs::mojom::TrackedPreferenceMetadataPtr> GetConfiguration(
+ EnforcementLevel max_enforcement_level) {
+ auto configuration = prefs::ConstructTrackedConfiguration(kTestTrackedPrefs);
+ for (const auto& metadata : configuration) {
+ if (metadata->enforcement_level > max_enforcement_level)
+ metadata->enforcement_level = max_enforcement_level;
+ }
+ return configuration;
+}
+
+class MockHashStoreContents : public HashStoreContents {
+ public:
+ MockHashStoreContents(){};
+
+ // Returns the number of hashes stored.
+ size_t stored_hashes_count() const { return dictionary_.size(); }
+
+ // Returns the number of paths cleared.
+ size_t cleared_paths_count() const { return removed_entries_.size(); }
+
+ // Returns the stored MAC for an Atomic preference.
+ std::string GetStoredMac(const std::string& path) const;
+ // Returns the stored MAC for a Split preference.
+ std::string GetStoredSplitMac(const std::string& path,
+ const std::string& split_path) const;
+
+ // HashStoreContents implementation.
+ bool IsCopyable() const override;
+ std::unique_ptr<HashStoreContents> MakeCopy() const override;
+ base::StringPiece GetUMASuffix() const override;
+ void Reset() override;
+ bool GetMac(const std::string& path, std::string* out_value) override;
+ bool GetSplitMacs(const std::string& path,
+ std::map<std::string, std::string>* split_macs) override;
+ void SetMac(const std::string& path, const std::string& value) override;
+ void SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) override;
+ void ImportEntry(const std::string& path,
+ const base::Value* in_value) override;
+ bool RemoveEntry(const std::string& path) override;
+ const base::DictionaryValue* GetContents() const override;
+ std::string GetSuperMac() const override;
+ void SetSuperMac(const std::string& super_mac) override;
+
+ private:
+ MockHashStoreContents(MockHashStoreContents* origin_mock);
+
+ // Records calls to this mock's SetMac/SetSplitMac methods.
+ void RecordSetMac(const std::string& path, const std::string& mac) {
+ dictionary_.SetStringWithoutPathExpansion(path, mac);
+ }
+ void RecordSetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& mac) {
+ base::DictionaryValue* mac_dict = nullptr;
+ dictionary_.GetDictionaryWithoutPathExpansion(path, &mac_dict);
+ if (!mac_dict) {
+ mac_dict = new base::DictionaryValue;
+ dictionary_.SetWithoutPathExpansion(path, mac_dict);
+ }
+ mac_dict->SetStringWithoutPathExpansion(split_path, mac);
+ }
+
+ // Records a call to this mock's RemoveEntry method.
+ void RecordRemoveEntry(const std::string& path) {
+ // Don't expect the same pref to be cleared more than once.
+ EXPECT_EQ(removed_entries_.end(), removed_entries_.find(path));
+ removed_entries_.insert(path);
+ }
+
+ base::DictionaryValue dictionary_;
+ std::set<std::string> removed_entries_;
+
+ // The code being tested copies its HashStoreContents for use in a callback
+ // which can be executed during shutdown. To be able to capture the behavior
+ // of the copy, we make it forward calls to the mock it was created from.
+ // Once set, |origin_mock_| must outlive this instance.
+ MockHashStoreContents* origin_mock_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockHashStoreContents);
+};
+
+std::string MockHashStoreContents::GetStoredMac(const std::string& path) const {
+ const base::Value* out_value;
+ if (dictionary_.GetWithoutPathExpansion(path, &out_value)) {
+ const base::Value* value_as_string;
+ EXPECT_TRUE(out_value->GetAsString(&value_as_string));
+
+ return value_as_string->GetString();
+ }
+
+ return std::string();
+}
+
+std::string MockHashStoreContents::GetStoredSplitMac(
+ const std::string& path,
+ const std::string& split_path) const {
+ const base::Value* out_value;
+ if (dictionary_.GetWithoutPathExpansion(path, &out_value)) {
+ const base::DictionaryValue* value_as_dict;
+ EXPECT_TRUE(out_value->GetAsDictionary(&value_as_dict));
+
+ if (value_as_dict->GetWithoutPathExpansion(split_path, &out_value)) {
+ const base::Value* value_as_string;
+ EXPECT_TRUE(out_value->GetAsString(&value_as_string));
+
+ return value_as_string->GetString();
+ }
+ }
+
+ return std::string();
+}
+
+MockHashStoreContents::MockHashStoreContents(MockHashStoreContents* origin_mock)
+ : origin_mock_(origin_mock) {}
+
+bool MockHashStoreContents::IsCopyable() const {
+ return true;
+}
+
+std::unique_ptr<HashStoreContents> MockHashStoreContents::MakeCopy() const {
+ // Return a new MockHashStoreContents which forwards all requests to this
+ // mock instance.
+ return std::unique_ptr<HashStoreContents>(
+ new MockHashStoreContents(const_cast<MockHashStoreContents*>(this)));
+}
+
+base::StringPiece MockHashStoreContents::GetUMASuffix() const {
+ return "Unused";
+}
+
+void MockHashStoreContents::Reset() {
+ ADD_FAILURE() << "Unexpected call.";
+}
+
+bool MockHashStoreContents::GetMac(const std::string& path,
+ std::string* out_value) {
+ ADD_FAILURE() << "Unexpected call.";
+ return false;
+}
+
+bool MockHashStoreContents::GetSplitMacs(
+ const std::string& path,
+ std::map<std::string, std::string>* split_macs) {
+ ADD_FAILURE() << "Unexpected call.";
+ return false;
+}
+
+void MockHashStoreContents::SetMac(const std::string& path,
+ const std::string& value) {
+ if (origin_mock_)
+ origin_mock_->RecordSetMac(path, value);
+ else
+ RecordSetMac(path, value);
+}
+
+void MockHashStoreContents::SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) {
+ if (origin_mock_)
+ origin_mock_->RecordSetSplitMac(path, split_path, value);
+ else
+ RecordSetSplitMac(path, split_path, value);
+}
+
+void MockHashStoreContents::ImportEntry(const std::string& path,
+ const base::Value* in_value) {
+ ADD_FAILURE() << "Unexpected call.";
+}
+
+bool MockHashStoreContents::RemoveEntry(const std::string& path) {
+ if (origin_mock_)
+ origin_mock_->RecordRemoveEntry(path);
+ else
+ RecordRemoveEntry(path);
+ return true;
+}
+
+const base::DictionaryValue* MockHashStoreContents::GetContents() const {
+ ADD_FAILURE() << "Unexpected call.";
+ return nullptr;
+}
+
+std::string MockHashStoreContents::GetSuperMac() const {
+ ADD_FAILURE() << "Unexpected call.";
+ return std::string();
+}
+
+void MockHashStoreContents::SetSuperMac(const std::string& super_mac) {
+ ADD_FAILURE() << "Unexpected call.";
+}
+
+class PrefHashFilterTest : public testing::TestWithParam<EnforcementLevel>,
+ public prefs::mojom::ResetOnLoadObserver {
+ public:
+ PrefHashFilterTest()
+ : mock_pref_hash_store_(NULL),
+ pref_store_contents_(new base::DictionaryValue),
+ mock_validation_delegate_record_(new MockValidationDelegateRecord),
+ mock_validation_delegate_(mock_validation_delegate_record_),
+ reset_recorded_(false) {}
+
+ void SetUp() override {
+ base::StatisticsRecorder::Initialize();
+ Reset();
+ }
+
+ protected:
+ // Reset the PrefHashFilter instance.
+ void Reset() {
+ // Construct a PrefHashFilter and MockPrefHashStore for the test.
+ InitializePrefHashFilter(GetConfiguration(GetParam()));
+ }
+
+ // Initializes |pref_hash_filter_| with a PrefHashFilter that uses a
+ // MockPrefHashStore. The raw pointer to the MockPrefHashStore (owned by the
+ // PrefHashFilter) is stored in |mock_pref_hash_store_|.
+ void InitializePrefHashFilter(
+ std::vector<prefs::mojom::TrackedPreferenceMetadataPtr> configuration) {
+ std::unique_ptr<MockPrefHashStore> temp_mock_pref_hash_store(
+ new MockPrefHashStore);
+ std::unique_ptr<MockPrefHashStore>
+ temp_mock_external_validation_pref_hash_store(new MockPrefHashStore);
+ std::unique_ptr<MockHashStoreContents>
+ temp_mock_external_validation_hash_store_contents(
+ new MockHashStoreContents);
+ mock_pref_hash_store_ = temp_mock_pref_hash_store.get();
+ mock_external_validation_pref_hash_store_ =
+ temp_mock_external_validation_pref_hash_store.get();
+ mock_external_validation_hash_store_contents_ =
+ temp_mock_external_validation_hash_store_contents.get();
+ pref_hash_filter_.reset(new PrefHashFilter(
+ std::move(temp_mock_pref_hash_store),
+ PrefHashFilter::StoreContentsPair(
+ std::move(temp_mock_external_validation_pref_hash_store),
+ std::move(temp_mock_external_validation_hash_store_contents)),
+ std::move(configuration),
+ reset_on_load_observer_bindings_.CreateInterfacePtrAndBind(this),
+ &mock_validation_delegate_, arraysize(kTestTrackedPrefs), true));
+ }
+
+ // Verifies whether a reset was reported by the PrefHashFiler. Also verifies
+ // that kPreferenceResetTime was set (or not) accordingly.
+ void VerifyRecordedReset(bool reset_expected) {
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(reset_expected, reset_recorded_);
+ EXPECT_EQ(reset_expected, pref_store_contents_->Get(
+ user_prefs::kPreferenceResetTime, NULL));
+ }
+
+ // Calls FilterOnLoad() on |pref_hash_Filter_|. |pref_store_contents_| is
+ // handed off, but should be given back to us synchronously through
+ // GetPrefsBack() as there is no FilterOnLoadInterceptor installed on
+ // |pref_hash_filter_|.
+ void DoFilterOnLoad(bool expect_prefs_modifications) {
+ pref_hash_filter_->FilterOnLoad(
+ base::Bind(&PrefHashFilterTest::GetPrefsBack, base::Unretained(this),
+ expect_prefs_modifications),
+ std::move(pref_store_contents_));
+ }
+
+ MockPrefHashStore* mock_pref_hash_store_;
+ MockPrefHashStore* mock_external_validation_pref_hash_store_;
+ MockHashStoreContents* mock_external_validation_hash_store_contents_;
+ std::unique_ptr<base::DictionaryValue> pref_store_contents_;
+ scoped_refptr<MockValidationDelegateRecord> mock_validation_delegate_record_;
+ std::unique_ptr<PrefHashFilter> pref_hash_filter_;
+
+ private:
+ // Stores |prefs| back in |pref_store_contents| and ensure
+ // |expected_schedule_write| matches the reported |schedule_write|.
+ void GetPrefsBack(bool expected_schedule_write,
+ std::unique_ptr<base::DictionaryValue> prefs,
+ bool schedule_write) {
+ pref_store_contents_ = std::move(prefs);
+ EXPECT_TRUE(pref_store_contents_);
+ EXPECT_EQ(expected_schedule_write, schedule_write);
+ }
+
+ void OnResetOnLoad() override {
+ // As-is |reset_recorded_| is only designed to remember a single reset, make
+ // sure none was previously recorded.
+ EXPECT_FALSE(reset_recorded_);
+ reset_recorded_ = true;
+ }
+
+ base::MessageLoop message_loop_;
+ MockValidationDelegate mock_validation_delegate_;
+ mojo::BindingSet<prefs::mojom::ResetOnLoadObserver>
+ reset_on_load_observer_bindings_;
+ bool reset_recorded_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefHashFilterTest);
+};
+
+TEST_P(PrefHashFilterTest, EmptyAndUnchanged) {
+ DoFilterOnLoad(false);
+ // All paths checked.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_pref_hash_store_->checked_paths_count());
+ // No paths stored, since they all return |UNCHANGED|.
+ ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+ // Since there was nothing in |pref_store_contents_| the checked value should
+ // have been NULL for all tracked preferences.
+ for (size_t i = 0; i < arraysize(kTestTrackedPrefs); ++i) {
+ ASSERT_EQ(
+ NULL,
+ mock_pref_hash_store_->checked_value(kTestTrackedPrefs[i].name).first);
+ }
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+ VerifyRecordedReset(false);
+
+ // Delegate saw all paths, and all unchanged.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->recorded_validations_count());
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNCHANGED));
+}
+
+TEST_P(PrefHashFilterTest, StampSuperMACAltersStore) {
+ mock_pref_hash_store_->set_stamp_super_mac_result(true);
+ DoFilterOnLoad(true);
+ // No paths stored, since they all return |UNCHANGED|. The StampSuperMAC
+ // result is the only reason the prefs were considered altered.
+ ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+}
+
+TEST_P(PrefHashFilterTest, FilterTrackedPrefUpdate) {
+ base::DictionaryValue root_dict;
+ // Ownership of |string_value| is transfered to |root_dict|.
+ base::Value* string_value = new base::Value("string value");
+ root_dict.Set(kAtomicPref, string_value);
+
+ // No path should be stored on FilterUpdate.
+ pref_hash_filter_->FilterUpdate(kAtomicPref);
+ ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+
+ // One path should be stored on FilterSerializeData.
+ pref_hash_filter_->FilterSerializeData(&root_dict);
+ ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
+ MockPrefHashStore::ValuePtrStrategyPair stored_value =
+ mock_pref_hash_store_->stored_value(kAtomicPref);
+ ASSERT_EQ(string_value, stored_value.first);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value.second);
+
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+ VerifyRecordedReset(false);
+}
+
+TEST_P(PrefHashFilterTest, ReportSuperMacValidity) {
+ // Do this once just to force the histogram to be defined.
+ DoFilterOnLoad(false);
+
+ base::HistogramBase* histogram = base::StatisticsRecorder::FindHistogram(
+ "Settings.HashesDictionaryTrusted");
+ ASSERT_TRUE(histogram);
+
+ base::HistogramBase::Count initial_untrusted =
+ histogram->SnapshotSamples()->GetCount(0);
+ base::HistogramBase::Count initial_trusted =
+ histogram->SnapshotSamples()->GetCount(1);
+
+ Reset();
+
+ // Run with an invalid super MAC.
+ mock_pref_hash_store_->set_is_super_mac_valid_result(false);
+
+ DoFilterOnLoad(false);
+
+ // Verify that the invalidity was reported.
+ ASSERT_EQ(initial_untrusted + 1, histogram->SnapshotSamples()->GetCount(0));
+ ASSERT_EQ(initial_trusted, histogram->SnapshotSamples()->GetCount(1));
+
+ Reset();
+
+ // Run with a valid super MAC.
+ mock_pref_hash_store_->set_is_super_mac_valid_result(true);
+
+ DoFilterOnLoad(false);
+
+ // Verify that the validity was reported.
+ ASSERT_EQ(initial_untrusted + 1, histogram->SnapshotSamples()->GetCount(0));
+ ASSERT_EQ(initial_trusted + 1, histogram->SnapshotSamples()->GetCount(1));
+}
+
+TEST_P(PrefHashFilterTest, FilterSplitPrefUpdate) {
+ base::DictionaryValue root_dict;
+ // Ownership of |dict_value| is transfered to |root_dict|.
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->SetString("a", "foo");
+ dict_value->SetInteger("b", 1234);
+ root_dict.Set(kSplitPref, dict_value);
+
+ // No path should be stored on FilterUpdate.
+ pref_hash_filter_->FilterUpdate(kSplitPref);
+ ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+
+ // One path should be stored on FilterSerializeData.
+ pref_hash_filter_->FilterSerializeData(&root_dict);
+ ASSERT_EQ(1u, mock_pref_hash_store_->stored_paths_count());
+ MockPrefHashStore::ValuePtrStrategyPair stored_value =
+ mock_pref_hash_store_->stored_value(kSplitPref);
+ ASSERT_EQ(dict_value, stored_value.first);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_value.second);
+
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+ VerifyRecordedReset(false);
+}
+
+TEST_P(PrefHashFilterTest, FilterUntrackedPrefUpdate) {
+ base::DictionaryValue root_dict;
+ root_dict.Set("untracked", new base::Value("some value"));
+ pref_hash_filter_->FilterUpdate("untracked");
+
+ // No paths should be stored on FilterUpdate.
+ ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+
+ // Nor on FilterSerializeData.
+ pref_hash_filter_->FilterSerializeData(&root_dict);
+ ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+
+ // No transaction should even be started on FilterSerializeData() if there are
+ // no updates to perform.
+ ASSERT_EQ(0u, mock_pref_hash_store_->transactions_performed());
+}
+
+TEST_P(PrefHashFilterTest, MultiplePrefsFilterSerializeData) {
+ base::DictionaryValue root_dict;
+ // Ownership of the following values is transfered to |root_dict|.
+ base::Value* int_value1 = new base::Value(1);
+ base::Value* int_value2 = new base::Value(2);
+ base::Value* int_value3 = new base::Value(3);
+ base::Value* int_value4 = new base::Value(4);
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->Set("a", new base::Value(true));
+ root_dict.Set(kAtomicPref, int_value1);
+ root_dict.Set(kAtomicPref2, int_value2);
+ root_dict.Set(kAtomicPref3, int_value3);
+ root_dict.Set("untracked", int_value4);
+ root_dict.Set(kSplitPref, dict_value);
+
+ // Only update kAtomicPref, kAtomicPref3, and kSplitPref.
+ pref_hash_filter_->FilterUpdate(kAtomicPref);
+ pref_hash_filter_->FilterUpdate(kAtomicPref3);
+ pref_hash_filter_->FilterUpdate(kSplitPref);
+ ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+
+ // Update kAtomicPref3 again, nothing should be stored still.
+ base::Value* int_value5 = new base::Value(5);
+ root_dict.Set(kAtomicPref3, int_value5);
+ ASSERT_EQ(0u, mock_pref_hash_store_->stored_paths_count());
+
+ // On FilterSerializeData, only kAtomicPref, kAtomicPref3, and kSplitPref
+ // should get a new hash.
+ pref_hash_filter_->FilterSerializeData(&root_dict);
+ ASSERT_EQ(3u, mock_pref_hash_store_->stored_paths_count());
+ MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic1 =
+ mock_pref_hash_store_->stored_value(kAtomicPref);
+ ASSERT_EQ(int_value1, stored_value_atomic1.first);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value_atomic1.second);
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+
+ MockPrefHashStore::ValuePtrStrategyPair stored_value_atomic3 =
+ mock_pref_hash_store_->stored_value(kAtomicPref3);
+ ASSERT_EQ(int_value5, stored_value_atomic3.first);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_value_atomic3.second);
+
+ MockPrefHashStore::ValuePtrStrategyPair stored_value_split =
+ mock_pref_hash_store_->stored_value(kSplitPref);
+ ASSERT_EQ(dict_value, stored_value_split.first);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_value_split.second);
+}
+
+TEST_P(PrefHashFilterTest, UnknownNullValue) {
+ ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
+ // NULL values are always trusted by the PrefHashStore.
+ mock_pref_hash_store_->SetCheckResult(kAtomicPref,
+ ValueState::TRUSTED_NULL_VALUE);
+ mock_pref_hash_store_->SetCheckResult(kSplitPref,
+ ValueState::TRUSTED_NULL_VALUE);
+ DoFilterOnLoad(false);
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+
+ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+ mock_pref_hash_store_->stored_value(kAtomicPref);
+ ASSERT_EQ(NULL, stored_atomic_value.first);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
+
+ MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+ mock_pref_hash_store_->stored_value(kSplitPref);
+ ASSERT_EQ(NULL, stored_split_value.first);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+
+ // Delegate saw all prefs, two of which had the expected value_state.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->recorded_validations_count());
+ ASSERT_EQ(2u, mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::TRUSTED_NULL_VALUE));
+ ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
+ mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNCHANGED));
+
+ const MockValidationDelegateRecord::ValidationEvent* validated_split_pref =
+ mock_validation_delegate_record_->GetEventForPath(kSplitPref);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, validated_split_pref->strategy);
+ ASSERT_FALSE(validated_split_pref->is_personal);
+ const MockValidationDelegateRecord::ValidationEvent* validated_atomic_pref =
+ mock_validation_delegate_record_->GetEventForPath(kAtomicPref);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, validated_atomic_pref->strategy);
+ ASSERT_TRUE(validated_atomic_pref->is_personal);
+}
+
+TEST_P(PrefHashFilterTest, InitialValueUnknown) {
+ // Ownership of these values is transfered to |pref_store_contents_|.
+ base::Value* string_value = new base::Value("string value");
+ pref_store_contents_->Set(kAtomicPref, string_value);
+
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->SetString("a", "foo");
+ dict_value->SetInteger("b", 1234);
+ pref_store_contents_->Set(kSplitPref, dict_value);
+
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
+
+ mock_pref_hash_store_->SetCheckResult(kAtomicPref,
+ ValueState::UNTRUSTED_UNKNOWN_VALUE);
+ mock_pref_hash_store_->SetCheckResult(kSplitPref,
+ ValueState::UNTRUSTED_UNKNOWN_VALUE);
+ // If we are enforcing, expect this to report changes.
+ DoFilterOnLoad(GetParam() >= EnforcementLevel::ENFORCE_ON_LOAD);
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+
+ // Delegate saw all prefs, two of which had the expected value_state.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->recorded_validations_count());
+ ASSERT_EQ(2u, mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNTRUSTED_UNKNOWN_VALUE));
+ ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
+ mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNCHANGED));
+
+ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+ mock_pref_hash_store_->stored_value(kAtomicPref);
+ MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+ mock_pref_hash_store_->stored_value(kSplitPref);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+ if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) {
+ // Ensure the prefs were cleared and the hashes for NULL were restored if
+ // the current enforcement level denies seeding.
+ ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_EQ(NULL, stored_atomic_value.first);
+
+ ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
+ ASSERT_EQ(NULL, stored_split_value.first);
+
+ VerifyRecordedReset(true);
+ } else {
+ // Otherwise the values should have remained intact and the hashes should
+ // have been updated to match them.
+ const base::Value* atomic_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
+ ASSERT_EQ(string_value, atomic_value_in_store);
+ ASSERT_EQ(string_value, stored_atomic_value.first);
+
+ const base::Value* split_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
+ ASSERT_EQ(dict_value, split_value_in_store);
+ ASSERT_EQ(dict_value, stored_split_value.first);
+
+ VerifyRecordedReset(false);
+ }
+}
+
+TEST_P(PrefHashFilterTest, InitialValueTrustedUnknown) {
+ // Ownership of this value is transfered to |pref_store_contents_|.
+ base::Value* string_value = new base::Value("test");
+ pref_store_contents_->Set(kAtomicPref, string_value);
+
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->SetString("a", "foo");
+ dict_value->SetInteger("b", 1234);
+ pref_store_contents_->Set(kSplitPref, dict_value);
+
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
+
+ mock_pref_hash_store_->SetCheckResult(kAtomicPref,
+ ValueState::TRUSTED_UNKNOWN_VALUE);
+ mock_pref_hash_store_->SetCheckResult(kSplitPref,
+ ValueState::TRUSTED_UNKNOWN_VALUE);
+ DoFilterOnLoad(false);
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+
+ // Delegate saw all prefs, two of which had the expected value_state.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->recorded_validations_count());
+ ASSERT_EQ(2u, mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::TRUSTED_UNKNOWN_VALUE));
+ ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
+ mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNCHANGED));
+
+ // Seeding is always allowed for trusted unknown values.
+ const base::Value* atomic_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
+ ASSERT_EQ(string_value, atomic_value_in_store);
+ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+ mock_pref_hash_store_->stored_value(kAtomicPref);
+ ASSERT_EQ(string_value, stored_atomic_value.first);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
+
+ const base::Value* split_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
+ ASSERT_EQ(dict_value, split_value_in_store);
+ MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+ mock_pref_hash_store_->stored_value(kSplitPref);
+ ASSERT_EQ(dict_value, stored_split_value.first);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+}
+
+TEST_P(PrefHashFilterTest, InitialValueChanged) {
+ // Ownership of this value is transfered to |pref_store_contents_|.
+ base::Value* int_value = new base::Value(1234);
+ pref_store_contents_->Set(kAtomicPref, int_value);
+
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->SetString("a", "foo");
+ dict_value->SetInteger("b", 1234);
+ dict_value->SetInteger("c", 56);
+ dict_value->SetBoolean("d", false);
+ pref_store_contents_->Set(kSplitPref, dict_value);
+
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
+
+ mock_pref_hash_store_->SetCheckResult(kAtomicPref, ValueState::CHANGED);
+ mock_pref_hash_store_->SetCheckResult(kSplitPref, ValueState::CHANGED);
+
+ std::vector<std::string> mock_invalid_keys;
+ mock_invalid_keys.push_back("a");
+ mock_invalid_keys.push_back("c");
+ mock_pref_hash_store_->SetInvalidKeysResult(kSplitPref, mock_invalid_keys);
+
+ DoFilterOnLoad(GetParam() >= EnforcementLevel::ENFORCE_ON_LOAD);
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+
+ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+ mock_pref_hash_store_->stored_value(kAtomicPref);
+ MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+ mock_pref_hash_store_->stored_value(kSplitPref);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+ if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) {
+ // Ensure the atomic pref was cleared and the hash for NULL was restored if
+ // the current enforcement level prevents changes.
+ ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_EQ(NULL, stored_atomic_value.first);
+
+ // The split pref on the other hand should only have been stripped of its
+ // invalid keys.
+ const base::Value* split_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
+ ASSERT_EQ(2U, dict_value->size());
+ ASSERT_FALSE(dict_value->HasKey("a"));
+ ASSERT_TRUE(dict_value->HasKey("b"));
+ ASSERT_FALSE(dict_value->HasKey("c"));
+ ASSERT_TRUE(dict_value->HasKey("d"));
+ ASSERT_EQ(dict_value, stored_split_value.first);
+
+ VerifyRecordedReset(true);
+ } else {
+ // Otherwise the value should have remained intact and the hash should have
+ // been updated to match it.
+ const base::Value* atomic_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
+ ASSERT_EQ(int_value, atomic_value_in_store);
+ ASSERT_EQ(int_value, stored_atomic_value.first);
+
+ const base::Value* split_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
+ ASSERT_EQ(dict_value, split_value_in_store);
+ ASSERT_EQ(4U, dict_value->size());
+ ASSERT_TRUE(dict_value->HasKey("a"));
+ ASSERT_TRUE(dict_value->HasKey("b"));
+ ASSERT_TRUE(dict_value->HasKey("c"));
+ ASSERT_TRUE(dict_value->HasKey("d"));
+ ASSERT_EQ(dict_value, stored_split_value.first);
+
+ VerifyRecordedReset(false);
+ }
+}
+
+TEST_P(PrefHashFilterTest, EmptyCleared) {
+ ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
+ mock_pref_hash_store_->SetCheckResult(kAtomicPref, ValueState::CLEARED);
+ mock_pref_hash_store_->SetCheckResult(kSplitPref, ValueState::CLEARED);
+ DoFilterOnLoad(false);
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+
+ // Delegate saw all prefs, two of which had the expected value_state.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->recorded_validations_count());
+ ASSERT_EQ(2u, mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::CLEARED));
+ ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
+ mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNCHANGED));
+
+ // Regardless of the enforcement level, the only thing that should be done is
+ // to restore the hash for NULL. The value itself should still be NULL.
+ ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
+ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+ mock_pref_hash_store_->stored_value(kAtomicPref);
+ ASSERT_EQ(NULL, stored_atomic_value.first);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
+
+ ASSERT_FALSE(pref_store_contents_->Get(kSplitPref, NULL));
+ MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+ mock_pref_hash_store_->stored_value(kSplitPref);
+ ASSERT_EQ(NULL, stored_split_value.first);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+}
+
+TEST_P(PrefHashFilterTest, InitialValueUnchangedLegacyId) {
+ // Ownership of these values is transfered to |pref_store_contents_|.
+ base::Value* string_value = new base::Value("string value");
+ pref_store_contents_->Set(kAtomicPref, string_value);
+
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->SetString("a", "foo");
+ dict_value->SetInteger("b", 1234);
+ pref_store_contents_->Set(kSplitPref, dict_value);
+
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, NULL));
+
+ mock_pref_hash_store_->SetCheckResult(kAtomicPref, ValueState::SECURE_LEGACY);
+ mock_pref_hash_store_->SetCheckResult(kSplitPref, ValueState::SECURE_LEGACY);
+ DoFilterOnLoad(false);
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+
+ // Delegate saw all prefs, two of which had the expected value_state.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->recorded_validations_count());
+ ASSERT_EQ(2u, mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::SECURE_LEGACY));
+ ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
+ mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNCHANGED));
+
+ // Ensure that both the atomic and split hashes were restored.
+ ASSERT_EQ(2u, mock_pref_hash_store_->stored_paths_count());
+
+ // In all cases, the values should have remained intact and the hashes should
+ // have been updated to match them.
+
+ MockPrefHashStore::ValuePtrStrategyPair stored_atomic_value =
+ mock_pref_hash_store_->stored_value(kAtomicPref);
+ ASSERT_EQ(PrefTrackingStrategy::ATOMIC, stored_atomic_value.second);
+ const base::Value* atomic_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &atomic_value_in_store));
+ ASSERT_EQ(string_value, atomic_value_in_store);
+ ASSERT_EQ(string_value, stored_atomic_value.first);
+
+ MockPrefHashStore::ValuePtrStrategyPair stored_split_value =
+ mock_pref_hash_store_->stored_value(kSplitPref);
+ ASSERT_EQ(PrefTrackingStrategy::SPLIT, stored_split_value.second);
+ const base::Value* split_value_in_store;
+ ASSERT_TRUE(pref_store_contents_->Get(kSplitPref, &split_value_in_store));
+ ASSERT_EQ(dict_value, split_value_in_store);
+ ASSERT_EQ(dict_value, stored_split_value.first);
+
+ VerifyRecordedReset(false);
+}
+
+TEST_P(PrefHashFilterTest, DontResetReportOnly) {
+ // Ownership of these values is transfered to |pref_store_contents_|.
+ base::Value* int_value1 = new base::Value(1);
+ base::Value* int_value2 = new base::Value(2);
+ base::Value* report_only_val = new base::Value(3);
+ base::DictionaryValue* report_only_split_val = new base::DictionaryValue;
+ report_only_split_val->SetInteger("a", 1234);
+ pref_store_contents_->Set(kAtomicPref, int_value1);
+ pref_store_contents_->Set(kAtomicPref2, int_value2);
+ pref_store_contents_->Set(kReportOnlyPref, report_only_val);
+ pref_store_contents_->Set(kReportOnlySplitPref, report_only_split_val);
+
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, NULL));
+ ASSERT_TRUE(pref_store_contents_->Get(kReportOnlyPref, NULL));
+ ASSERT_TRUE(pref_store_contents_->Get(kReportOnlySplitPref, NULL));
+
+ mock_pref_hash_store_->SetCheckResult(kAtomicPref, ValueState::CHANGED);
+ mock_pref_hash_store_->SetCheckResult(kAtomicPref2, ValueState::CHANGED);
+ mock_pref_hash_store_->SetCheckResult(kReportOnlyPref, ValueState::CHANGED);
+ mock_pref_hash_store_->SetCheckResult(kReportOnlySplitPref,
+ ValueState::CHANGED);
+
+ DoFilterOnLoad(GetParam() >= EnforcementLevel::ENFORCE_ON_LOAD);
+ // All prefs should be checked and a new hash should be stored for each tested
+ // pref.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(4u, mock_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(1u, mock_pref_hash_store_->transactions_performed());
+
+ // Delegate saw all prefs, four of which had the expected value_state.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->recorded_validations_count());
+ ASSERT_EQ(4u, mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::CHANGED));
+ ASSERT_EQ(arraysize(kTestTrackedPrefs) - 4u,
+ mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNCHANGED));
+
+ // No matter what the enforcement level is, the report only pref should never
+ // be reset.
+ ASSERT_TRUE(pref_store_contents_->Get(kReportOnlyPref, NULL));
+ ASSERT_TRUE(pref_store_contents_->Get(kReportOnlySplitPref, NULL));
+ ASSERT_EQ(report_only_val,
+ mock_pref_hash_store_->stored_value(kReportOnlyPref).first);
+ ASSERT_EQ(report_only_split_val,
+ mock_pref_hash_store_->stored_value(kReportOnlySplitPref).first);
+
+ // All other prefs should have been reset if the enforcement level allows it.
+ if (GetParam() == EnforcementLevel::ENFORCE_ON_LOAD) {
+ ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref, NULL));
+ ASSERT_FALSE(pref_store_contents_->Get(kAtomicPref2, NULL));
+ ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref).first);
+ ASSERT_EQ(NULL, mock_pref_hash_store_->stored_value(kAtomicPref2).first);
+
+ VerifyRecordedReset(true);
+ } else {
+ const base::Value* value_in_store;
+ const base::Value* value_in_store2;
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref, &value_in_store));
+ ASSERT_TRUE(pref_store_contents_->Get(kAtomicPref2, &value_in_store2));
+ ASSERT_EQ(int_value1, value_in_store);
+ ASSERT_EQ(int_value1,
+ mock_pref_hash_store_->stored_value(kAtomicPref).first);
+ ASSERT_EQ(int_value2, value_in_store2);
+ ASSERT_EQ(int_value2,
+ mock_pref_hash_store_->stored_value(kAtomicPref2).first);
+
+ VerifyRecordedReset(false);
+ }
+}
+
+TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacks) {
+ base::DictionaryValue root_dict;
+ // Ownership of the following values is transfered to |root_dict|.
+ base::Value* int_value1 = new base::Value(1);
+ base::Value* int_value2 = new base::Value(2);
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->Set("a", new base::Value(true));
+ root_dict.Set(kAtomicPref, int_value1);
+ root_dict.Set(kAtomicPref2, int_value2);
+ root_dict.Set(kSplitPref, dict_value);
+
+ // Skip updating kAtomicPref2.
+ pref_hash_filter_->FilterUpdate(kAtomicPref);
+ pref_hash_filter_->FilterUpdate(kSplitPref);
+
+ PrefHashFilter::OnWriteCallbackPair callbacks =
+ pref_hash_filter_->FilterSerializeData(&root_dict);
+
+ ASSERT_FALSE(callbacks.first.is_null());
+
+ // Prefs should be cleared from the external validation store only once the
+ // before-write callback is run.
+ ASSERT_EQ(
+ 0u, mock_external_validation_hash_store_contents_->cleared_paths_count());
+ callbacks.first.Run();
+ ASSERT_EQ(
+ 2u, mock_external_validation_hash_store_contents_->cleared_paths_count());
+
+ // No pref write should occur before the after-write callback is run.
+ ASSERT_EQ(
+ 0u, mock_external_validation_hash_store_contents_->stored_hashes_count());
+
+ callbacks.second.Run(true);
+
+ ASSERT_EQ(
+ 2u, mock_external_validation_hash_store_contents_->stored_hashes_count());
+ ASSERT_EQ(
+ "atomic mac for: atomic_pref",
+ mock_external_validation_hash_store_contents_->GetStoredMac(kAtomicPref));
+ ASSERT_EQ("split mac for: split_pref/a",
+ mock_external_validation_hash_store_contents_->GetStoredSplitMac(
+ kSplitPref, "a"));
+
+ // The callbacks should write directly to the contents without going through
+ // a pref hash store.
+ ASSERT_EQ(0u,
+ mock_external_validation_pref_hash_store_->stored_paths_count());
+}
+
+TEST_P(PrefHashFilterTest, CallFilterSerializeDataCallbacksWithFailure) {
+ base::DictionaryValue root_dict;
+ // Ownership of the following values is transfered to |root_dict|.
+ base::Value* int_value1 = new base::Value(1);
+ root_dict.Set(kAtomicPref, int_value1);
+
+ // Only update kAtomicPref.
+ pref_hash_filter_->FilterUpdate(kAtomicPref);
+
+ PrefHashFilter::OnWriteCallbackPair callbacks =
+ pref_hash_filter_->FilterSerializeData(&root_dict);
+
+ ASSERT_FALSE(callbacks.first.is_null());
+
+ callbacks.first.Run();
+
+ // The pref should have been cleared from the external validation store.
+ ASSERT_EQ(
+ 1u, mock_external_validation_hash_store_contents_->cleared_paths_count());
+
+ callbacks.second.Run(false);
+
+ // Expect no writes to the external validation hash store contents.
+ ASSERT_EQ(0u,
+ mock_external_validation_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(
+ 0u, mock_external_validation_hash_store_contents_->stored_hashes_count());
+}
+
+TEST_P(PrefHashFilterTest, ExternalValidationValueChanged) {
+ // Ownership of this value is transfered to |pref_store_contents_|.
+ base::Value* int_value = new base::Value(1234);
+ pref_store_contents_->Set(kAtomicPref, int_value);
+
+ base::DictionaryValue* dict_value = new base::DictionaryValue;
+ dict_value->SetString("a", "foo");
+ dict_value->SetInteger("b", 1234);
+ dict_value->SetInteger("c", 56);
+ dict_value->SetBoolean("d", false);
+ pref_store_contents_->Set(kSplitPref, dict_value);
+
+ mock_external_validation_pref_hash_store_->SetCheckResult(
+ kAtomicPref, ValueState::CHANGED);
+ mock_external_validation_pref_hash_store_->SetCheckResult(
+ kSplitPref, ValueState::CHANGED);
+
+ std::vector<std::string> mock_invalid_keys;
+ mock_invalid_keys.push_back("a");
+ mock_invalid_keys.push_back("c");
+ mock_external_validation_pref_hash_store_->SetInvalidKeysResult(
+ kSplitPref, mock_invalid_keys);
+
+ DoFilterOnLoad(false);
+
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_external_validation_pref_hash_store_->checked_paths_count());
+ ASSERT_EQ(2u,
+ mock_external_validation_pref_hash_store_->stored_paths_count());
+ ASSERT_EQ(
+ 1u, mock_external_validation_pref_hash_store_->transactions_performed());
+
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->recorded_validations_count());
+
+ // Regular validation should not have any CHANGED prefs.
+ ASSERT_EQ(arraysize(kTestTrackedPrefs),
+ mock_validation_delegate_record_->CountValidationsOfState(
+ ValueState::UNCHANGED));
+
+ // External validation should have two CHANGED prefs (kAtomic and kSplit).
+ ASSERT_EQ(2u,
+ mock_validation_delegate_record_->CountExternalValidationsOfState(
+ ValueState::CHANGED));
+ ASSERT_EQ(arraysize(kTestTrackedPrefs) - 2u,
+ mock_validation_delegate_record_->CountExternalValidationsOfState(
+ ValueState::UNCHANGED));
+}
+
+INSTANTIATE_TEST_CASE_P(PrefHashFilterTestInstance,
+ PrefHashFilterTest,
+ testing::Values(EnforcementLevel::NO_ENFORCEMENT,
+ EnforcementLevel::ENFORCE_ON_LOAD));
diff --git a/chromium/services/preferences/tracked/pref_hash_store.h b/chromium/services/preferences/tracked/pref_hash_store.h
new file mode 100644
index 00000000000..4716834c946
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_store.h
@@ -0,0 +1,48 @@
+// Copyright 2013 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_PREFERENCES_TRACKED_PREF_HASH_STORE_H_
+#define SERVICES_PREFERENCES_TRACKED_PREF_HASH_STORE_H_
+
+#include <memory>
+#include <string>
+
+#include "base/values.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+
+class HashStoreContents;
+class PrefHashStoreTransaction;
+
+// Holds the configuration and implementation used to calculate and verify
+// preference MACs.
+// TODO(gab): Rename this class as it is no longer a store.
+class PrefHashStore {
+ public:
+ virtual ~PrefHashStore() {}
+
+ // Returns a PrefHashStoreTransaction which can be used to perform a series
+ // of operations on the hash store. |storage| MAY be used as the backing store
+ // depending on the implementation. Therefore the HashStoreContents used for
+ // related transactions should correspond to the same underlying data store.
+ // |storage| must outlive the returned transaction.
+ virtual std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
+ HashStoreContents* storage) = 0;
+
+ // Computes the MAC to be associated with |path| and |value| in this store.
+ // PrefHashStoreTransaction typically uses this internally but it's also
+ // exposed for users that want to compute MACs ahead of time for asynchronous
+ // operations.
+ virtual std::string ComputeMac(const std::string& path,
+ const base::Value* value) = 0;
+
+ // Computes the MAC to be associated with |path| and |split_values| in this
+ // store. PrefHashStoreTransaction typically uses this internally but it's
+ // also exposed for users that want to compute MACs ahead of time for
+ // asynchronous operations.
+ virtual std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) = 0;
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_PREF_HASH_STORE_H_
diff --git a/chromium/services/preferences/tracked/pref_hash_store_impl.cc b/chromium/services/preferences/tracked/pref_hash_store_impl.cc
new file mode 100644
index 00000000000..522b013c5bc
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_store_impl.cc
@@ -0,0 +1,321 @@
+// Copyright 2013 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/preferences/tracked/pref_hash_store_impl.h"
+
+#include <stddef.h>
+#include <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
+#include "services/preferences/tracked/device_id.h"
+#include "services/preferences/tracked/hash_store_contents.h"
+
+namespace {
+
+using ValueState =
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
+
+// Returns a deterministic ID for this machine.
+std::string GenerateDeviceId() {
+ static std::string cached_device_id;
+ if (!cached_device_id.empty())
+ return cached_device_id;
+
+ std::string device_id;
+ MachineIdStatus status = GetDeterministicMachineSpecificId(&device_id);
+ if (status != MachineIdStatus::NOT_IMPLEMENTED) {
+ // TODO(proberge): Remove this histogram once we validate that machine id
+ // generation is not flaky and consider adding a CHECK or DCHECK.
+ UMA_HISTOGRAM_BOOLEAN("Settings.MachineIdGenerationSuccess",
+ status == MachineIdStatus::SUCCESS);
+ }
+
+ if (status == MachineIdStatus::SUCCESS) {
+ cached_device_id = device_id;
+ return device_id;
+ }
+
+ return std::string();
+}
+
+} // namespace
+
+class PrefHashStoreImpl::PrefHashStoreTransactionImpl
+ : public PrefHashStoreTransaction {
+ public:
+ // Constructs a PrefHashStoreTransactionImpl which can use the private
+ // members of its |outer| PrefHashStoreImpl.
+ PrefHashStoreTransactionImpl(PrefHashStoreImpl* outer,
+ HashStoreContents* storage);
+ ~PrefHashStoreTransactionImpl() override;
+
+ // PrefHashStoreTransaction implementation.
+ base::StringPiece GetStoreUMASuffix() const override;
+ ValueState CheckValue(const std::string& path,
+ const base::Value* value) const override;
+ void StoreHash(const std::string& path, const base::Value* value) override;
+ ValueState CheckSplitValue(
+ const std::string& path,
+ const base::DictionaryValue* initial_split_value,
+ std::vector<std::string>* invalid_keys) const override;
+ void StoreSplitHash(const std::string& path,
+ const base::DictionaryValue* split_value) override;
+ bool HasHash(const std::string& path) const override;
+ void ImportHash(const std::string& path, const base::Value* hash) override;
+ void ClearHash(const std::string& path) override;
+ bool IsSuperMACValid() const override;
+ bool StampSuperMac() override;
+
+ private:
+ PrefHashStoreImpl* outer_;
+ HashStoreContents* contents_;
+
+ bool super_mac_valid_;
+ bool super_mac_dirty_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefHashStoreTransactionImpl);
+};
+
+PrefHashStoreImpl::PrefHashStoreImpl(const std::string& seed,
+ const std::string& legacy_device_id,
+ bool use_super_mac)
+ : pref_hash_calculator_(seed, GenerateDeviceId(), legacy_device_id),
+ use_super_mac_(use_super_mac) {}
+
+PrefHashStoreImpl::~PrefHashStoreImpl() {}
+
+std::unique_ptr<PrefHashStoreTransaction> PrefHashStoreImpl::BeginTransaction(
+ HashStoreContents* storage) {
+ return std::unique_ptr<PrefHashStoreTransaction>(
+ new PrefHashStoreTransactionImpl(this, std::move(storage)));
+}
+
+std::string PrefHashStoreImpl::ComputeMac(const std::string& path,
+ const base::Value* value) {
+ return pref_hash_calculator_.Calculate(path, value);
+}
+
+std::unique_ptr<base::DictionaryValue> PrefHashStoreImpl::ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) {
+ DCHECK(split_values);
+
+ std::string keyed_path(path);
+ keyed_path.push_back('.');
+ const size_t common_part_length = keyed_path.length();
+
+ std::unique_ptr<base::DictionaryValue> split_macs(new base::DictionaryValue);
+
+ for (base::DictionaryValue::Iterator it(*split_values); !it.IsAtEnd();
+ it.Advance()) {
+ // Keep the common part from the old |keyed_path| and replace the key to
+ // get the new |keyed_path|.
+ keyed_path.replace(common_part_length, std::string::npos, it.key());
+
+ split_macs->SetStringWithoutPathExpansion(
+ it.key(), ComputeMac(keyed_path, &it.value()));
+ }
+
+ return split_macs;
+}
+
+PrefHashStoreImpl::PrefHashStoreTransactionImpl::PrefHashStoreTransactionImpl(
+ PrefHashStoreImpl* outer,
+ HashStoreContents* storage)
+ : outer_(outer),
+ contents_(std::move(storage)),
+ super_mac_valid_(false),
+ super_mac_dirty_(false) {
+ if (!outer_->use_super_mac_)
+ return;
+
+ // The store must have a valid super MAC to be trusted.
+ std::string super_mac = contents_->GetSuperMac();
+ if (super_mac.empty())
+ return;
+
+ super_mac_valid_ =
+ outer_->pref_hash_calculator_.Validate(
+ "", contents_->GetContents(), super_mac) == PrefHashCalculator::VALID;
+}
+
+PrefHashStoreImpl::PrefHashStoreTransactionImpl::
+ ~PrefHashStoreTransactionImpl() {
+ if (super_mac_dirty_ && outer_->use_super_mac_) {
+ // Get the dictionary of hashes (or NULL if it doesn't exist).
+ const base::DictionaryValue* hashes_dict = contents_->GetContents();
+ contents_->SetSuperMac(outer_->ComputeMac("", hashes_dict));
+ }
+}
+
+base::StringPiece
+PrefHashStoreImpl::PrefHashStoreTransactionImpl::GetStoreUMASuffix() const {
+ return contents_->GetUMASuffix();
+}
+
+ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckValue(
+ const std::string& path,
+ const base::Value* initial_value) const {
+ std::string last_hash;
+ contents_->GetMac(path, &last_hash);
+
+ if (last_hash.empty()) {
+ // In the absence of a hash for this pref, always trust a NULL value, but
+ // only trust an existing value if the initial hashes dictionary is trusted.
+ if (!initial_value)
+ return ValueState::TRUSTED_NULL_VALUE;
+ else if (super_mac_valid_)
+ return ValueState::TRUSTED_UNKNOWN_VALUE;
+ else
+ return ValueState::UNTRUSTED_UNKNOWN_VALUE;
+ }
+
+ PrefHashCalculator::ValidationResult validation_result =
+ outer_->pref_hash_calculator_.Validate(path, initial_value, last_hash);
+ switch (validation_result) {
+ case PrefHashCalculator::VALID:
+ return ValueState::UNCHANGED;
+ case PrefHashCalculator::VALID_SECURE_LEGACY:
+ return ValueState::SECURE_LEGACY;
+ case PrefHashCalculator::INVALID:
+ return initial_value ? ValueState::CHANGED : ValueState::CLEARED;
+ }
+ NOTREACHED() << "Unexpected PrefHashCalculator::ValidationResult: "
+ << validation_result;
+ return ValueState::UNTRUSTED_UNKNOWN_VALUE;
+}
+
+void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreHash(
+ const std::string& path,
+ const base::Value* new_value) {
+ const std::string mac = outer_->ComputeMac(path, new_value);
+ contents_->SetMac(path, mac);
+ super_mac_dirty_ = true;
+}
+
+ValueState PrefHashStoreImpl::PrefHashStoreTransactionImpl::CheckSplitValue(
+ const std::string& path,
+ const base::DictionaryValue* initial_split_value,
+ std::vector<std::string>* invalid_keys) const {
+ DCHECK(invalid_keys && invalid_keys->empty());
+
+ std::map<std::string, std::string> split_macs;
+ const bool has_hashes = contents_->GetSplitMacs(path, &split_macs);
+
+ // Treat NULL and empty the same; otherwise we would need to store a hash for
+ // the entire dictionary (or some other special beacon) to differentiate these
+ // two cases which are really the same for dictionaries.
+ if (!initial_split_value || initial_split_value->empty())
+ return has_hashes ? ValueState::CLEARED : ValueState::UNCHANGED;
+
+ if (!has_hashes)
+ return super_mac_valid_ ? ValueState::TRUSTED_UNKNOWN_VALUE
+ : ValueState::UNTRUSTED_UNKNOWN_VALUE;
+
+ bool has_secure_legacy_id_hashes = false;
+ std::string keyed_path(path);
+ keyed_path.push_back('.');
+ const size_t common_part_length = keyed_path.length();
+ for (base::DictionaryValue::Iterator it(*initial_split_value); !it.IsAtEnd();
+ it.Advance()) {
+ std::map<std::string, std::string>::iterator entry =
+ split_macs.find(it.key());
+ if (entry == split_macs.end()) {
+ invalid_keys->push_back(it.key());
+ } else {
+ // Keep the common part from the old |keyed_path| and replace the key to
+ // get the new |keyed_path|.
+ keyed_path.replace(common_part_length, std::string::npos, it.key());
+ switch (outer_->pref_hash_calculator_.Validate(keyed_path, &it.value(),
+ entry->second)) {
+ case PrefHashCalculator::VALID:
+ break;
+ case PrefHashCalculator::VALID_SECURE_LEGACY:
+ // Secure legacy device IDs based hashes are still accepted, but we
+ // should make sure to notify the caller for them to update the legacy
+ // hashes.
+ has_secure_legacy_id_hashes = true;
+ break;
+ case PrefHashCalculator::INVALID:
+ invalid_keys->push_back(it.key());
+ break;
+ }
+ // Remove processed MACs, remaining MACs at the end will also be
+ // considered invalid.
+ split_macs.erase(entry);
+ }
+ }
+
+ // Anything left in the map is missing from the data.
+ for (std::map<std::string, std::string>::const_iterator it =
+ split_macs.begin();
+ it != split_macs.end(); ++it) {
+ invalid_keys->push_back(it->first);
+ }
+
+ return invalid_keys->empty()
+ ? (has_secure_legacy_id_hashes ? ValueState::SECURE_LEGACY
+ : ValueState::UNCHANGED)
+ : ValueState::CHANGED;
+}
+
+void PrefHashStoreImpl::PrefHashStoreTransactionImpl::StoreSplitHash(
+ const std::string& path,
+ const base::DictionaryValue* split_value) {
+ contents_->RemoveEntry(path);
+
+ if (split_value) {
+ std::unique_ptr<base::DictionaryValue> split_macs =
+ outer_->ComputeSplitMacs(path, split_value);
+
+ for (base::DictionaryValue::Iterator it(*split_macs); !it.IsAtEnd();
+ it.Advance()) {
+ const base::Value* value_as_string;
+ bool is_string = it.value().GetAsString(&value_as_string);
+ DCHECK(is_string);
+
+ contents_->SetSplitMac(path, it.key(), value_as_string->GetString());
+ }
+ }
+ super_mac_dirty_ = true;
+}
+
+bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::HasHash(
+ const std::string& path) const {
+ std::string out_value;
+ std::map<std::string, std::string> out_values;
+ return contents_->GetMac(path, &out_value) ||
+ contents_->GetSplitMacs(path, &out_values);
+}
+
+void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ImportHash(
+ const std::string& path,
+ const base::Value* hash) {
+ DCHECK(hash);
+
+ contents_->ImportEntry(path, hash);
+
+ if (super_mac_valid_)
+ super_mac_dirty_ = true;
+}
+
+void PrefHashStoreImpl::PrefHashStoreTransactionImpl::ClearHash(
+ const std::string& path) {
+ if (contents_->RemoveEntry(path) && super_mac_valid_) {
+ super_mac_dirty_ = true;
+ }
+}
+
+bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::IsSuperMACValid() const {
+ return super_mac_valid_;
+}
+
+bool PrefHashStoreImpl::PrefHashStoreTransactionImpl::StampSuperMac() {
+ if (!outer_->use_super_mac_ || super_mac_valid_)
+ return false;
+ super_mac_dirty_ = true;
+ return true;
+}
diff --git a/chromium/services/preferences/tracked/pref_hash_store_impl.h b/chromium/services/preferences/tracked/pref_hash_store_impl.h
new file mode 100644
index 00000000000..8e7ae8a796c
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_store_impl.h
@@ -0,0 +1,61 @@
+// Copyright 2013 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_PREFERENCES_TRACKED_PREF_HASH_STORE_IMPL_H_
+#define SERVICES_PREFERENCES_TRACKED_PREF_HASH_STORE_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "services/preferences/tracked/pref_hash_calculator.h"
+#include "services/preferences/tracked/pref_hash_store.h"
+
+// Implements PrefHashStoreImpl by storing preference hashes in a
+// HashStoreContents.
+class PrefHashStoreImpl : public PrefHashStore {
+ public:
+ enum StoreVersion {
+ // No hashes have been stored in this PrefHashStore yet.
+ VERSION_UNINITIALIZED = 0,
+ // The hashes in this PrefHashStore were stored before the introduction
+ // of a version number and should be re-initialized.
+ VERSION_PRE_MIGRATION = 1,
+ // The hashes in this PrefHashStore were stored using the latest algorithm.
+ VERSION_LATEST = 2,
+ };
+
+ // Constructs a PrefHashStoreImpl that calculates hashes using
+ // |seed| and |legacy_device_id| and stores them in |contents|.
+ //
+ // The same |seed| and |legacy_device_id| must be used to load and validate
+ // previously stored hashes in |contents|.
+ PrefHashStoreImpl(const std::string& seed,
+ const std::string& legacy_device_id,
+ bool use_super_mac);
+
+ ~PrefHashStoreImpl() override;
+
+ // Clears the contents of this PrefHashStore. |IsInitialized()| will return
+ // false after this call.
+ void Reset();
+
+ // PrefHashStore implementation.
+ std::unique_ptr<PrefHashStoreTransaction> BeginTransaction(
+ HashStoreContents* storage) override;
+
+ std::string ComputeMac(const std::string& path,
+ const base::Value* new_value) override;
+ std::unique_ptr<base::DictionaryValue> ComputeSplitMacs(
+ const std::string& path,
+ const base::DictionaryValue* split_values) override;
+
+ private:
+ class PrefHashStoreTransactionImpl;
+
+ const PrefHashCalculator pref_hash_calculator_;
+ bool use_super_mac_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefHashStoreImpl);
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_PREF_HASH_STORE_IMPL_H_
diff --git a/chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc b/chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc
new file mode 100644
index 00000000000..3c6ca13126f
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_store_impl_unittest.cc
@@ -0,0 +1,507 @@
+// Copyright 2013 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/preferences/tracked/pref_hash_store_impl.h"
+
+#include <string>
+
+#include "base/macros.h"
+#include "base/values.h"
+#include "services/preferences/tracked/dictionary_hash_store_contents.h"
+#include "services/preferences/tracked/hash_store_contents.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ValueState =
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
+
+class PrefHashStoreImplTest : public testing::Test {
+ public:
+ PrefHashStoreImplTest() : contents_(&pref_store_contents_) {}
+
+ protected:
+ HashStoreContents* GetHashStoreContents() { return &contents_; }
+
+ private:
+ base::DictionaryValue pref_store_contents_;
+ // Must be declared after |pref_store_contents_| as it needs to be outlived
+ // by it.
+ DictionaryHashStoreContents contents_;
+
+ DISALLOW_COPY_AND_ASSIGN(PrefHashStoreImplTest);
+};
+
+TEST_F(PrefHashStoreImplTest, ComputeMac) {
+ base::Value string_1("string1");
+ base::Value string_2("string2");
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+
+ std::string computed_mac_1 = pref_hash_store.ComputeMac("path1", &string_1);
+ std::string computed_mac_2 = pref_hash_store.ComputeMac("path1", &string_2);
+ std::string computed_mac_3 = pref_hash_store.ComputeMac("path2", &string_1);
+
+ // Quick sanity checks here, see pref_hash_calculator_unittest.cc for more
+ // complete tests.
+ EXPECT_EQ(computed_mac_1, pref_hash_store.ComputeMac("path1", &string_1));
+ EXPECT_NE(computed_mac_1, computed_mac_2);
+ EXPECT_NE(computed_mac_1, computed_mac_3);
+ EXPECT_EQ(64U, computed_mac_1.size());
+}
+
+TEST_F(PrefHashStoreImplTest, ComputeSplitMacs) {
+ base::DictionaryValue dict;
+ dict.Set("a", new base::Value("string1"));
+ dict.Set("b", new base::Value("string2"));
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+
+ std::unique_ptr<base::DictionaryValue> computed_macs =
+ pref_hash_store.ComputeSplitMacs("foo.bar", &dict);
+
+ std::string mac_1;
+ std::string mac_2;
+ ASSERT_TRUE(computed_macs->GetString("a", &mac_1));
+ ASSERT_TRUE(computed_macs->GetString("b", &mac_2));
+
+ EXPECT_EQ(2U, computed_macs->size());
+
+ base::Value string_1("string1");
+ base::Value string_2("string2");
+ EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.a", &string_1), mac_1);
+ EXPECT_EQ(pref_hash_store.ComputeMac("foo.bar.b", &string_2), mac_2);
+}
+
+TEST_F(PrefHashStoreImplTest, AtomicHashStoreAndCheck) {
+ base::Value string_1("string1");
+ base::Value string_2("string2");
+
+ {
+ // 32 NULL bytes is the seed that was used to generate the legacy hash.
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+
+ // Only NULL should be trusted in the absence of a hash.
+ EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
+ transaction->CheckValue("path1", &string_1));
+ EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
+ transaction->CheckValue("path1", NULL));
+
+ transaction->StoreHash("path1", &string_1);
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckValue("path1", &string_1));
+ EXPECT_EQ(ValueState::CLEARED, transaction->CheckValue("path1", NULL));
+ transaction->StoreHash("path1", NULL);
+ EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckValue("path1", NULL));
+ EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
+
+ base::DictionaryValue dict;
+ dict.Set("a", new base::Value("foo"));
+ dict.Set("d", new base::Value("bad"));
+ dict.Set("b", new base::Value("bar"));
+ dict.Set("c", new base::Value("baz"));
+
+ transaction->StoreHash("path1", &dict);
+ EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckValue("path1", &dict));
+ }
+
+ ASSERT_FALSE(GetHashStoreContents()->GetSuperMac().empty());
+
+ {
+ // |pref_hash_store2| should trust its initial hashes dictionary and thus
+ // trust new unknown values.
+ PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
+ EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
+ transaction->CheckValue("new_path", &string_1));
+ EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
+ transaction->CheckValue("new_path", &string_2));
+ EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
+ transaction->CheckValue("new_path", NULL));
+ }
+
+ // Manually corrupt the super MAC.
+ GetHashStoreContents()->SetSuperMac(std::string(64, 'A'));
+
+ {
+ // |pref_hash_store3| should no longer trust its initial hashes dictionary
+ // and thus shouldn't trust non-NULL unknown values.
+ PrefHashStoreImpl pref_hash_store3(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store3.BeginTransaction(GetHashStoreContents()));
+ EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
+ transaction->CheckValue("new_path", &string_1));
+ EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
+ transaction->CheckValue("new_path", &string_2));
+ EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
+ transaction->CheckValue("new_path", NULL));
+ }
+}
+
+TEST_F(PrefHashStoreImplTest, ImportExportOperations) {
+ base::Value string_1("string1");
+ base::Value string_2("string2");
+
+ // Initial state: no super MAC.
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_FALSE(transaction->IsSuperMACValid());
+
+ ASSERT_FALSE(transaction->HasHash("path1"));
+
+ // Storing a hash will stamp the super MAC.
+ transaction->StoreHash("path1", &string_1);
+
+ ASSERT_TRUE(transaction->HasHash("path1"));
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckValue("path1", &string_1));
+ EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
+ }
+
+ // Make a copy of the stored hash for future use.
+ const base::Value* hash = NULL;
+ ASSERT_TRUE(GetHashStoreContents()->GetContents()->Get("path1", &hash));
+ std::unique_ptr<base::Value> path_1_string_1_hash_copy(hash->DeepCopy());
+ hash = NULL;
+
+ // Verify that the super MAC was stamped.
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_TRUE(transaction->IsSuperMACValid());
+ ASSERT_TRUE(transaction->HasHash("path1"));
+
+ // Clearing the hash should preserve validity.
+ transaction->ClearHash("path1");
+
+ // The effects of the clear should be immediately visible.
+ ASSERT_FALSE(transaction->HasHash("path1"));
+ EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
+ transaction->CheckValue("path1", NULL));
+ EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
+ transaction->CheckValue("path1", &string_1));
+ }
+
+ // Verify that validity was preserved and that the clear took effect.
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_TRUE(transaction->IsSuperMACValid());
+ ASSERT_FALSE(transaction->HasHash("path1"));
+ }
+
+ // Invalidate the super MAC.
+ GetHashStoreContents()->SetSuperMac(std::string());
+
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_FALSE(transaction->IsSuperMACValid());
+ ASSERT_FALSE(transaction->HasHash("path1"));
+
+ // An import should preserve invalidity.
+ transaction->ImportHash("path1", path_1_string_1_hash_copy.get());
+
+ ASSERT_TRUE(transaction->HasHash("path1"));
+
+ // The imported hash should be usable for validating the original value.
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckValue("path1", &string_1));
+ }
+
+ // Verify that invalidity was preserved and that the import took effect.
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_FALSE(transaction->IsSuperMACValid());
+ ASSERT_TRUE(transaction->HasHash("path1"));
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckValue("path1", &string_1));
+
+ // After clearing the hash, non-null values are UNTRUSTED_UNKNOWN.
+ transaction->ClearHash("path1");
+
+ EXPECT_EQ(ValueState::TRUSTED_NULL_VALUE,
+ transaction->CheckValue("path1", NULL));
+ EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
+ transaction->CheckValue("path1", &string_1));
+ }
+
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_FALSE(transaction->IsSuperMACValid());
+
+ // Test StampSuperMac.
+ transaction->StampSuperMac();
+ }
+
+ // Verify that the store is now valid.
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_TRUE(transaction->IsSuperMACValid());
+
+ // Store the hash of a different value to test an "over-import".
+ transaction->StoreHash("path1", &string_2);
+ EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_1));
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckValue("path1", &string_2));
+ }
+
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_TRUE(transaction->IsSuperMACValid());
+
+ // "Over-import". An import should preserve validity.
+ transaction->ImportHash("path1", path_1_string_1_hash_copy.get());
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckValue("path1", &string_1));
+ EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
+ }
+
+ // Verify that validity was preserved and the "over-import" took effect.
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+ ASSERT_TRUE(transaction->IsSuperMACValid());
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckValue("path1", &string_1));
+ EXPECT_EQ(ValueState::CHANGED, transaction->CheckValue("path1", &string_2));
+ }
+}
+
+TEST_F(PrefHashStoreImplTest, SuperMACDisabled) {
+ base::Value string_1("string1");
+ base::Value string_2("string2");
+
+ {
+ // Pass |use_super_mac| => false.
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", false);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+
+ transaction->StoreHash("path1", &string_2);
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckValue("path1", &string_2));
+ }
+
+ ASSERT_TRUE(GetHashStoreContents()->GetSuperMac().empty());
+
+ {
+ PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", false);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
+ EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
+ transaction->CheckValue("new_path", &string_1));
+ }
+}
+
+TEST_F(PrefHashStoreImplTest, SplitHashStoreAndCheck) {
+ base::DictionaryValue dict;
+ dict.Set("a", new base::Value("to be replaced"));
+ dict.Set("b", new base::Value("same"));
+ dict.Set("o", new base::Value("old"));
+
+ base::DictionaryValue modified_dict;
+ modified_dict.Set("a", new base::Value("replaced"));
+ modified_dict.Set("b", new base::Value("same"));
+ modified_dict.Set("c", new base::Value("new"));
+
+ base::DictionaryValue empty_dict;
+
+ std::vector<std::string> invalid_keys;
+
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+
+ // No hashes stored yet and hashes dictionary is empty (and thus not
+ // trusted).
+ EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
+ transaction->CheckSplitValue("path1", &dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+
+ transaction->StoreSplitHash("path1", &dict);
+
+ // Verify match post storage.
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckSplitValue("path1", &dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+
+ // Verify new path is still unknown.
+ EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
+ transaction->CheckSplitValue("path2", &dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+
+ // Verify NULL or empty dicts are declared as having been cleared.
+ EXPECT_EQ(ValueState::CLEARED,
+ transaction->CheckSplitValue("path1", NULL, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+ EXPECT_EQ(ValueState::CLEARED, transaction->CheckSplitValue(
+ "path1", &empty_dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+
+ // Verify changes are properly detected.
+ EXPECT_EQ(ValueState::CHANGED, transaction->CheckSplitValue(
+ "path1", &modified_dict, &invalid_keys));
+ std::vector<std::string> expected_invalid_keys1;
+ expected_invalid_keys1.push_back("a");
+ expected_invalid_keys1.push_back("c");
+ expected_invalid_keys1.push_back("o");
+ EXPECT_EQ(expected_invalid_keys1, invalid_keys);
+ invalid_keys.clear();
+
+ // Verify |dict| still matches post check.
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckSplitValue("path1", &dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+
+ // Store hash for |modified_dict|.
+ transaction->StoreSplitHash("path1", &modified_dict);
+
+ // Verify |modified_dict| is now the one that verifies correctly.
+ EXPECT_EQ(
+ ValueState::UNCHANGED,
+ transaction->CheckSplitValue("path1", &modified_dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+
+ // Verify old dict no longer matches.
+ EXPECT_EQ(ValueState::CHANGED,
+ transaction->CheckSplitValue("path1", &dict, &invalid_keys));
+ std::vector<std::string> expected_invalid_keys2;
+ expected_invalid_keys2.push_back("a");
+ expected_invalid_keys2.push_back("o");
+ expected_invalid_keys2.push_back("c");
+ EXPECT_EQ(expected_invalid_keys2, invalid_keys);
+ invalid_keys.clear();
+ }
+
+ {
+ // |pref_hash_store2| should trust its initial hashes dictionary and thus
+ // trust new unknown values.
+ PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
+ EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
+ transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+ }
+
+ // Manually corrupt the super MAC.
+ GetHashStoreContents()->SetSuperMac(std::string(64, 'A'));
+
+ {
+ // |pref_hash_store3| should no longer trust its initial hashes dictionary
+ // and thus shouldn't trust unknown values.
+ PrefHashStoreImpl pref_hash_store3(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store3.BeginTransaction(GetHashStoreContents()));
+ EXPECT_EQ(ValueState::UNTRUSTED_UNKNOWN_VALUE,
+ transaction->CheckSplitValue("new_path", &dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+ }
+}
+
+TEST_F(PrefHashStoreImplTest, EmptyAndNULLSplitDict) {
+ base::DictionaryValue empty_dict;
+
+ std::vector<std::string> invalid_keys;
+
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+
+ // Store hashes for a random dict to be overwritten below.
+ base::DictionaryValue initial_dict;
+ initial_dict.Set("a", new base::Value("foo"));
+ transaction->StoreSplitHash("path1", &initial_dict);
+
+ // Verify stored empty dictionary matches NULL and empty dictionary back.
+ transaction->StoreSplitHash("path1", &empty_dict);
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckSplitValue("path1", NULL, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+ EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckSplitValue(
+ "path1", &empty_dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+
+ // Same when storing NULL directly.
+ transaction->StoreSplitHash("path1", NULL);
+ EXPECT_EQ(ValueState::UNCHANGED,
+ transaction->CheckSplitValue("path1", NULL, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+ EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckSplitValue(
+ "path1", &empty_dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+ }
+
+ {
+ // |pref_hash_store2| should trust its initial hashes dictionary (and thus
+ // trust new unknown values) even though the last action done was to clear
+ // the hashes for path1 by setting its value to NULL (this is a regression
+ // test ensuring that the internal action of clearing some hashes does
+ // update the stored hash of hashes).
+ PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
+
+ base::DictionaryValue tested_dict;
+ tested_dict.Set("a", new base::Value("foo"));
+ tested_dict.Set("b", new base::Value("bar"));
+ EXPECT_EQ(
+ ValueState::TRUSTED_UNKNOWN_VALUE,
+ transaction->CheckSplitValue("new_path", &tested_dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+ }
+}
+
+// Test that the PrefHashStore returns TRUSTED_UNKNOWN_VALUE when checking for
+// a split preference even if there is an existing atomic preference's hash
+// stored. There is no point providing a migration path for preferences
+// switching strategies after their initial release as split preferences are
+// turned into split preferences specifically because the atomic hash isn't
+// considered useful.
+TEST_F(PrefHashStoreImplTest, TrustedUnknownSplitValueFromExistingAtomic) {
+ base::Value string("string1");
+
+ base::DictionaryValue dict;
+ dict.Set("a", new base::Value("foo"));
+ dict.Set("d", new base::Value("bad"));
+ dict.Set("b", new base::Value("bar"));
+ dict.Set("c", new base::Value("baz"));
+
+ {
+ PrefHashStoreImpl pref_hash_store(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store.BeginTransaction(GetHashStoreContents()));
+
+ transaction->StoreHash("path1", &string);
+ EXPECT_EQ(ValueState::UNCHANGED, transaction->CheckValue("path1", &string));
+ }
+
+ {
+ // Load a new |pref_hash_store2| in which the hashes dictionary is trusted.
+ PrefHashStoreImpl pref_hash_store2(std::string(32, 0), "device_id", true);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ pref_hash_store2.BeginTransaction(GetHashStoreContents()));
+ std::vector<std::string> invalid_keys;
+ EXPECT_EQ(ValueState::TRUSTED_UNKNOWN_VALUE,
+ transaction->CheckSplitValue("path1", &dict, &invalid_keys));
+ EXPECT_TRUE(invalid_keys.empty());
+ }
+}
diff --git a/chromium/services/preferences/tracked/pref_hash_store_transaction.h b/chromium/services/preferences/tracked/pref_hash_store_transaction.h
new file mode 100644
index 00000000000..2e888859ee8
--- /dev/null
+++ b/chromium/services/preferences/tracked/pref_hash_store_transaction.h
@@ -0,0 +1,80 @@
+// 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_PREFERENCES_TRACKED_PREF_HASH_STORE_TRANSACTION_H_
+#define SERVICES_PREFERENCES_TRACKED_PREF_HASH_STORE_TRANSACTION_H_
+
+#include <string>
+#include <vector>
+
+#include "base/strings/string_piece.h"
+#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+
+namespace base {
+class DictionaryValue;
+class Value;
+} // namespace base
+
+// Used to perform a series of checks/transformations on a PrefHashStore.
+class PrefHashStoreTransaction {
+ public:
+ // Finalizes any remaining work after the transaction has been performed.
+ virtual ~PrefHashStoreTransaction() {}
+
+ // Returns the suffix to be appended to UMA histograms for the store contained
+ // in this transaction.
+ virtual base::StringPiece GetStoreUMASuffix() const = 0;
+
+ // Checks |initial_value| against the existing stored value hash.
+ virtual prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ CheckValue(const std::string& path,
+ const base::Value* initial_value) const = 0;
+
+ // Stores a hash of the current |value| of the preference at |path|.
+ virtual void StoreHash(const std::string& path, const base::Value* value) = 0;
+
+ // Checks |initial_value| against the existing stored hashes for the split
+ // preference at |path|. |initial_split_value| being an empty dictionary or
+ // NULL is equivalent. |invalid_keys| must initially be empty. |invalid_keys|
+ // will not be modified unless the return value is CHANGED, in which case it
+ // will be filled with the keys that are considered invalid (unknown or
+ // changed).
+ virtual prefs::mojom::TrackedPreferenceValidationDelegate::ValueState
+ CheckSplitValue(const std::string& path,
+ const base::DictionaryValue* initial_split_value,
+ std::vector<std::string>* invalid_keys) const = 0;
+
+ // Stores hashes for the |value| of the split preference at |path|.
+ // |split_value| being an empty dictionary or NULL is equivalent.
+ virtual void StoreSplitHash(const std::string& path,
+ const base::DictionaryValue* split_value) = 0;
+
+ // Indicates whether the store contains a hash for the preference at |path|.
+ virtual bool HasHash(const std::string& path) const = 0;
+
+ // Sets the hash for the preference at |path|.
+ // If |path| is a split preference |hash| must be a DictionaryValue whose
+ // keys are keys in the split preference and whose values are MACs of the
+ // corresponding values in the split preference.
+ // If |path| is an atomic preference |hash| must be a StringValue
+ // containing a MAC of the preference value.
+ // |hash| should originate from a PrefHashStore sharing the same MAC
+ // parameters as this transaction's store.
+ // The (in)validity of the super MAC will be maintained by this call.
+ virtual void ImportHash(const std::string& path, const base::Value* hash) = 0;
+
+ // Removes the hash stored at |path|. The (in)validity of the super MAC will
+ // be maintained by this call.
+ virtual void ClearHash(const std::string& path) = 0;
+
+ // Indicates whether the super MAC was successfully verified at the beginning
+ // of this transaction.
+ virtual bool IsSuperMACValid() const = 0;
+
+ // Forces a valid super MAC to be stored when this transaction terminates.
+ // Returns true if this results in a change to the store contents.
+ virtual bool StampSuperMac() = 0;
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_PREF_HASH_STORE_TRANSACTION_H_
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc b/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc
new file mode 100644
index 00000000000..ab1c2c56478
--- /dev/null
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win.cc
@@ -0,0 +1,182 @@
+// Copyright (c) 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/preferences/tracked/registry_hash_store_contents_win.h"
+
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/stringprintf.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "base/win/registry.h"
+#include "services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h"
+
+using base::win::RegistryValueIterator;
+
+namespace {
+
+constexpr size_t kMacSize = 64;
+
+base::string16 GetSplitPrefKeyName(const base::string16& reg_key_name,
+ const std::string& split_key_name) {
+ return reg_key_name + L"\\" + base::UTF8ToUTF16(split_key_name);
+}
+
+bool ReadMacFromRegistry(const base::win::RegKey& key,
+ const std::string& value_name,
+ std::string* out_mac) {
+ base::string16 string_value;
+ if (key.ReadValue(base::UTF8ToUTF16(value_name).c_str(), &string_value) ==
+ ERROR_SUCCESS &&
+ string_value.size() == kMacSize) {
+ out_mac->assign(base::UTF16ToUTF8(string_value));
+ return true;
+ }
+ return false;
+}
+
+// Removes |value_name| under |reg_key_name|. Returns true if found and
+// successfully removed.
+bool ClearAtomicMac(const base::string16& reg_key_name,
+ const std::string& value_name) {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, reg_key_name.c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ return key.DeleteValue(base::UTF8ToUTF16(value_name).c_str()) ==
+ ERROR_SUCCESS;
+ }
+ return false;
+}
+
+// Deletes |split_key_name| under |reg_key_name|. Returns true if found and
+// successfully removed.
+bool ClearSplitMac(const base::string16& reg_key_name,
+ const std::string& split_key_name) {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER,
+ GetSplitPrefKeyName(reg_key_name, split_key_name).c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ return key.DeleteKey(L"") == ERROR_SUCCESS;
+ }
+ return false;
+}
+
+} // namespace
+
+RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
+ const base::string16& registry_path,
+ const base::string16& store_key)
+ : preference_key_name_(registry_path + L"\\PreferenceMACs\\" + store_key) {}
+
+RegistryHashStoreContentsWin::RegistryHashStoreContentsWin(
+ const RegistryHashStoreContentsWin& other) = default;
+
+bool RegistryHashStoreContentsWin::IsCopyable() const {
+ return true;
+}
+
+std::unique_ptr<HashStoreContents> RegistryHashStoreContentsWin::MakeCopy()
+ const {
+ return base::WrapUnique(new RegistryHashStoreContentsWin(*this));
+}
+
+base::StringPiece RegistryHashStoreContentsWin::GetUMASuffix() const {
+ return user_prefs::tracked::kTrackedPrefRegistryValidationSuffix;
+}
+
+void RegistryHashStoreContentsWin::Reset() {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ LONG result = key.DeleteKey(L"");
+ DCHECK(result == ERROR_SUCCESS || result == ERROR_FILE_NOT_FOUND) << result;
+ }
+}
+
+bool RegistryHashStoreContentsWin::GetMac(const std::string& path,
+ std::string* out_value) {
+ base::win::RegKey key;
+ if (key.Open(HKEY_CURRENT_USER, preference_key_name_.c_str(),
+ KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ return ReadMacFromRegistry(key, path, out_value);
+ }
+
+ return false;
+}
+
+bool RegistryHashStoreContentsWin::GetSplitMacs(
+ const std::string& path,
+ std::map<std::string, std::string>* split_macs) {
+ DCHECK(split_macs);
+ DCHECK(split_macs->empty());
+
+ RegistryValueIterator iter_key(
+ HKEY_CURRENT_USER,
+ GetSplitPrefKeyName(preference_key_name_, path).c_str());
+
+ for (; iter_key.Valid(); ++iter_key) {
+ split_macs->insert(make_pair(base::UTF16ToUTF8(iter_key.Name()),
+ base::UTF16ToUTF8(iter_key.Value())));
+ }
+
+ return !split_macs->empty();
+}
+
+void RegistryHashStoreContentsWin::SetMac(const std::string& path,
+ const std::string& value) {
+ base::win::RegKey key;
+ DCHECK_EQ(kMacSize, value.size());
+
+ if (key.Create(HKEY_CURRENT_USER, preference_key_name_.c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ key.WriteValue(base::UTF8ToUTF16(path).c_str(),
+ base::UTF8ToUTF16(value).c_str());
+ }
+}
+
+void RegistryHashStoreContentsWin::SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) {
+ base::win::RegKey key;
+ DCHECK_EQ(kMacSize, value.size());
+
+ if (key.Create(HKEY_CURRENT_USER,
+ GetSplitPrefKeyName(preference_key_name_, path).c_str(),
+ KEY_SET_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS) {
+ key.WriteValue(base::UTF8ToUTF16(split_path).c_str(),
+ base::UTF8ToUTF16(value).c_str());
+ }
+}
+
+bool RegistryHashStoreContentsWin::RemoveEntry(const std::string& path) {
+ return ClearAtomicMac(preference_key_name_, path) ||
+ ClearSplitMac(preference_key_name_, path);
+}
+
+void RegistryHashStoreContentsWin::ImportEntry(const std::string& path,
+ const base::Value* in_value) {
+ NOTREACHED()
+ << "RegistryHashStoreContents does not support the ImportEntry operation";
+}
+
+const base::DictionaryValue* RegistryHashStoreContentsWin::GetContents() const {
+ NOTREACHED()
+ << "RegistryHashStoreContents does not support the GetContents operation";
+ return NULL;
+}
+
+std::string RegistryHashStoreContentsWin::GetSuperMac() const {
+ NOTREACHED()
+ << "RegistryHashStoreContents does not support the GetSuperMac operation";
+ return NULL;
+}
+
+void RegistryHashStoreContentsWin::SetSuperMac(const std::string& super_mac) {
+ NOTREACHED()
+ << "RegistryHashStoreContents does not support the SetSuperMac operation";
+}
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win.h b/chromium/services/preferences/tracked/registry_hash_store_contents_win.h
new file mode 100644
index 00000000000..34496f97cec
--- /dev/null
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win.h
@@ -0,0 +1,49 @@
+// 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_PREFERENCES_TRACKED_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
+#define SERVICES_PREFERENCES_TRACKED_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "services/preferences/tracked/hash_store_contents.h"
+
+// Implements HashStoreContents by storing MACs in the Windows registry.
+class RegistryHashStoreContentsWin : public HashStoreContents {
+ public:
+ // Constructs a RegistryHashStoreContents which acts on a registry entry
+ // defined by |registry_path| and |store_key|.
+ explicit RegistryHashStoreContentsWin(const base::string16& registry_path,
+ const base::string16& store_key);
+
+ // HashStoreContents overrides:
+ bool IsCopyable() const override;
+ std::unique_ptr<HashStoreContents> MakeCopy() const override;
+ base::StringPiece GetUMASuffix() const override;
+ void Reset() override;
+ bool GetMac(const std::string& path, std::string* out_value) override;
+ bool GetSplitMacs(const std::string& path,
+ std::map<std::string, std::string>* split_macs) override;
+ void SetMac(const std::string& path, const std::string& value) override;
+ void SetSplitMac(const std::string& path,
+ const std::string& split_path,
+ const std::string& value) override;
+ bool RemoveEntry(const std::string& path) override;
+
+ // Unsupported HashStoreContents overrides:
+ void ImportEntry(const std::string& path,
+ const base::Value* in_value) override;
+ const base::DictionaryValue* GetContents() const override;
+ std::string GetSuperMac() const override;
+ void SetSuperMac(const std::string& super_mac) override;
+
+ private:
+ // Helper constructor for |MakeCopy|.
+ explicit RegistryHashStoreContentsWin(
+ const RegistryHashStoreContentsWin& other);
+
+ const base::string16 preference_key_name_;
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_REGISTRY_HASH_STORE_CONTENTS_WIN_H_
diff --git a/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc b/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc
new file mode 100644
index 00000000000..468843437fb
--- /dev/null
+++ b/chromium/services/preferences/tracked/registry_hash_store_contents_win_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 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/preferences/tracked/registry_hash_store_contents_win.h"
+
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/test_reg_util_win.h"
+#include "base/values.h"
+#include "base/win/registry.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+constexpr base::char16 kRegistryPath[] = L"Foo\\TestStore";
+constexpr base::char16 kStoreKey[] = L"test_store_key";
+
+// Hex-encoded MACs are 64 characters long.
+constexpr char kTestStringA[] =
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
+constexpr char kTestStringB[] =
+ "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+
+constexpr char kAtomicPrefPath[] = "path1";
+constexpr char kSplitPrefPath[] = "extension";
+
+class RegistryHashStoreContentsWinTest : public testing::Test {
+ protected:
+ RegistryHashStoreContentsWinTest() {}
+
+ void SetUp() override {
+ ASSERT_NO_FATAL_FAILURE(
+ registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER));
+
+ contents.reset(new RegistryHashStoreContentsWin(kRegistryPath, kStoreKey));
+ }
+
+ std::unique_ptr<HashStoreContents> contents;
+
+ private:
+ registry_util::RegistryOverrideManager registry_override_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(RegistryHashStoreContentsWinTest);
+};
+
+} // namespace
+
+TEST_F(RegistryHashStoreContentsWinTest, TestSetAndGetMac) {
+ std::string stored_mac;
+ EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+
+ contents->SetMac(kAtomicPrefPath, kTestStringA);
+
+ EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringA, stored_mac);
+}
+
+TEST_F(RegistryHashStoreContentsWinTest, TestSetAndGetSplitMacs) {
+ std::map<std::string, std::string> split_macs;
+ EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+
+ contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
+ contents->SetSplitMac(kSplitPrefPath, "b", kTestStringB);
+
+ EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(2U, split_macs.size());
+ EXPECT_EQ(kTestStringA, split_macs.at("a"));
+ EXPECT_EQ(kTestStringB, split_macs.at("b"));
+}
+
+TEST_F(RegistryHashStoreContentsWinTest, TestRemoveAtomicMac) {
+ contents->SetMac(kAtomicPrefPath, kTestStringA);
+
+ std::string stored_mac;
+ EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringA, stored_mac);
+
+ contents->RemoveEntry(kAtomicPrefPath);
+
+ EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+}
+
+TEST_F(RegistryHashStoreContentsWinTest, TestRemoveSplitMacs) {
+ contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
+ contents->SetSplitMac(kSplitPrefPath, "b", kTestStringB);
+
+ std::map<std::string, std::string> split_macs;
+ EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(2U, split_macs.size());
+
+ contents->RemoveEntry(kSplitPrefPath);
+
+ split_macs.clear();
+ EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(0U, split_macs.size());
+}
+
+TEST_F(RegistryHashStoreContentsWinTest, TestReset) {
+ contents->SetMac(kAtomicPrefPath, kTestStringA);
+ contents->SetSplitMac(kSplitPrefPath, "a", kTestStringA);
+
+ std::string stored_mac;
+ EXPECT_TRUE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_EQ(kTestStringA, stored_mac);
+
+ std::map<std::string, std::string> split_macs;
+ EXPECT_TRUE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(1U, split_macs.size());
+
+ contents->Reset();
+
+ stored_mac.clear();
+ EXPECT_FALSE(contents->GetMac(kAtomicPrefPath, &stored_mac));
+ EXPECT_TRUE(stored_mac.empty());
+
+ split_macs.clear();
+ EXPECT_FALSE(contents->GetSplitMacs(kSplitPrefPath, &split_macs));
+ EXPECT_EQ(0U, split_macs.size());
+}
diff --git a/chromium/services/preferences/tracked/segregated_pref_store.cc b/chromium/services/preferences/tracked/segregated_pref_store.cc
new file mode 100644
index 00000000000..af7349e0382
--- /dev/null
+++ b/chromium/services/preferences/tracked/segregated_pref_store.cc
@@ -0,0 +1,195 @@
+// 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/preferences/tracked/segregated_pref_store.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/stl_util.h"
+#include "base/values.h"
+
+SegregatedPrefStore::AggregatingObserver::AggregatingObserver(
+ SegregatedPrefStore* outer)
+ : outer_(outer),
+ failed_sub_initializations_(0),
+ successful_sub_initializations_(0) {}
+
+void SegregatedPrefStore::AggregatingObserver::OnPrefValueChanged(
+ const std::string& key) {
+ // There is no need to tell clients about changes if they have not yet been
+ // told about initialization.
+ if (failed_sub_initializations_ + successful_sub_initializations_ < 2)
+ return;
+
+ for (auto& observer : outer_->observers_)
+ observer.OnPrefValueChanged(key);
+}
+
+void SegregatedPrefStore::AggregatingObserver::OnInitializationCompleted(
+ bool succeeded) {
+ if (succeeded)
+ ++successful_sub_initializations_;
+ else
+ ++failed_sub_initializations_;
+
+ DCHECK_LE(failed_sub_initializations_ + successful_sub_initializations_, 2);
+
+ if (failed_sub_initializations_ + successful_sub_initializations_ == 2) {
+ if (successful_sub_initializations_ == 2 && outer_->read_error_delegate_) {
+ PersistentPrefStore::PrefReadError read_error = outer_->GetReadError();
+ if (read_error != PersistentPrefStore::PREF_READ_ERROR_NONE)
+ outer_->read_error_delegate_->OnError(read_error);
+ }
+
+ for (auto& observer : outer_->observers_)
+ observer.OnInitializationCompleted(successful_sub_initializations_ == 2);
+ }
+}
+
+SegregatedPrefStore::SegregatedPrefStore(
+ const scoped_refptr<PersistentPrefStore>& default_pref_store,
+ const scoped_refptr<PersistentPrefStore>& selected_pref_store,
+ const std::set<std::string>& selected_pref_names,
+ prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate)
+ : validation_delegate_(std::move(validation_delegate)),
+ default_pref_store_(default_pref_store),
+ selected_pref_store_(selected_pref_store),
+ selected_preference_names_(selected_pref_names),
+ aggregating_observer_(this) {
+ default_pref_store_->AddObserver(&aggregating_observer_);
+ selected_pref_store_->AddObserver(&aggregating_observer_);
+}
+
+void SegregatedPrefStore::AddObserver(Observer* observer) {
+ observers_.AddObserver(observer);
+}
+
+void SegregatedPrefStore::RemoveObserver(Observer* observer) {
+ observers_.RemoveObserver(observer);
+}
+
+bool SegregatedPrefStore::HasObservers() const {
+ return observers_.might_have_observers();
+}
+
+bool SegregatedPrefStore::IsInitializationComplete() const {
+ return default_pref_store_->IsInitializationComplete() &&
+ selected_pref_store_->IsInitializationComplete();
+}
+
+bool SegregatedPrefStore::GetValue(const std::string& key,
+ const base::Value** result) const {
+ return StoreForKey(key)->GetValue(key, result);
+}
+
+std::unique_ptr<base::DictionaryValue> SegregatedPrefStore::GetValues() const {
+ auto values = default_pref_store_->GetValues();
+ auto selected_pref_store_values = selected_pref_store_->GetValues();
+ for (const auto& key : selected_preference_names_) {
+ const base::Value* value = nullptr;
+ if (selected_pref_store_values->Get(key, &value)) {
+ values->Set(key, value->CreateDeepCopy());
+ } else {
+ values->Remove(key, nullptr);
+ }
+ }
+ return values;
+}
+
+void SegregatedPrefStore::SetValue(const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) {
+ StoreForKey(key)->SetValue(key, std::move(value), flags);
+}
+
+void SegregatedPrefStore::RemoveValue(const std::string& key, uint32_t flags) {
+ StoreForKey(key)->RemoveValue(key, flags);
+}
+
+bool SegregatedPrefStore::GetMutableValue(const std::string& key,
+ base::Value** result) {
+ return StoreForKey(key)->GetMutableValue(key, result);
+}
+
+void SegregatedPrefStore::ReportValueChanged(const std::string& key,
+ uint32_t flags) {
+ StoreForKey(key)->ReportValueChanged(key, flags);
+}
+
+void SegregatedPrefStore::SetValueSilently(const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) {
+ StoreForKey(key)->SetValueSilently(key, std::move(value), flags);
+}
+
+bool SegregatedPrefStore::ReadOnly() const {
+ return selected_pref_store_->ReadOnly() || default_pref_store_->ReadOnly();
+}
+
+PersistentPrefStore::PrefReadError SegregatedPrefStore::GetReadError() const {
+ PersistentPrefStore::PrefReadError read_error =
+ default_pref_store_->GetReadError();
+ if (read_error == PersistentPrefStore::PREF_READ_ERROR_NONE) {
+ read_error = selected_pref_store_->GetReadError();
+ // Ignore NO_FILE from selected_pref_store_.
+ if (read_error == PersistentPrefStore::PREF_READ_ERROR_NO_FILE)
+ read_error = PersistentPrefStore::PREF_READ_ERROR_NONE;
+ }
+ return read_error;
+}
+
+PersistentPrefStore::PrefReadError SegregatedPrefStore::ReadPrefs() {
+ // Note: Both of these stores own PrefFilters which makes ReadPrefs
+ // asynchronous. This is okay in this case as only the first call will be
+ // truly asynchronous, the second call will then unblock the migration in
+ // TrackedPreferencesMigrator and complete synchronously.
+ default_pref_store_->ReadPrefs();
+ PersistentPrefStore::PrefReadError selected_store_read_error =
+ selected_pref_store_->ReadPrefs();
+ DCHECK_NE(PersistentPrefStore::PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE,
+ selected_store_read_error);
+
+ return GetReadError();
+}
+
+void SegregatedPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) {
+ read_error_delegate_.reset(error_delegate);
+ default_pref_store_->ReadPrefsAsync(NULL);
+ selected_pref_store_->ReadPrefsAsync(NULL);
+}
+
+void SegregatedPrefStore::CommitPendingWrite() {
+ default_pref_store_->CommitPendingWrite();
+ selected_pref_store_->CommitPendingWrite();
+}
+
+void SegregatedPrefStore::SchedulePendingLossyWrites() {
+ default_pref_store_->SchedulePendingLossyWrites();
+ selected_pref_store_->SchedulePendingLossyWrites();
+}
+
+void SegregatedPrefStore::ClearMutableValues() {
+ NOTIMPLEMENTED();
+}
+
+SegregatedPrefStore::~SegregatedPrefStore() {
+ default_pref_store_->RemoveObserver(&aggregating_observer_);
+ selected_pref_store_->RemoveObserver(&aggregating_observer_);
+}
+
+PersistentPrefStore* SegregatedPrefStore::StoreForKey(const std::string& key) {
+ return (base::ContainsKey(selected_preference_names_, key)
+ ? selected_pref_store_
+ : default_pref_store_)
+ .get();
+}
+
+const PersistentPrefStore* SegregatedPrefStore::StoreForKey(
+ const std::string& key) const {
+ return (base::ContainsKey(selected_preference_names_, key)
+ ? selected_pref_store_
+ : default_pref_store_)
+ .get();
+}
diff --git a/chromium/services/preferences/tracked/segregated_pref_store.h b/chromium/services/preferences/tracked/segregated_pref_store.h
new file mode 100644
index 00000000000..3621e49aa07
--- /dev/null
+++ b/chromium/services/preferences/tracked/segregated_pref_store.h
@@ -0,0 +1,122 @@
+// 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_PREFERENCES_TRACKED_SEGREGATED_PREF_STORE_H_
+#define SERVICES_PREFERENCES_TRACKED_SEGREGATED_PREF_STORE_H_
+
+#include <stdint.h>
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#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"
+
+// Provides a unified PersistentPrefStore implementation that splits its storage
+// and retrieval between two underlying PersistentPrefStore instances: a set of
+// preference names is used to partition the preferences.
+//
+// Combines properties of the two stores as follows:
+// * The unified read error will be:
+// Selected Store Error
+// Default Store Error | NO_ERROR | NO_FILE | other selected |
+// NO_ERROR | NO_ERROR | NO_ERROR | other selected |
+// NO_FILE | NO_FILE | NO_FILE | NO_FILE |
+// other default | other default | other default | other default |
+// * The unified initialization success, initialization completion, and
+// read-only state are the boolean OR of the underlying stores' properties.
+class SegregatedPrefStore : public PersistentPrefStore {
+ public:
+ // Creates an instance that delegates to |selected_pref_store| for the
+ // preferences named in |selected_pref_names| and to |default_pref_store|
+ // for all others. If an unselected preference is present in
+ // |selected_pref_store| (i.e. because it was previously selected) it will
+ // be migrated back to |default_pref_store| upon access via a non-const
+ // method.
+ // |on_initialization| will be invoked when both stores have been initialized,
+ // before observers of the SegregatedPrefStore store are notified.
+ SegregatedPrefStore(
+ const scoped_refptr<PersistentPrefStore>& default_pref_store,
+ const scoped_refptr<PersistentPrefStore>& selected_pref_store,
+ const std::set<std::string>& selected_pref_names,
+ prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate);
+
+ // PrefStore implementation
+ void AddObserver(Observer* observer) override;
+ void RemoveObserver(Observer* observer) override;
+ bool HasObservers() const override;
+ bool IsInitializationComplete() const override;
+ bool GetValue(const std::string& key,
+ const base::Value** result) const override;
+ std::unique_ptr<base::DictionaryValue> GetValues() const override;
+
+ // WriteablePrefStore implementation
+ void SetValue(const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) override;
+ void RemoveValue(const std::string& key, uint32_t flags) override;
+
+ // PersistentPrefStore implementation
+ bool GetMutableValue(const std::string& key, base::Value** result) override;
+ void ReportValueChanged(const std::string& key, uint32_t flags) override;
+ void SetValueSilently(const std::string& key,
+ std::unique_ptr<base::Value> value,
+ uint32_t flags) override;
+ bool ReadOnly() const override;
+ PrefReadError GetReadError() const override;
+ PrefReadError ReadPrefs() override;
+ void ReadPrefsAsync(ReadErrorDelegate* error_delegate) override;
+ void CommitPendingWrite() override;
+ void SchedulePendingLossyWrites() override;
+
+ void ClearMutableValues() override;
+
+ private:
+ // Aggregates events from the underlying stores and synthesizes external
+ // events via |on_initialization|, |read_error_delegate_|, and |observers_|.
+ class AggregatingObserver : public PrefStore::Observer {
+ public:
+ explicit AggregatingObserver(SegregatedPrefStore* outer);
+
+ // PrefStore::Observer implementation
+ void OnPrefValueChanged(const std::string& key) override;
+ void OnInitializationCompleted(bool succeeded) override;
+
+ private:
+ SegregatedPrefStore* outer_;
+ int failed_sub_initializations_;
+ int successful_sub_initializations_;
+
+ DISALLOW_COPY_AND_ASSIGN(AggregatingObserver);
+ };
+
+ ~SegregatedPrefStore() override;
+
+ // Returns |selected_pref_store| if |key| is selected and |default_pref_store|
+ // otherwise.
+ PersistentPrefStore* StoreForKey(const std::string& key);
+ const PersistentPrefStore* StoreForKey(const std::string& key) const;
+
+ // |validation_delegate_| is used by |default_pref_store_| and
+ // |selected_pref_store_| PrefHashFilters. Its lifetime is managed here since
+ // a single owner is required.
+ prefs::mojom::TrackedPreferenceValidationDelegatePtr validation_delegate_;
+
+ scoped_refptr<PersistentPrefStore> default_pref_store_;
+ scoped_refptr<PersistentPrefStore> selected_pref_store_;
+ std::set<std::string> selected_preference_names_;
+
+ std::unique_ptr<PersistentPrefStore::ReadErrorDelegate> read_error_delegate_;
+ base::ObserverList<PrefStore::Observer, true> observers_;
+ AggregatingObserver aggregating_observer_;
+
+ DISALLOW_COPY_AND_ASSIGN(SegregatedPrefStore);
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_SEGREGATED_PREF_STORE_H_
diff --git a/chromium/services/preferences/tracked/segregated_pref_store_unittest.cc b/chromium/services/preferences/tracked/segregated_pref_store_unittest.cc
new file mode 100644
index 00000000000..a237f38285e
--- /dev/null
+++ b/chromium/services/preferences/tracked/segregated_pref_store_unittest.cc
@@ -0,0 +1,304 @@
+// 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/preferences/tracked/segregated_pref_store.h"
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/values.h"
+#include "components/prefs/persistent_pref_store.h"
+#include "components/prefs/pref_store_observer_mock.h"
+#include "components/prefs/testing_pref_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const char kSelectedPref[] = "selected_pref";
+const char kUnselectedPref[] = "unselected_pref";
+const char kSharedPref[] = "shared_pref";
+
+const char kValue1[] = "value1";
+const char kValue2[] = "value2";
+
+class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate {
+ public:
+ struct Data {
+ Data(bool invoked_in, PersistentPrefStore::PrefReadError read_error_in)
+ : invoked(invoked_in), read_error(read_error_in) {}
+
+ bool invoked;
+ PersistentPrefStore::PrefReadError read_error;
+ };
+
+ explicit MockReadErrorDelegate(Data* data) : data_(data) {
+ DCHECK(data_);
+ EXPECT_FALSE(data_->invoked);
+ }
+
+ // PersistentPrefStore::ReadErrorDelegate implementation
+ void OnError(PersistentPrefStore::PrefReadError read_error) override {
+ EXPECT_FALSE(data_->invoked);
+ data_->invoked = true;
+ data_->read_error = read_error;
+ }
+
+ private:
+ Data* data_;
+};
+
+} // namespace
+
+class SegregatedPrefStoreTest : public testing::Test {
+ public:
+ SegregatedPrefStoreTest()
+ : read_error_delegate_data_(false,
+ PersistentPrefStore::PREF_READ_ERROR_NONE),
+ read_error_delegate_(
+ new MockReadErrorDelegate(&read_error_delegate_data_)) {}
+
+ void SetUp() override {
+ selected_store_ = new TestingPrefStore;
+ default_store_ = new TestingPrefStore;
+
+ std::set<std::string> selected_pref_names;
+ selected_pref_names.insert(kSelectedPref);
+ selected_pref_names.insert(kSharedPref);
+
+ segregated_store_ = new SegregatedPrefStore(default_store_, selected_store_,
+ selected_pref_names, nullptr);
+
+ segregated_store_->AddObserver(&observer_);
+ }
+
+ void TearDown() override { segregated_store_->RemoveObserver(&observer_); }
+
+ protected:
+ std::unique_ptr<PersistentPrefStore::ReadErrorDelegate>
+ GetReadErrorDelegate() {
+ EXPECT_TRUE(read_error_delegate_);
+ return std::move(read_error_delegate_);
+ }
+
+ PrefStoreObserverMock observer_;
+
+ scoped_refptr<TestingPrefStore> default_store_;
+ scoped_refptr<TestingPrefStore> selected_store_;
+ scoped_refptr<SegregatedPrefStore> segregated_store_;
+
+ MockReadErrorDelegate::Data read_error_delegate_data_;
+
+ private:
+ std::unique_ptr<MockReadErrorDelegate> read_error_delegate_;
+};
+
+TEST_F(SegregatedPrefStoreTest, StoreValues) {
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ segregated_store_->ReadPrefs());
+
+ // Properly stores new values.
+ segregated_store_->SetValue(kSelectedPref,
+ base::MakeUnique<base::Value>(kValue1),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ segregated_store_->SetValue(kUnselectedPref,
+ base::MakeUnique<base::Value>(kValue2),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+ ASSERT_TRUE(selected_store_->GetValue(kSelectedPref, NULL));
+ ASSERT_FALSE(selected_store_->GetValue(kUnselectedPref, NULL));
+ ASSERT_FALSE(default_store_->GetValue(kSelectedPref, NULL));
+ ASSERT_TRUE(default_store_->GetValue(kUnselectedPref, NULL));
+
+ ASSERT_TRUE(segregated_store_->GetValue(kSelectedPref, NULL));
+ ASSERT_TRUE(segregated_store_->GetValue(kUnselectedPref, NULL));
+
+ ASSERT_FALSE(selected_store_->committed());
+ ASSERT_FALSE(default_store_->committed());
+
+ segregated_store_->CommitPendingWrite();
+
+ ASSERT_TRUE(selected_store_->committed());
+ ASSERT_TRUE(default_store_->committed());
+}
+
+TEST_F(SegregatedPrefStoreTest, ReadValues) {
+ selected_store_->SetValue(kSelectedPref,
+ base::MakeUnique<base::Value>(kValue1),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ default_store_->SetValue(kUnselectedPref,
+ base::MakeUnique<base::Value>(kValue2),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+ // Works properly with values that are already there.
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ segregated_store_->ReadPrefs());
+ ASSERT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ segregated_store_->GetReadError());
+
+ ASSERT_TRUE(selected_store_->GetValue(kSelectedPref, NULL));
+ ASSERT_FALSE(selected_store_->GetValue(kUnselectedPref, NULL));
+ ASSERT_FALSE(default_store_->GetValue(kSelectedPref, NULL));
+ ASSERT_TRUE(default_store_->GetValue(kUnselectedPref, NULL));
+
+ ASSERT_TRUE(segregated_store_->GetValue(kSelectedPref, NULL));
+ ASSERT_TRUE(segregated_store_->GetValue(kUnselectedPref, NULL));
+}
+
+TEST_F(SegregatedPrefStoreTest, Observer) {
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ segregated_store_->ReadPrefs());
+ EXPECT_TRUE(observer_.initialized);
+ EXPECT_TRUE(observer_.initialization_success);
+ EXPECT_TRUE(observer_.changed_keys.empty());
+ segregated_store_->SetValue(kSelectedPref,
+ base::MakeUnique<base::Value>(kValue1),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ observer_.VerifyAndResetChangedKey(kSelectedPref);
+ segregated_store_->SetValue(kUnselectedPref,
+ base::MakeUnique<base::Value>(kValue2),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ observer_.VerifyAndResetChangedKey(kUnselectedPref);
+}
+
+TEST_F(SegregatedPrefStoreTest, SelectedPrefReadNoFileError) {
+ // PREF_READ_ERROR_NO_FILE for the selected prefs file is silently converted
+ // to PREF_READ_ERROR_NONE.
+ selected_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ segregated_store_->ReadPrefs());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ segregated_store_->GetReadError());
+}
+
+TEST_F(SegregatedPrefStoreTest, SelectedPrefReadError) {
+ selected_store_->set_read_error(
+ PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
+ segregated_store_->ReadPrefs());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
+ segregated_store_->GetReadError());
+}
+
+TEST_F(SegregatedPrefStoreTest, SelectedPrefReadNoFileErrorAsync) {
+ // PREF_READ_ERROR_NO_FILE for the selected prefs file is silently converted
+ // to PREF_READ_ERROR_NONE.
+ selected_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
+
+ default_store_->SetBlockAsyncRead(true);
+
+ EXPECT_FALSE(read_error_delegate_data_.invoked);
+
+ segregated_store_->ReadPrefsAsync(GetReadErrorDelegate().release());
+
+ EXPECT_FALSE(read_error_delegate_data_.invoked);
+
+ default_store_->SetBlockAsyncRead(false);
+
+ // ReadErrorDelegate is not invoked for ERROR_NONE.
+ EXPECT_FALSE(read_error_delegate_data_.invoked);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ segregated_store_->GetReadError());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE,
+ segregated_store_->GetReadError());
+}
+
+TEST_F(SegregatedPrefStoreTest, UnselectedPrefReadNoFileError) {
+ default_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+ segregated_store_->ReadPrefs());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+ segregated_store_->GetReadError());
+}
+
+TEST_F(SegregatedPrefStoreTest, UnselectedPrefReadError) {
+ default_store_->set_read_error(
+ PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
+ segregated_store_->ReadPrefs());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED,
+ segregated_store_->GetReadError());
+}
+
+TEST_F(SegregatedPrefStoreTest, BothPrefReadError) {
+ default_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
+ selected_store_->set_read_error(
+ PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+ segregated_store_->ReadPrefs());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+ segregated_store_->GetReadError());
+}
+
+TEST_F(SegregatedPrefStoreTest, BothPrefReadErrorAsync) {
+ default_store_->set_read_error(PersistentPrefStore::PREF_READ_ERROR_NO_FILE);
+ selected_store_->set_read_error(
+ PersistentPrefStore::PREF_READ_ERROR_ACCESS_DENIED);
+
+ selected_store_->SetBlockAsyncRead(true);
+
+ EXPECT_FALSE(read_error_delegate_data_.invoked);
+
+ segregated_store_->ReadPrefsAsync(GetReadErrorDelegate().release());
+
+ EXPECT_FALSE(read_error_delegate_data_.invoked);
+
+ selected_store_->SetBlockAsyncRead(false);
+
+ EXPECT_TRUE(read_error_delegate_data_.invoked);
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+ segregated_store_->GetReadError());
+ EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NO_FILE,
+ segregated_store_->GetReadError());
+}
+
+TEST_F(SegregatedPrefStoreTest, IsInitializationComplete) {
+ EXPECT_FALSE(segregated_store_->IsInitializationComplete());
+ segregated_store_->ReadPrefs();
+ EXPECT_TRUE(segregated_store_->IsInitializationComplete());
+}
+
+TEST_F(SegregatedPrefStoreTest, IsInitializationCompleteAsync) {
+ selected_store_->SetBlockAsyncRead(true);
+ default_store_->SetBlockAsyncRead(true);
+ EXPECT_FALSE(segregated_store_->IsInitializationComplete());
+ segregated_store_->ReadPrefsAsync(NULL);
+ EXPECT_FALSE(segregated_store_->IsInitializationComplete());
+ selected_store_->SetBlockAsyncRead(false);
+ EXPECT_FALSE(segregated_store_->IsInitializationComplete());
+ default_store_->SetBlockAsyncRead(false);
+ EXPECT_TRUE(segregated_store_->IsInitializationComplete());
+}
+
+TEST_F(SegregatedPrefStoreTest, GetValues) {
+ // To check merge behavior, create selected and default stores so each has a
+ // key the other doesn't have and they have one key in common.
+ selected_store_->SetValue(kSelectedPref,
+ base::MakeUnique<base::Value>(kValue1),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ default_store_->SetValue(kUnselectedPref,
+ base::MakeUnique<base::Value>(kValue2),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ selected_store_->SetValue(kSharedPref, base::MakeUnique<base::Value>(kValue1),
+ WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+
+ auto values = segregated_store_->GetValues();
+ const base::Value* value = nullptr;
+ // Check that a selected preference is returned.
+ ASSERT_TRUE(values->Get(kSelectedPref, &value));
+ EXPECT_TRUE(base::Value(kValue1).Equals(value));
+
+ // Check that a a default preference is returned.
+ ASSERT_TRUE(values->Get(kUnselectedPref, &value));
+ EXPECT_TRUE(base::Value(kValue2).Equals(value));
+
+ // Check that the selected preference is preferred.
+ ASSERT_TRUE(values->Get(kSharedPref, &value));
+ EXPECT_TRUE(base::Value(kValue1).Equals(value));
+}
diff --git a/chromium/services/preferences/tracked/tracked_atomic_preference.cc b/chromium/services/preferences/tracked/tracked_atomic_preference.cc
new file mode 100644
index 00000000000..8df3a3609fa
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_atomic_preference.cc
@@ -0,0 +1,89 @@
+// 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/preferences/tracked/tracked_atomic_preference.h"
+
+#include "base/values.h"
+#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+
+using ValueState =
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
+
+TrackedAtomicPreference::TrackedAtomicPreference(
+ const std::string& pref_path,
+ size_t reporting_id,
+ size_t reporting_ids_count,
+ prefs::mojom::TrackedPreferenceMetadata::EnforcementLevel enforcement_level,
+ prefs::mojom::TrackedPreferenceMetadata::ValueType value_type,
+ prefs::mojom::TrackedPreferenceValidationDelegate* delegate)
+ : pref_path_(pref_path),
+ helper_(pref_path,
+ reporting_id,
+ reporting_ids_count,
+ enforcement_level,
+ value_type),
+ delegate_(delegate) {}
+
+TrackedPreferenceType TrackedAtomicPreference::GetType() const {
+ return TrackedPreferenceType::ATOMIC;
+}
+
+void TrackedAtomicPreference::OnNewValue(
+ const base::Value* value,
+ PrefHashStoreTransaction* transaction) const {
+ transaction->StoreHash(pref_path_, value);
+}
+
+bool TrackedAtomicPreference::EnforceAndReport(
+ base::DictionaryValue* pref_store_contents,
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const {
+ const base::Value* value = NULL;
+ pref_store_contents->Get(pref_path_, &value);
+ ValueState value_state = transaction->CheckValue(pref_path_, value);
+ helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix());
+
+ ValueState external_validation_value_state = ValueState::UNSUPPORTED;
+ if (external_validation_transaction) {
+ external_validation_value_state =
+ external_validation_transaction->CheckValue(pref_path_, value);
+ helper_.ReportValidationResult(
+ external_validation_value_state,
+ external_validation_transaction->GetStoreUMASuffix());
+ }
+
+ if (delegate_) {
+ delegate_->OnAtomicPreferenceValidation(
+ pref_path_, value ? value->CreateDeepCopy() : nullptr, value_state,
+ external_validation_value_state, helper_.IsPersonal());
+ }
+ TrackedPreferenceHelper::ResetAction reset_action =
+ helper_.GetAction(value_state);
+ helper_.ReportAction(reset_action);
+
+ bool was_reset = false;
+ if (reset_action == TrackedPreferenceHelper::DO_RESET) {
+ pref_store_contents->RemovePath(pref_path_, NULL);
+ was_reset = true;
+ }
+
+ if (value_state != ValueState::UNCHANGED) {
+ // Store the hash for the new value (whether it was reset or not).
+ const base::Value* new_value = NULL;
+ pref_store_contents->Get(pref_path_, &new_value);
+ transaction->StoreHash(pref_path_, new_value);
+ }
+
+ // Update MACs in the external store if there is one and there either was a
+ // reset or external validation failed.
+ if (external_validation_transaction &&
+ (was_reset || external_validation_value_state != ValueState::UNCHANGED)) {
+ const base::Value* new_value = nullptr;
+ pref_store_contents->Get(pref_path_, &new_value);
+ external_validation_transaction->StoreHash(pref_path_, new_value);
+ }
+
+ return was_reset;
+}
diff --git a/chromium/services/preferences/tracked/tracked_atomic_preference.h b/chromium/services/preferences/tracked/tracked_atomic_preference.h
new file mode 100644
index 00000000000..3f3477e9dd9
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_atomic_preference.h
@@ -0,0 +1,55 @@
+// 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_PREFERENCES_TRACKED_TRACKED_ATOMIC_PREFERENCE_H_
+#define SERVICES_PREFERENCES_TRACKED_TRACKED_ATOMIC_PREFERENCE_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "services/preferences/tracked/pref_hash_filter.h"
+#include "services/preferences/tracked/tracked_preference.h"
+#include "services/preferences/tracked/tracked_preference_helper.h"
+
+namespace prefs {
+namespace mojom {
+class TrackedPreferenceValidationDelegate;
+}
+}
+
+// A TrackedAtomicPreference is tracked as a whole. A hash is stored for its
+// entire value and it is entirely reset on mismatch. An optional delegate is
+// notified of the status of the preference during enforcement.
+class TrackedAtomicPreference : public TrackedPreference {
+ public:
+ TrackedAtomicPreference(
+ const std::string& pref_path,
+ size_t reporting_id,
+ size_t reporting_ids_count,
+ prefs::mojom::TrackedPreferenceMetadata::EnforcementLevel
+ enforcement_level,
+ prefs::mojom::TrackedPreferenceMetadata::ValueType value_type,
+ prefs::mojom::TrackedPreferenceValidationDelegate* delegate);
+
+ // TrackedPreference implementation.
+ TrackedPreferenceType GetType() const override;
+ void OnNewValue(const base::Value* value,
+ PrefHashStoreTransaction* transaction) const override;
+ bool EnforceAndReport(
+ base::DictionaryValue* pref_store_contents,
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const override;
+
+ private:
+ const std::string pref_path_;
+ const TrackedPreferenceHelper helper_;
+ prefs::mojom::TrackedPreferenceValidationDelegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrackedAtomicPreference);
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_TRACKED_ATOMIC_PREFERENCE_H_
diff --git a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
new file mode 100644
index 00000000000..ffb5ab2e9ac
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.cc
@@ -0,0 +1,133 @@
+// 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/preferences/tracked/tracked_persistent_pref_store_factory.h"
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#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/tracked/pref_hash_filter.h"
+#include "services/preferences/tracked/pref_hash_store_impl.h"
+#include "services/preferences/tracked/segregated_pref_store.h"
+#include "services/preferences/tracked/tracked_preferences_migration.h"
+
+#if defined(OS_WIN)
+#include "services/preferences/tracked/registry_hash_store_contents_win.h"
+#endif
+
+namespace {
+
+void RemoveValueSilently(const base::WeakPtr<JsonPrefStore> pref_store,
+ const std::string& key) {
+ if (pref_store) {
+ pref_store->RemoveValueSilently(
+ key, WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+ }
+}
+
+std::unique_ptr<PrefHashStore> CreatePrefHashStore(
+ const prefs::mojom::TrackedPersistentPrefStoreConfiguration& config,
+ bool use_super_mac) {
+ return base::MakeUnique<PrefHashStoreImpl>(
+ config.seed, config.legacy_device_id, use_super_mac);
+}
+
+std::pair<std::unique_ptr<PrefHashStore>, std::unique_ptr<HashStoreContents>>
+GetExternalVerificationPrefHashStorePair(
+ const prefs::mojom::TrackedPersistentPrefStoreConfiguration& config) {
+#if defined(OS_WIN)
+ return std::make_pair(
+ base::MakeUnique<PrefHashStoreImpl>(config.registry_seed,
+ config.legacy_device_id,
+ false /* use_super_mac */),
+ base::MakeUnique<RegistryHashStoreContentsWin>(
+ config.registry_path, config.unprotected_pref_filename.DirName()
+ .BaseName()
+ .LossyDisplayName()));
+#else
+ return std::make_pair(nullptr, nullptr);
+#endif
+}
+
+} // namespace
+
+PersistentPrefStore* CreateTrackedPersistentPrefStore(
+ prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr config,
+ base::SequencedWorkerPool* worker_pool) {
+ auto io_task_runner = JsonPrefStore::GetTaskRunnerForFile(
+ config->unprotected_pref_filename.DirName(), worker_pool);
+
+ std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
+ unprotected_configuration;
+ std::vector<prefs::mojom::TrackedPreferenceMetadataPtr>
+ protected_configuration;
+ std::set<std::string> protected_pref_names;
+ std::set<std::string> unprotected_pref_names;
+ for (auto& metadata : config->tracking_configuration) {
+ if (metadata->enforcement_level > prefs::mojom::TrackedPreferenceMetadata::
+ EnforcementLevel::NO_ENFORCEMENT) {
+ protected_pref_names.insert(metadata->name);
+ protected_configuration.push_back(std::move(metadata));
+ } else {
+ unprotected_pref_names.insert(metadata->name);
+ unprotected_configuration.push_back(std::move(metadata));
+ }
+ }
+ config->tracking_configuration.clear();
+
+ std::unique_ptr<PrefHashFilter> unprotected_pref_hash_filter(
+ new PrefHashFilter(CreatePrefHashStore(*config, false),
+ GetExternalVerificationPrefHashStorePair(*config),
+ unprotected_configuration, nullptr,
+ config->validation_delegate.get(),
+ config->reporting_ids_count, false));
+ std::unique_ptr<PrefHashFilter> protected_pref_hash_filter(new PrefHashFilter(
+ CreatePrefHashStore(*config, true),
+ GetExternalVerificationPrefHashStorePair(*config),
+ protected_configuration, std::move(config->reset_on_load_observer),
+ config->validation_delegate.get(), config->reporting_ids_count, true));
+
+ PrefHashFilter* raw_unprotected_pref_hash_filter =
+ unprotected_pref_hash_filter.get();
+ PrefHashFilter* raw_protected_pref_hash_filter =
+ protected_pref_hash_filter.get();
+
+ scoped_refptr<JsonPrefStore> unprotected_pref_store(
+ new JsonPrefStore(config->unprotected_pref_filename, io_task_runner.get(),
+ std::move(unprotected_pref_hash_filter)));
+ scoped_refptr<JsonPrefStore> protected_pref_store(
+ new JsonPrefStore(config->protected_pref_filename, io_task_runner.get(),
+ std::move(protected_pref_hash_filter)));
+
+ SetupTrackedPreferencesMigration(
+ unprotected_pref_names, protected_pref_names,
+ base::Bind(&RemoveValueSilently, unprotected_pref_store->AsWeakPtr()),
+ base::Bind(&RemoveValueSilently, protected_pref_store->AsWeakPtr()),
+ base::Bind(&JsonPrefStore::RegisterOnNextSuccessfulWriteReply,
+ unprotected_pref_store->AsWeakPtr()),
+ base::Bind(&JsonPrefStore::RegisterOnNextSuccessfulWriteReply,
+ protected_pref_store->AsWeakPtr()),
+ CreatePrefHashStore(*config, false), CreatePrefHashStore(*config, true),
+ raw_unprotected_pref_hash_filter, raw_protected_pref_hash_filter);
+
+ return new SegregatedPrefStore(unprotected_pref_store, protected_pref_store,
+ protected_pref_names,
+ std::move(config->validation_delegate));
+}
+
+void InitializeMasterPrefsTracking(
+ prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr configuration,
+ base::DictionaryValue* master_prefs) {
+ PrefHashFilter(CreatePrefHashStore(*configuration, false),
+ GetExternalVerificationPrefHashStorePair(*configuration),
+ configuration->tracking_configuration, nullptr, nullptr,
+ configuration->reporting_ids_count, false)
+ .Initialize(master_prefs);
+}
diff --git a/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h
new file mode 100644
index 00000000000..fb426bab47d
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_persistent_pref_store_factory.h
@@ -0,0 +1,27 @@
+// 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_PREFERENCES_TRACKED_TRACKED_PERSISTENT_PREF_STORE_FACTORY_H_
+#define SERVICES_PREFERENCES_TRACKED_TRACKED_PERSISTENT_PREF_STORE_FACTORY_H_
+
+#include <utility>
+#include "services/preferences/public/interfaces/preferences_configuration.mojom.h"
+
+namespace base {
+class DictionaryValue;
+class SequencedWorkerPool;
+}
+
+class PersistentPrefStore;
+
+PersistentPrefStore* CreateTrackedPersistentPrefStore(
+ prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr config,
+ base::SequencedWorkerPool* worker_pool);
+
+// TODO(sammc): This should move somewhere more appropriate in the longer term.
+void InitializeMasterPrefsTracking(
+ prefs::mojom::TrackedPersistentPrefStoreConfigurationPtr configuration,
+ base::DictionaryValue* master_prefs);
+
+#endif // SERVICES_PREFERENCES_TRACKED_TRACKED_PERSISTENT_PREF_STORE_FACTORY_H_
diff --git a/chromium/services/preferences/tracked/tracked_preference.h b/chromium/services/preferences/tracked/tracked_preference.h
new file mode 100644
index 00000000000..eeb333c52a1
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_preference.h
@@ -0,0 +1,44 @@
+// 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_PREFERENCES_TRACKED_TRACKED_PREFERENCE_H_
+#define SERVICES_PREFERENCES_TRACKED_TRACKED_PREFERENCE_H_
+
+class PrefHashStoreTransaction;
+
+namespace base {
+class DictionaryValue;
+class Value;
+}
+
+enum class TrackedPreferenceType { ATOMIC, SPLIT };
+
+// A TrackedPreference tracks changes to an individual preference, reporting and
+// reacting to them according to preference-specific and browser-wide policies.
+class TrackedPreference {
+ public:
+ virtual ~TrackedPreference() {}
+
+ virtual TrackedPreferenceType GetType() const = 0;
+
+ // Notifies the underlying TrackedPreference about its new |value| which
+ // can update hashes in the corresponding hash store via |transaction|.
+ virtual void OnNewValue(const base::Value* value,
+ PrefHashStoreTransaction* transaction) const = 0;
+
+ // Verifies that the value of this TrackedPreference in |pref_store_contents|
+ // is valid. Responds to verification failures according to
+ // preference-specific and browser-wide policy and reports results to via UMA.
+ // May use |transaction| to check/modify hashes in the corresponding hash
+ // store. Performs validation and reports results without enforcing for
+ // |external_validation_transaction|. This call assumes exclusive access to
+ // |external_validation_transaction| and its associated state and as such
+ // should only be called before any other subsystem is made aware of it.
+ virtual bool EnforceAndReport(
+ base::DictionaryValue* pref_store_contents,
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const = 0;
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_TRACKED_PREFERENCE_H_
diff --git a/chromium/services/preferences/tracked/tracked_preference_helper.cc b/chromium/services/preferences/tracked/tracked_preference_helper.cc
new file mode 100644
index 00000000000..d368ddb2f00
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_preference_helper.cc
@@ -0,0 +1,139 @@
+// 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/preferences/tracked/tracked_preference_helper.h"
+
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
+#include "services/preferences/public/cpp/tracked/tracked_preference_histogram_names.h"
+
+using ValueState =
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
+
+TrackedPreferenceHelper::TrackedPreferenceHelper(
+ const std::string& pref_path,
+ size_t reporting_id,
+ size_t reporting_ids_count,
+ prefs::mojom::TrackedPreferenceMetadata::EnforcementLevel enforcement_level,
+ prefs::mojom::TrackedPreferenceMetadata::ValueType value_type)
+ : pref_path_(pref_path),
+ reporting_id_(reporting_id),
+ reporting_ids_count_(reporting_ids_count),
+ enforce_(enforcement_level == prefs::mojom::TrackedPreferenceMetadata::
+ EnforcementLevel::ENFORCE_ON_LOAD),
+ personal_(value_type ==
+ prefs::mojom::TrackedPreferenceMetadata::ValueType::PERSONAL) {}
+
+TrackedPreferenceHelper::ResetAction TrackedPreferenceHelper::GetAction(
+ ValueState value_state) const {
+ switch (value_state) {
+ case ValueState::UNCHANGED:
+ // Desired case, nothing to do.
+ return DONT_RESET;
+ case ValueState::CLEARED:
+ // Unfortunate case, but there is nothing we can do.
+ return DONT_RESET;
+ case ValueState::TRUSTED_NULL_VALUE: // Falls through.
+ case ValueState::TRUSTED_UNKNOWN_VALUE:
+ // It is okay to seed the hash in this case.
+ return DONT_RESET;
+ case ValueState::SECURE_LEGACY:
+ // Accept secure legacy device ID based hashes.
+ return DONT_RESET;
+ case ValueState::UNSUPPORTED:
+ NOTREACHED()
+ << "GetAction should not be called with an UNSUPPORTED value state";
+ return DONT_RESET;
+ case ValueState::UNTRUSTED_UNKNOWN_VALUE: // Falls through.
+ case ValueState::CHANGED:
+ return enforce_ ? DO_RESET : WANTED_RESET;
+ }
+ NOTREACHED() << "Unexpected ValueState: " << value_state;
+ return DONT_RESET;
+}
+
+bool TrackedPreferenceHelper::IsPersonal() const {
+ return personal_;
+}
+
+void TrackedPreferenceHelper::ReportValidationResult(
+ ValueState value_state,
+ base::StringPiece validation_type_suffix) const {
+ const char* histogram_name = nullptr;
+ switch (value_state) {
+ case ValueState::UNCHANGED:
+ histogram_name = user_prefs::tracked::kTrackedPrefHistogramUnchanged;
+ break;
+ case ValueState::CLEARED:
+ histogram_name = user_prefs::tracked::kTrackedPrefHistogramCleared;
+ break;
+ case ValueState::SECURE_LEGACY:
+ histogram_name =
+ user_prefs::tracked::kTrackedPrefHistogramMigratedLegacyDeviceId;
+ break;
+ case ValueState::CHANGED:
+ histogram_name = user_prefs::tracked::kTrackedPrefHistogramChanged;
+ break;
+ case ValueState::UNTRUSTED_UNKNOWN_VALUE:
+ histogram_name = user_prefs::tracked::kTrackedPrefHistogramInitialized;
+ break;
+ case ValueState::TRUSTED_UNKNOWN_VALUE:
+ histogram_name =
+ user_prefs::tracked::kTrackedPrefHistogramTrustedInitialized;
+ break;
+ case ValueState::TRUSTED_NULL_VALUE:
+ histogram_name =
+ user_prefs::tracked::kTrackedPrefHistogramNullInitialized;
+ break;
+ case ValueState::UNSUPPORTED:
+ NOTREACHED() << "ReportValidationResult should not be called with an "
+ "UNSUPPORTED value state";
+ return;
+ }
+ DCHECK(histogram_name);
+
+ std::string full_histogram_name(histogram_name);
+ if (!validation_type_suffix.empty()) {
+ full_histogram_name.push_back('.');
+ validation_type_suffix.AppendToString(&full_histogram_name);
+ }
+
+ // Using FactoryGet to allow dynamic histogram names. This is equivalent to
+ // UMA_HISTOGRAM_ENUMERATION(name, reporting_id_, reporting_ids_count_);
+ base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+ full_histogram_name, 1, reporting_ids_count_, reporting_ids_count_ + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(reporting_id_);
+}
+
+void TrackedPreferenceHelper::ReportAction(ResetAction reset_action) const {
+ switch (reset_action) {
+ case DONT_RESET:
+ // No report for DONT_RESET.
+ break;
+ case WANTED_RESET:
+ UMA_HISTOGRAM_EXACT_LINEAR(
+ user_prefs::tracked::kTrackedPrefHistogramWantedReset, reporting_id_,
+ reporting_ids_count_);
+ break;
+ case DO_RESET:
+ UMA_HISTOGRAM_EXACT_LINEAR(
+ user_prefs::tracked::kTrackedPrefHistogramReset, reporting_id_,
+ reporting_ids_count_);
+ break;
+ }
+}
+
+void TrackedPreferenceHelper::ReportSplitPreferenceChangedCount(
+ size_t count) const {
+ // The histogram below is an expansion of the UMA_HISTOGRAM_COUNTS_100 macro
+ // adapted to allow for a dynamically suffixed histogram name.
+ // Note: The factory creates and owns the histogram.
+ base::HistogramBase* histogram = base::LinearHistogram::FactoryGet(
+ user_prefs::tracked::kTrackedSplitPrefHistogramChanged + pref_path_, 1,
+ 100, // Allow counts up to 100.
+ 101, base::HistogramBase::kUmaTargetedHistogramFlag);
+ histogram->Add(count);
+}
diff --git a/chromium/services/preferences/tracked/tracked_preference_helper.h b/chromium/services/preferences/tracked/tracked_preference_helper.h
new file mode 100644
index 00000000000..182520dd106
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_preference_helper.h
@@ -0,0 +1,75 @@
+// 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_PREFERENCES_TRACKED_TRACKED_PREFERENCE_HELPER_H_
+#define SERVICES_PREFERENCES_TRACKED_TRACKED_PREFERENCE_HELPER_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/macros.h"
+#include "services/preferences/tracked/pref_hash_filter.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+
+// A TrackedPreferenceHelper is a helper class for TrackedPreference which
+// handles decision making and reporting for TrackedPreference's
+// implementations.
+class TrackedPreferenceHelper {
+ public:
+ enum ResetAction {
+ DONT_RESET,
+ // WANTED_RESET is reported when DO_RESET would have been reported but the
+ // current |enforcement_level| doesn't allow a reset for the detected state.
+ WANTED_RESET,
+ DO_RESET,
+ };
+
+ TrackedPreferenceHelper(
+ const std::string& pref_path,
+ size_t reporting_id,
+ size_t reporting_ids_count,
+ prefs::mojom::TrackedPreferenceMetadata::EnforcementLevel
+ enforcement_level,
+ prefs::mojom::TrackedPreferenceMetadata::ValueType value_type);
+
+ // Returns a ResetAction stating whether a reset is desired (DO_RESET) or not
+ // (DONT_RESET) based on observing |value_state|. Can also return WANTED_RESET
+ // if a reset would have been desired but the current |enforcement_level|
+ // doesn't allow it.
+ ResetAction GetAction(
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state)
+ const;
+
+ // Returns true if the preference value may contain personal information.
+ bool IsPersonal() const;
+
+ // Reports |value_state| via UMA under |reporting_id_|.
+ // |validation_type_suffix| is appended to the reported histogram's name.
+ void ReportValidationResult(
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState value_state,
+ base::StringPiece validation_type_suffix) const;
+
+ // Reports |reset_action| via UMA under |reporting_id_|.
+ void ReportAction(ResetAction reset_action) const;
+
+ // Reports, via UMA, the |count| of split preference entries that were
+ // considered invalid in a CHANGED event.
+ void ReportSplitPreferenceChangedCount(size_t count) const;
+
+ private:
+ const std::string pref_path_;
+
+ const size_t reporting_id_;
+ const size_t reporting_ids_count_;
+
+ // Deny setting changes and hash seeding/migration.
+ const bool enforce_;
+
+ const bool personal_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrackedPreferenceHelper);
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_TRACKED_PREFERENCE_HELPER_H_
diff --git a/chromium/services/preferences/tracked/tracked_preferences_migration.cc b/chromium/services/preferences/tracked/tracked_preferences_migration.cc
new file mode 100644
index 00000000000..f2af336e350
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_preferences_migration.cc
@@ -0,0 +1,333 @@
+// 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/preferences/tracked/tracked_preferences_migration.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/metrics/histogram.h"
+#include "base/values.h"
+#include "services/preferences/tracked/dictionary_hash_store_contents.h"
+#include "services/preferences/tracked/hash_store_contents.h"
+#include "services/preferences/tracked/interceptable_pref_filter.h"
+#include "services/preferences/tracked/pref_hash_store.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+
+namespace {
+
+class TrackedPreferencesMigrator
+ : public base::RefCounted<TrackedPreferencesMigrator> {
+ public:
+ TrackedPreferencesMigrator(
+ const std::set<std::string>& unprotected_pref_names,
+ const std::set<std::string>& protected_pref_names,
+ const base::Callback<void(const std::string& key)>&
+ unprotected_store_cleaner,
+ const base::Callback<void(const std::string& key)>&
+ protected_store_cleaner,
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_unprotected_store_write_callback,
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_protected_store_write_callback,
+ std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
+ std::unique_ptr<PrefHashStore> protected_pref_hash_store,
+ InterceptablePrefFilter* unprotected_pref_filter,
+ InterceptablePrefFilter* protected_pref_filter);
+
+ private:
+ friend class base::RefCounted<TrackedPreferencesMigrator>;
+
+ enum PrefFilterID { UNPROTECTED_PREF_FILTER, PROTECTED_PREF_FILTER };
+
+ ~TrackedPreferencesMigrator();
+
+ // Stores the data coming in from the filter identified by |id| into this
+ // class and then calls MigrateIfReady();
+ void InterceptFilterOnLoad(
+ PrefFilterID id,
+ const InterceptablePrefFilter::FinalizeFilterOnLoadCallback&
+ finalize_filter_on_load,
+ std::unique_ptr<base::DictionaryValue> prefs);
+
+ // Proceeds with migration if both |unprotected_prefs_| and |protected_prefs_|
+ // have been set.
+ void MigrateIfReady();
+
+ const std::set<std::string> unprotected_pref_names_;
+ const std::set<std::string> protected_pref_names_;
+
+ const base::Callback<void(const std::string& key)> unprotected_store_cleaner_;
+ const base::Callback<void(const std::string& key)> protected_store_cleaner_;
+ const base::Callback<void(const base::Closure&)>
+ register_on_successful_unprotected_store_write_callback_;
+ const base::Callback<void(const base::Closure&)>
+ register_on_successful_protected_store_write_callback_;
+
+ InterceptablePrefFilter::FinalizeFilterOnLoadCallback
+ finalize_unprotected_filter_on_load_;
+ InterceptablePrefFilter::FinalizeFilterOnLoadCallback
+ finalize_protected_filter_on_load_;
+
+ std::unique_ptr<PrefHashStore> unprotected_pref_hash_store_;
+ std::unique_ptr<PrefHashStore> protected_pref_hash_store_;
+
+ std::unique_ptr<base::DictionaryValue> unprotected_prefs_;
+ std::unique_ptr<base::DictionaryValue> protected_prefs_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrackedPreferencesMigrator);
+};
+
+// Invokes |store_cleaner| for every |keys_to_clean|.
+void CleanupPrefStore(
+ const base::Callback<void(const std::string& key)>& store_cleaner,
+ const std::set<std::string>& keys_to_clean) {
+ for (std::set<std::string>::const_iterator it = keys_to_clean.begin();
+ it != keys_to_clean.end(); ++it) {
+ store_cleaner.Run(*it);
+ }
+}
+
+// If |wait_for_commit_to_destination_store|: schedules (via
+// |register_on_successful_destination_store_write_callback|) a cleanup of the
+// |keys_to_clean| from the source pref store (through |source_store_cleaner|)
+// once the destination pref store they were migrated to was successfully
+// written to disk. Otherwise, executes the cleanup right away.
+void ScheduleSourcePrefStoreCleanup(
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_destination_store_write_callback,
+ const base::Callback<void(const std::string& key)>& source_store_cleaner,
+ const std::set<std::string>& keys_to_clean,
+ bool wait_for_commit_to_destination_store) {
+ DCHECK(!keys_to_clean.empty());
+ if (wait_for_commit_to_destination_store) {
+ register_on_successful_destination_store_write_callback.Run(
+ base::Bind(&CleanupPrefStore, source_store_cleaner, keys_to_clean));
+ } else {
+ CleanupPrefStore(source_store_cleaner, keys_to_clean);
+ }
+}
+
+// Removes hashes for |migrated_pref_names| from |origin_pref_store| using
+// the configuration/implementation in |origin_pref_hash_store|.
+void CleanupMigratedHashes(const std::set<std::string>& migrated_pref_names,
+ PrefHashStore* origin_pref_hash_store,
+ base::DictionaryValue* origin_pref_store) {
+ DictionaryHashStoreContents dictionary_contents(origin_pref_store);
+ std::unique_ptr<PrefHashStoreTransaction> transaction(
+ origin_pref_hash_store->BeginTransaction(&dictionary_contents));
+ for (std::set<std::string>::const_iterator it = migrated_pref_names.begin();
+ it != migrated_pref_names.end(); ++it) {
+ transaction->ClearHash(*it);
+ }
+}
+
+// Copies the value of each pref in |pref_names| which is set in |old_store|,
+// but not in |new_store| into |new_store|. Sets |old_store_needs_cleanup| to
+// true if any old duplicates remain in |old_store| and sets |new_store_altered|
+// to true if any value was copied to |new_store|.
+void MigratePrefsFromOldToNewStore(const std::set<std::string>& pref_names,
+ base::DictionaryValue* old_store,
+ base::DictionaryValue* new_store,
+ PrefHashStore* new_hash_store,
+ bool* old_store_needs_cleanup,
+ bool* new_store_altered) {
+ const base::DictionaryValue* old_hash_store_contents =
+ DictionaryHashStoreContents(old_store).GetContents();
+ DictionaryHashStoreContents dictionary_contents(new_store);
+ std::unique_ptr<PrefHashStoreTransaction> new_hash_store_transaction(
+ new_hash_store->BeginTransaction(&dictionary_contents));
+
+ for (std::set<std::string>::const_iterator it = pref_names.begin();
+ it != pref_names.end(); ++it) {
+ const std::string& pref_name = *it;
+ const base::Value* value_in_old_store = NULL;
+
+ // If the destination does not have a hash for this pref we will
+ // unconditionally attempt to move it.
+ bool destination_hash_missing =
+ !new_hash_store_transaction->HasHash(pref_name);
+ // If we migrate the value we will also attempt to migrate the hash.
+ bool migrated_value = false;
+ if (old_store->Get(pref_name, &value_in_old_store)) {
+ // Whether this value ends up being copied below or was left behind by a
+ // previous incomplete migration, it should be cleaned up.
+ *old_store_needs_cleanup = true;
+
+ if (!new_store->Get(pref_name, NULL)) {
+ // Copy the value from |old_store| to |new_store| rather than moving it
+ // to avoid data loss should |old_store| be flushed to disk without
+ // |new_store| having equivalently been successfully flushed to disk
+ // (e.g., on crash or in cases where |new_store| is read-only following
+ // a read error on startup).
+ new_store->Set(pref_name, value_in_old_store->DeepCopy());
+ migrated_value = true;
+ *new_store_altered = true;
+ }
+ }
+
+ if (destination_hash_missing || migrated_value) {
+ const base::Value* old_hash = NULL;
+ if (old_hash_store_contents)
+ old_hash_store_contents->Get(pref_name, &old_hash);
+ if (old_hash) {
+ new_hash_store_transaction->ImportHash(pref_name, old_hash);
+ *new_store_altered = true;
+ } else if (!destination_hash_missing) {
+ // Do not allow values to be migrated without MACs if the destination
+ // already has a MAC (http://crbug.com/414554). Remove the migrated
+ // value in order to provide the same no-op behaviour as if the pref was
+ // added to the wrong file when there was already a value for
+ // |pref_name| in |new_store|.
+ new_store->Remove(pref_name, NULL);
+ *new_store_altered = true;
+ }
+ }
+ }
+}
+
+TrackedPreferencesMigrator::TrackedPreferencesMigrator(
+ const std::set<std::string>& unprotected_pref_names,
+ const std::set<std::string>& protected_pref_names,
+ const base::Callback<void(const std::string& key)>&
+ unprotected_store_cleaner,
+ const base::Callback<void(const std::string& key)>& protected_store_cleaner,
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_unprotected_store_write_callback,
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_protected_store_write_callback,
+ std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
+ std::unique_ptr<PrefHashStore> protected_pref_hash_store,
+ InterceptablePrefFilter* unprotected_pref_filter,
+ InterceptablePrefFilter* protected_pref_filter)
+ : unprotected_pref_names_(unprotected_pref_names),
+ protected_pref_names_(protected_pref_names),
+ unprotected_store_cleaner_(unprotected_store_cleaner),
+ protected_store_cleaner_(protected_store_cleaner),
+ register_on_successful_unprotected_store_write_callback_(
+ register_on_successful_unprotected_store_write_callback),
+ register_on_successful_protected_store_write_callback_(
+ register_on_successful_protected_store_write_callback),
+ unprotected_pref_hash_store_(std::move(unprotected_pref_hash_store)),
+ protected_pref_hash_store_(std::move(protected_pref_hash_store)) {
+ // The callbacks bound below will own this TrackedPreferencesMigrator by
+ // reference.
+ unprotected_pref_filter->InterceptNextFilterOnLoad(
+ base::Bind(&TrackedPreferencesMigrator::InterceptFilterOnLoad, this,
+ UNPROTECTED_PREF_FILTER));
+ protected_pref_filter->InterceptNextFilterOnLoad(
+ base::Bind(&TrackedPreferencesMigrator::InterceptFilterOnLoad, this,
+ PROTECTED_PREF_FILTER));
+}
+
+TrackedPreferencesMigrator::~TrackedPreferencesMigrator() {}
+
+void TrackedPreferencesMigrator::InterceptFilterOnLoad(
+ PrefFilterID id,
+ const InterceptablePrefFilter::FinalizeFilterOnLoadCallback&
+ finalize_filter_on_load,
+ std::unique_ptr<base::DictionaryValue> prefs) {
+ switch (id) {
+ case UNPROTECTED_PREF_FILTER:
+ finalize_unprotected_filter_on_load_ = finalize_filter_on_load;
+ unprotected_prefs_ = std::move(prefs);
+ break;
+ case PROTECTED_PREF_FILTER:
+ finalize_protected_filter_on_load_ = finalize_filter_on_load;
+ protected_prefs_ = std::move(prefs);
+ break;
+ }
+
+ MigrateIfReady();
+}
+
+void TrackedPreferencesMigrator::MigrateIfReady() {
+ // Wait for both stores to have been read before proceeding.
+ if (!protected_prefs_ || !unprotected_prefs_)
+ return;
+
+ bool protected_prefs_need_cleanup = false;
+ bool unprotected_prefs_altered = false;
+ MigratePrefsFromOldToNewStore(
+ unprotected_pref_names_, protected_prefs_.get(), unprotected_prefs_.get(),
+ unprotected_pref_hash_store_.get(), &protected_prefs_need_cleanup,
+ &unprotected_prefs_altered);
+ bool unprotected_prefs_need_cleanup = false;
+ bool protected_prefs_altered = false;
+ MigratePrefsFromOldToNewStore(
+ protected_pref_names_, unprotected_prefs_.get(), protected_prefs_.get(),
+ protected_pref_hash_store_.get(), &unprotected_prefs_need_cleanup,
+ &protected_prefs_altered);
+
+ if (!unprotected_prefs_altered && !protected_prefs_altered) {
+ // Clean up any MACs that might have been previously migrated from the
+ // various stores. It's safe to leave them behind for a little while as they
+ // will be ignored unless the corresponding value is _also_ present. The
+ // cleanup must be deferred until the MACs have been written to their target
+ // stores, and doing so in a subsequent launch is easier than within the
+ // same process.
+ CleanupMigratedHashes(unprotected_pref_names_,
+ protected_pref_hash_store_.get(),
+ protected_prefs_.get());
+ CleanupMigratedHashes(protected_pref_names_,
+ unprotected_pref_hash_store_.get(),
+ unprotected_prefs_.get());
+ }
+
+ // Hand the processed prefs back to their respective filters.
+ finalize_unprotected_filter_on_load_.Run(std::move(unprotected_prefs_),
+ unprotected_prefs_altered);
+ finalize_protected_filter_on_load_.Run(std::move(protected_prefs_),
+ protected_prefs_altered);
+
+ if (unprotected_prefs_need_cleanup) {
+ // Schedule a cleanup of the |protected_pref_names_| from the unprotected
+ // prefs once the protected prefs were successfully written to disk (or
+ // do it immediately if |!protected_prefs_altered|).
+ ScheduleSourcePrefStoreCleanup(
+ register_on_successful_protected_store_write_callback_,
+ unprotected_store_cleaner_, protected_pref_names_,
+ protected_prefs_altered);
+ }
+
+ if (protected_prefs_need_cleanup) {
+ // Schedule a cleanup of the |unprotected_pref_names_| from the protected
+ // prefs once the unprotected prefs were successfully written to disk (or
+ // do it immediately if |!unprotected_prefs_altered|).
+ ScheduleSourcePrefStoreCleanup(
+ register_on_successful_unprotected_store_write_callback_,
+ protected_store_cleaner_, unprotected_pref_names_,
+ unprotected_prefs_altered);
+ }
+}
+
+} // namespace
+
+void SetupTrackedPreferencesMigration(
+ const std::set<std::string>& unprotected_pref_names,
+ const std::set<std::string>& protected_pref_names,
+ const base::Callback<void(const std::string& key)>&
+ unprotected_store_cleaner,
+ const base::Callback<void(const std::string& key)>& protected_store_cleaner,
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_unprotected_store_write_callback,
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_protected_store_write_callback,
+ std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
+ std::unique_ptr<PrefHashStore> protected_pref_hash_store,
+ InterceptablePrefFilter* unprotected_pref_filter,
+ InterceptablePrefFilter* protected_pref_filter) {
+ scoped_refptr<TrackedPreferencesMigrator> prefs_migrator(
+ new TrackedPreferencesMigrator(
+ unprotected_pref_names, protected_pref_names,
+ unprotected_store_cleaner, protected_store_cleaner,
+ register_on_successful_unprotected_store_write_callback,
+ register_on_successful_protected_store_write_callback,
+ std::move(unprotected_pref_hash_store),
+ std::move(protected_pref_hash_store), unprotected_pref_filter,
+ protected_pref_filter));
+}
diff --git a/chromium/services/preferences/tracked/tracked_preferences_migration.h b/chromium/services/preferences/tracked/tracked_preferences_migration.h
new file mode 100644
index 00000000000..381434aada7
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_preferences_migration.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_PREFERENCES_TRACKED_TRACKED_PREFERENCES_MIGRATION_H_
+#define SERVICES_PREFERENCES_TRACKED_TRACKED_PREFERENCES_MIGRATION_H_
+
+#include <memory>
+#include <set>
+#include <string>
+
+#include "base/callback_forward.h"
+#include "services/preferences/tracked/pref_hash_store.h"
+
+class InterceptablePrefFilter;
+class PrefHashStore;
+
+// Sets up InterceptablePrefFilter::FilterOnLoadInterceptors on
+// |unprotected_pref_filter| and |protected_pref_filter| which prevents each
+// filter from running their on load operations until the interceptors decide to
+// hand the prefs back to them (after migration is complete). |
+// (un)protected_store_cleaner| and
+// |register_on_successful_(un)protected_store_write_callback| are used to do
+// post-migration cleanup tasks. Those should be bound to weak pointers to avoid
+// blocking shutdown. |(un)protected_pref_hash_store| is used to migrate MACs
+// along with their protected preferences. Migrated MACs will only be cleared
+// from their old location in a subsequent run. The migration framework is
+// resilient to a failed cleanup (it will simply try again in the next Chrome
+// run).
+void SetupTrackedPreferencesMigration(
+ const std::set<std::string>& unprotected_pref_names,
+ const std::set<std::string>& protected_pref_names,
+ const base::Callback<void(const std::string& key)>&
+ unprotected_store_cleaner,
+ const base::Callback<void(const std::string& key)>& protected_store_cleaner,
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_unprotected_store_write_callback,
+ const base::Callback<void(const base::Closure&)>&
+ register_on_successful_protected_store_write_callback,
+ std::unique_ptr<PrefHashStore> unprotected_pref_hash_store,
+ std::unique_ptr<PrefHashStore> protected_pref_hash_store,
+ InterceptablePrefFilter* unprotected_pref_filter,
+ InterceptablePrefFilter* protected_pref_filter);
+
+#endif // SERVICES_PREFERENCES_TRACKED_TRACKED_PREFERENCES_MIGRATION_H_
diff --git a/chromium/services/preferences/tracked/tracked_preferences_migration_unittest.cc b/chromium/services/preferences/tracked/tracked_preferences_migration_unittest.cc
new file mode 100644
index 00000000000..fdbdd099d3d
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_preferences_migration_unittest.cc
@@ -0,0 +1,645 @@
+// 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/preferences/tracked/tracked_preferences_migration.h"
+
+#include <memory>
+#include <set>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/strings/string_split.h"
+#include "base/values.h"
+#include "components/prefs/testing_pref_service.h"
+#include "services/preferences/tracked/dictionary_hash_store_contents.h"
+#include "services/preferences/tracked/hash_store_contents.h"
+#include "services/preferences/tracked/interceptable_pref_filter.h"
+#include "services/preferences/tracked/pref_hash_store.h"
+#include "services/preferences/tracked/pref_hash_store_impl.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// An unprotected pref.
+const char kUnprotectedPref[] = "unprotected";
+// A protected pref.
+const char kProtectedPref[] = "protected";
+// A protected pref which is initially stored in the unprotected store.
+const char kPreviouslyUnprotectedPref[] = "previously.unprotected";
+// An unprotected pref which is initially stored in the protected store.
+const char kPreviouslyProtectedPref[] = "previously.protected";
+
+const char kUnprotectedPrefValue[] = "unprotected_value";
+const char kProtectedPrefValue[] = "protected_value";
+const char kPreviouslyUnprotectedPrefValue[] = "previously_unprotected_value";
+const char kPreviouslyProtectedPrefValue[] = "previously_protected_value";
+
+// A simple InterceptablePrefFilter which doesn't do anything but hand the prefs
+// back downstream in FinalizeFilterOnLoad.
+class SimpleInterceptablePrefFilter : public InterceptablePrefFilter {
+ public:
+ // PrefFilter remaining implementation.
+ void FilterUpdate(const std::string& path) override { ADD_FAILURE(); }
+ OnWriteCallbackPair FilterSerializeData(
+ base::DictionaryValue* pref_store_contents) override {
+ ADD_FAILURE();
+ return std::make_pair(base::Closure(),
+ base::Callback<void(bool success)>());
+ }
+
+ private:
+ // InterceptablePrefFilter implementation.
+ void FinalizeFilterOnLoad(
+ const PostFilterOnLoadCallback& post_filter_on_load_callback,
+ std::unique_ptr<base::DictionaryValue> pref_store_contents,
+ bool prefs_altered) override {
+ post_filter_on_load_callback.Run(std::move(pref_store_contents),
+ prefs_altered);
+ }
+};
+
+// A test fixture designed to be used like this:
+// 1) Set up initial store prefs with PresetStoreValue().
+// 2) Hand both sets of prefs to the migrator via HandPrefsToMigrator().
+// 3) Migration completes synchronously when the second store hands its prefs
+// over.
+// 4) Verifications can be made via various methods of this fixture.
+// Call Reset() to perform a second migration.
+class TrackedPreferencesMigrationTest : public testing::Test {
+ public:
+ enum MockPrefStoreID {
+ MOCK_UNPROTECTED_PREF_STORE,
+ MOCK_PROTECTED_PREF_STORE,
+ };
+
+ TrackedPreferencesMigrationTest()
+ : unprotected_prefs_(new base::DictionaryValue),
+ protected_prefs_(new base::DictionaryValue),
+ migration_modified_unprotected_store_(false),
+ migration_modified_protected_store_(false),
+ unprotected_store_migration_complete_(false),
+ protected_store_migration_complete_(false) {}
+
+ void SetUp() override { Reset(); }
+
+ void Reset() {
+ std::set<std::string> unprotected_pref_names;
+ std::set<std::string> protected_pref_names;
+ unprotected_pref_names.insert(kUnprotectedPref);
+ unprotected_pref_names.insert(kPreviouslyProtectedPref);
+ protected_pref_names.insert(kProtectedPref);
+ protected_pref_names.insert(kPreviouslyUnprotectedPref);
+
+ migration_modified_unprotected_store_ = false;
+ migration_modified_protected_store_ = false;
+ unprotected_store_migration_complete_ = false;
+ protected_store_migration_complete_ = false;
+
+ unprotected_store_successful_write_callback_.Reset();
+ protected_store_successful_write_callback_.Reset();
+
+ SetupTrackedPreferencesMigration(
+ unprotected_pref_names, protected_pref_names,
+ base::Bind(&TrackedPreferencesMigrationTest::RemovePathFromStore,
+ base::Unretained(this), MOCK_UNPROTECTED_PREF_STORE),
+ base::Bind(&TrackedPreferencesMigrationTest::RemovePathFromStore,
+ base::Unretained(this), MOCK_PROTECTED_PREF_STORE),
+ base::Bind(
+ &TrackedPreferencesMigrationTest::RegisterSuccessfulWriteClosure,
+ base::Unretained(this), MOCK_UNPROTECTED_PREF_STORE),
+ base::Bind(
+ &TrackedPreferencesMigrationTest::RegisterSuccessfulWriteClosure,
+ base::Unretained(this), MOCK_PROTECTED_PREF_STORE),
+ std::unique_ptr<PrefHashStore>(
+ new PrefHashStoreImpl(kSeed, kDeviceId, false)),
+ std::unique_ptr<PrefHashStore>(
+ new PrefHashStoreImpl(kSeed, kDeviceId, true)),
+ &mock_unprotected_pref_filter_, &mock_protected_pref_filter_);
+
+ // Verify initial expectations are met.
+ EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_FALSE(
+ WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_FALSE(
+ WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
+ }
+
+ protected:
+ // Sets |key| to |value| in the test store identified by |store_id| before
+ // migration begins. Also sets the corresponding hash in the same store.
+ void PresetStoreValue(MockPrefStoreID store_id,
+ const std::string& key,
+ const std::string value) {
+ PresetStoreValueOnly(store_id, key, value);
+ PresetStoreValueHash(store_id, key, value);
+ }
+
+ // Stores a hash for |key| and |value| in the hash store identified by
+ // |store_id| before migration begins.
+ void PresetStoreValueHash(MockPrefStoreID store_id,
+ const std::string& key,
+ const std::string value) {
+ base::DictionaryValue* store = NULL;
+ std::unique_ptr<PrefHashStore> pref_hash_store;
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ store = unprotected_prefs_.get();
+ pref_hash_store.reset(new PrefHashStoreImpl(kSeed, kDeviceId, false));
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ store = protected_prefs_.get();
+ pref_hash_store.reset(new PrefHashStoreImpl(kSeed, kDeviceId, true));
+ break;
+ }
+ DCHECK(store);
+
+ base::Value string_value(value);
+ DictionaryHashStoreContents contents(store);
+ pref_hash_store->BeginTransaction(&contents)->StoreHash(key, &string_value);
+ }
+
+ // Returns true if the store opposite to |store_id| is observed for its next
+ // successful write.
+ bool WasOnSuccessfulWriteCallbackRegistered(MockPrefStoreID store_id) {
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ return !protected_store_successful_write_callback_.is_null();
+ case MOCK_PROTECTED_PREF_STORE:
+ return !unprotected_store_successful_write_callback_.is_null();
+ }
+ NOTREACHED();
+ return false;
+ }
+
+ // Verifies that the (key, value) pairs in |expected_prefs_in_store| are found
+ // in the store identified by |store_id|.
+ void VerifyValuesStored(MockPrefStoreID store_id,
+ const base::StringPairs& expected_prefs_in_store) {
+ base::DictionaryValue* store = NULL;
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ store = unprotected_prefs_.get();
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ store = protected_prefs_.get();
+ break;
+ }
+ DCHECK(store);
+
+ for (base::StringPairs::const_iterator it = expected_prefs_in_store.begin();
+ it != expected_prefs_in_store.end(); ++it) {
+ std::string val;
+ EXPECT_TRUE(store->GetString(it->first, &val));
+ EXPECT_EQ(it->second, val);
+ }
+ }
+
+ // Determines whether |expected_pref_in_hash_store| has a hash in the hash
+ // store identified by |store_id|.
+ bool ContainsHash(MockPrefStoreID store_id,
+ std::string expected_pref_in_hash_store) {
+ base::DictionaryValue* store = NULL;
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ store = unprotected_prefs_.get();
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ store = protected_prefs_.get();
+ break;
+ }
+ DCHECK(store);
+ const base::DictionaryValue* hash_store_contents =
+ DictionaryHashStoreContents(store).GetContents();
+ return hash_store_contents &&
+ hash_store_contents->GetString(expected_pref_in_hash_store,
+ static_cast<std::string*>(NULL));
+ }
+
+ // Both stores need to hand their prefs over in order for migration to kick
+ // in.
+ void HandPrefsToMigrator(MockPrefStoreID store_id) {
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ mock_unprotected_pref_filter_.FilterOnLoad(
+ base::Bind(&TrackedPreferencesMigrationTest::GetPrefsBack,
+ base::Unretained(this), MOCK_UNPROTECTED_PREF_STORE),
+ std::move(unprotected_prefs_));
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ mock_protected_pref_filter_.FilterOnLoad(
+ base::Bind(&TrackedPreferencesMigrationTest::GetPrefsBack,
+ base::Unretained(this), MOCK_PROTECTED_PREF_STORE),
+ std::move(protected_prefs_));
+ break;
+ }
+ }
+
+ bool HasPrefs(MockPrefStoreID store_id) {
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ return !!unprotected_prefs_;
+ case MOCK_PROTECTED_PREF_STORE:
+ return !!protected_prefs_;
+ }
+ NOTREACHED();
+ return false;
+ }
+
+ bool StoreModifiedByMigration(MockPrefStoreID store_id) {
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ return migration_modified_unprotected_store_;
+ case MOCK_PROTECTED_PREF_STORE:
+ return migration_modified_protected_store_;
+ }
+ NOTREACHED();
+ return false;
+ }
+
+ bool MigrationCompleted() {
+ return unprotected_store_migration_complete_ &&
+ protected_store_migration_complete_;
+ }
+
+ void SimulateSuccessfulWrite(MockPrefStoreID store_id) {
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ EXPECT_FALSE(unprotected_store_successful_write_callback_.is_null());
+ unprotected_store_successful_write_callback_.Run();
+ unprotected_store_successful_write_callback_.Reset();
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ EXPECT_FALSE(protected_store_successful_write_callback_.is_null());
+ protected_store_successful_write_callback_.Run();
+ protected_store_successful_write_callback_.Reset();
+ break;
+ }
+ }
+
+ private:
+ void RegisterSuccessfulWriteClosure(
+ MockPrefStoreID store_id,
+ const base::Closure& successful_write_closure) {
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ EXPECT_TRUE(unprotected_store_successful_write_callback_.is_null());
+ unprotected_store_successful_write_callback_ = successful_write_closure;
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ EXPECT_TRUE(protected_store_successful_write_callback_.is_null());
+ protected_store_successful_write_callback_ = successful_write_closure;
+ break;
+ }
+ }
+
+ // Helper given as an InterceptablePrefFilter::FinalizeFilterOnLoadCallback
+ // to the migrator to be invoked when it's done.
+ void GetPrefsBack(MockPrefStoreID store_id,
+ std::unique_ptr<base::DictionaryValue> prefs,
+ bool prefs_altered) {
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ EXPECT_FALSE(unprotected_prefs_);
+ unprotected_prefs_ = std::move(prefs);
+ migration_modified_unprotected_store_ = prefs_altered;
+ unprotected_store_migration_complete_ = true;
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ EXPECT_FALSE(protected_prefs_);
+ protected_prefs_ = std::move(prefs);
+ migration_modified_protected_store_ = prefs_altered;
+ protected_store_migration_complete_ = true;
+ break;
+ }
+ }
+
+ // Helper given as a cleaning callback to the migrator.
+ void RemovePathFromStore(MockPrefStoreID store_id, const std::string& key) {
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ ASSERT_TRUE(unprotected_prefs_);
+ unprotected_prefs_->RemovePath(key, NULL);
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ ASSERT_TRUE(protected_prefs_);
+ protected_prefs_->RemovePath(key, NULL);
+ break;
+ }
+ }
+
+ // Sets |key| to |value| in the test store identified by |store_id| before
+ // migration begins. Does not store a preference hash.
+ void PresetStoreValueOnly(MockPrefStoreID store_id,
+ const std::string& key,
+ const std::string value) {
+ base::DictionaryValue* store = NULL;
+ switch (store_id) {
+ case MOCK_UNPROTECTED_PREF_STORE:
+ store = unprotected_prefs_.get();
+ break;
+ case MOCK_PROTECTED_PREF_STORE:
+ store = protected_prefs_.get();
+ break;
+ }
+ DCHECK(store);
+
+ store->SetString(key, value);
+ }
+
+ static const char kSeed[];
+ static const char kDeviceId[];
+
+ std::unique_ptr<base::DictionaryValue> unprotected_prefs_;
+ std::unique_ptr<base::DictionaryValue> protected_prefs_;
+
+ SimpleInterceptablePrefFilter mock_unprotected_pref_filter_;
+ SimpleInterceptablePrefFilter mock_protected_pref_filter_;
+
+ base::Closure unprotected_store_successful_write_callback_;
+ base::Closure protected_store_successful_write_callback_;
+
+ bool migration_modified_unprotected_store_;
+ bool migration_modified_protected_store_;
+
+ bool unprotected_store_migration_complete_;
+ bool protected_store_migration_complete_;
+
+ TestingPrefServiceSimple local_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrackedPreferencesMigrationTest);
+};
+
+// static
+const char TrackedPreferencesMigrationTest::kSeed[] = "seed";
+
+// static
+const char TrackedPreferencesMigrationTest::kDeviceId[] = "device-id";
+
+} // namespace
+
+TEST_F(TrackedPreferencesMigrationTest, NoMigrationRequired) {
+ PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref,
+ kUnprotectedPrefValue);
+ PresetStoreValue(MOCK_PROTECTED_PREF_STORE, kProtectedPref,
+ kProtectedPrefValue);
+
+ EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
+
+ EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
+
+ // Hand unprotected prefs to the migrator which should wait for the protected
+ // prefs.
+ HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
+ EXPECT_FALSE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_FALSE(MigrationCompleted());
+
+ // Hand protected prefs to the migrator which should proceed with the
+ // migration synchronously.
+ HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
+ EXPECT_TRUE(MigrationCompleted());
+
+ // Prefs should have been handed back over.
+ EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_FALSE(
+ WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_FALSE(
+ WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_FALSE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_FALSE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE));
+
+ base::StringPairs expected_unprotected_values;
+ expected_unprotected_values.push_back(
+ std::make_pair(kUnprotectedPref, kUnprotectedPrefValue));
+ VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE, expected_unprotected_values);
+
+ base::StringPairs expected_protected_values;
+ expected_protected_values.push_back(
+ std::make_pair(kProtectedPref, kProtectedPrefValue));
+ VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
+
+ EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
+
+ EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
+}
+
+TEST_F(TrackedPreferencesMigrationTest, FullMigration) {
+ PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref,
+ kUnprotectedPrefValue);
+ PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref,
+ kPreviouslyUnprotectedPrefValue);
+ PresetStoreValue(MOCK_PROTECTED_PREF_STORE, kProtectedPref,
+ kProtectedPrefValue);
+ PresetStoreValue(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref,
+ kPreviouslyProtectedPrefValue);
+
+ EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
+ EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_FALSE(
+ ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
+
+ EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_FALSE(
+ ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
+ EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
+
+ HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
+ EXPECT_FALSE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_FALSE(MigrationCompleted());
+
+ HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
+ EXPECT_TRUE(MigrationCompleted());
+
+ EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_TRUE(
+ WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(
+ WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_TRUE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE));
+
+ // Values should have been migrated to their store, but migrated values should
+ // still remain in the source store until cleanup tasks are later invoked.
+ {
+ base::StringPairs expected_unprotected_values;
+ expected_unprotected_values.push_back(
+ std::make_pair(kUnprotectedPref, kUnprotectedPrefValue));
+ expected_unprotected_values.push_back(std::make_pair(
+ kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
+ expected_unprotected_values.push_back(std::make_pair(
+ kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
+ VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE,
+ expected_unprotected_values);
+
+ base::StringPairs expected_protected_values;
+ expected_protected_values.push_back(
+ std::make_pair(kProtectedPref, kProtectedPrefValue));
+ expected_protected_values.push_back(std::make_pair(
+ kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
+ expected_unprotected_values.push_back(std::make_pair(
+ kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
+ VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
+
+ EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
+ EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
+
+ EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
+ EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
+ }
+
+ // A successful write of the protected pref store should result in a clean up
+ // of the unprotected store.
+ SimulateSuccessfulWrite(MOCK_PROTECTED_PREF_STORE);
+
+ {
+ base::StringPairs expected_unprotected_values;
+ expected_unprotected_values.push_back(
+ std::make_pair(kUnprotectedPref, kUnprotectedPrefValue));
+ expected_unprotected_values.push_back(std::make_pair(
+ kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
+ VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE,
+ expected_unprotected_values);
+
+ base::StringPairs expected_protected_values;
+ expected_protected_values.push_back(
+ std::make_pair(kProtectedPref, kProtectedPrefValue));
+ expected_protected_values.push_back(std::make_pair(
+ kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
+ expected_unprotected_values.push_back(std::make_pair(
+ kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
+ VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
+ }
+
+ SimulateSuccessfulWrite(MOCK_UNPROTECTED_PREF_STORE);
+
+ {
+ base::StringPairs expected_unprotected_values;
+ expected_unprotected_values.push_back(
+ std::make_pair(kUnprotectedPref, kUnprotectedPrefValue));
+ expected_unprotected_values.push_back(std::make_pair(
+ kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
+ VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE,
+ expected_unprotected_values);
+
+ base::StringPairs expected_protected_values;
+ expected_protected_values.push_back(
+ std::make_pair(kProtectedPref, kProtectedPrefValue));
+ expected_protected_values.push_back(std::make_pair(
+ kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
+ VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
+ }
+
+ // Hashes are not cleaned up yet.
+ EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
+ EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
+
+ EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
+ EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
+
+ Reset();
+
+ HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
+ HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
+ EXPECT_TRUE(MigrationCompleted());
+
+ // Hashes are cleaned up.
+ EXPECT_TRUE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_FALSE(
+ ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
+ EXPECT_FALSE(ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref));
+
+ EXPECT_FALSE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kUnprotectedPref));
+ EXPECT_TRUE(
+ ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref));
+ EXPECT_TRUE(ContainsHash(MOCK_PROTECTED_PREF_STORE, kProtectedPref));
+ EXPECT_FALSE(
+ ContainsHash(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref));
+}
+
+TEST_F(TrackedPreferencesMigrationTest, CleanupOnly) {
+ // Already migrated; only cleanup needed.
+ PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE, kUnprotectedPref,
+ kUnprotectedPrefValue);
+ PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyProtectedPref,
+ kPreviouslyProtectedPrefValue);
+ PresetStoreValue(MOCK_UNPROTECTED_PREF_STORE, kPreviouslyUnprotectedPref,
+ kPreviouslyUnprotectedPrefValue);
+ PresetStoreValue(MOCK_PROTECTED_PREF_STORE, kProtectedPref,
+ kProtectedPrefValue);
+ PresetStoreValue(MOCK_PROTECTED_PREF_STORE, kPreviouslyProtectedPref,
+ kPreviouslyProtectedPrefValue);
+ PresetStoreValue(MOCK_PROTECTED_PREF_STORE, kPreviouslyUnprotectedPref,
+ kPreviouslyUnprotectedPrefValue);
+
+ HandPrefsToMigrator(MOCK_UNPROTECTED_PREF_STORE);
+ EXPECT_FALSE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_FALSE(MigrationCompleted());
+
+ HandPrefsToMigrator(MOCK_PROTECTED_PREF_STORE);
+ EXPECT_TRUE(MigrationCompleted());
+
+ EXPECT_TRUE(HasPrefs(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_TRUE(HasPrefs(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_FALSE(
+ WasOnSuccessfulWriteCallbackRegistered(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_FALSE(
+ WasOnSuccessfulWriteCallbackRegistered(MOCK_PROTECTED_PREF_STORE));
+ EXPECT_FALSE(StoreModifiedByMigration(MOCK_UNPROTECTED_PREF_STORE));
+ EXPECT_FALSE(StoreModifiedByMigration(MOCK_PROTECTED_PREF_STORE));
+
+ // Cleanup should happen synchronously if the values were already present in
+ // their destination stores.
+ {
+ base::StringPairs expected_unprotected_values;
+ expected_unprotected_values.push_back(
+ std::make_pair(kUnprotectedPref, kUnprotectedPrefValue));
+ expected_unprotected_values.push_back(std::make_pair(
+ kPreviouslyProtectedPref, kPreviouslyProtectedPrefValue));
+ VerifyValuesStored(MOCK_UNPROTECTED_PREF_STORE,
+ expected_unprotected_values);
+
+ base::StringPairs expected_protected_values;
+ expected_protected_values.push_back(
+ std::make_pair(kProtectedPref, kProtectedPrefValue));
+ expected_protected_values.push_back(std::make_pair(
+ kPreviouslyUnprotectedPref, kPreviouslyUnprotectedPrefValue));
+ VerifyValuesStored(MOCK_PROTECTED_PREF_STORE, expected_protected_values);
+ }
+}
diff --git a/chromium/services/preferences/tracked/tracked_split_preference.cc b/chromium/services/preferences/tracked/tracked_split_preference.cc
new file mode 100644
index 00000000000..da6ceba8fbf
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_split_preference.cc
@@ -0,0 +1,120 @@
+// 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/preferences/tracked/tracked_split_preference.h"
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/values.h"
+#include "services/preferences/public/interfaces/tracked_preference_validation_delegate.mojom.h"
+#include "services/preferences/tracked/pref_hash_store_transaction.h"
+
+using ValueState =
+ prefs::mojom::TrackedPreferenceValidationDelegate::ValueState;
+
+TrackedSplitPreference::TrackedSplitPreference(
+ const std::string& pref_path,
+ size_t reporting_id,
+ size_t reporting_ids_count,
+ prefs::mojom::TrackedPreferenceMetadata::EnforcementLevel enforcement_level,
+ prefs::mojom::TrackedPreferenceMetadata::ValueType value_type,
+ prefs::mojom::TrackedPreferenceValidationDelegate* delegate)
+ : pref_path_(pref_path),
+ helper_(pref_path,
+ reporting_id,
+ reporting_ids_count,
+ enforcement_level,
+ value_type),
+ delegate_(delegate) {}
+
+TrackedPreferenceType TrackedSplitPreference::GetType() const {
+ return TrackedPreferenceType::SPLIT;
+}
+
+void TrackedSplitPreference::OnNewValue(
+ const base::Value* value,
+ PrefHashStoreTransaction* transaction) const {
+ const base::DictionaryValue* dict_value = NULL;
+ if (value && !value->GetAsDictionary(&dict_value)) {
+ NOTREACHED();
+ return;
+ }
+ transaction->StoreSplitHash(pref_path_, dict_value);
+}
+
+bool TrackedSplitPreference::EnforceAndReport(
+ base::DictionaryValue* pref_store_contents,
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const {
+ base::DictionaryValue* dict_value = NULL;
+ if (!pref_store_contents->GetDictionary(pref_path_, &dict_value) &&
+ pref_store_contents->Get(pref_path_, NULL)) {
+ // There should be a dictionary or nothing at |pref_path_|.
+ NOTREACHED();
+ return false;
+ }
+
+ std::vector<std::string> invalid_keys;
+ ValueState value_state =
+ transaction->CheckSplitValue(pref_path_, dict_value, &invalid_keys);
+
+ if (value_state == ValueState::CHANGED)
+ helper_.ReportSplitPreferenceChangedCount(invalid_keys.size());
+
+ helper_.ReportValidationResult(value_state, transaction->GetStoreUMASuffix());
+
+ ValueState external_validation_value_state = ValueState::UNSUPPORTED;
+ std::vector<std::string> external_validation_invalid_keys;
+ if (external_validation_transaction) {
+ external_validation_value_state =
+ external_validation_transaction->CheckSplitValue(
+ pref_path_, dict_value, &external_validation_invalid_keys);
+ helper_.ReportValidationResult(
+ external_validation_value_state,
+ external_validation_transaction->GetStoreUMASuffix());
+ }
+
+ if (delegate_) {
+ delegate_->OnSplitPreferenceValidation(
+ pref_path_, invalid_keys, external_validation_invalid_keys, value_state,
+ external_validation_value_state, helper_.IsPersonal());
+ }
+ TrackedPreferenceHelper::ResetAction reset_action =
+ helper_.GetAction(value_state);
+ helper_.ReportAction(reset_action);
+
+ bool was_reset = false;
+ if (reset_action == TrackedPreferenceHelper::DO_RESET) {
+ if (value_state == ValueState::CHANGED) {
+ DCHECK(!invalid_keys.empty());
+
+ for (std::vector<std::string>::const_iterator it = invalid_keys.begin();
+ it != invalid_keys.end(); ++it) {
+ dict_value->Remove(*it, NULL);
+ }
+ } else {
+ pref_store_contents->RemovePath(pref_path_, NULL);
+ }
+ was_reset = true;
+ }
+
+ if (value_state != ValueState::UNCHANGED) {
+ // Store the hash for the new value (whether it was reset or not).
+ const base::DictionaryValue* new_dict_value = NULL;
+ pref_store_contents->GetDictionary(pref_path_, &new_dict_value);
+ transaction->StoreSplitHash(pref_path_, new_dict_value);
+ }
+
+ // Update MACs in the external store if there is one and there either was a
+ // reset or external validation failed.
+ if (external_validation_transaction &&
+ (was_reset || external_validation_value_state != ValueState::UNCHANGED)) {
+ const base::DictionaryValue* new_dict_value = nullptr;
+ pref_store_contents->GetDictionary(pref_path_, &new_dict_value);
+ external_validation_transaction->StoreSplitHash(pref_path_, new_dict_value);
+ }
+
+ return was_reset;
+}
diff --git a/chromium/services/preferences/tracked/tracked_split_preference.h b/chromium/services/preferences/tracked/tracked_split_preference.h
new file mode 100644
index 00000000000..f416b3695fa
--- /dev/null
+++ b/chromium/services/preferences/tracked/tracked_split_preference.h
@@ -0,0 +1,58 @@
+// 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_PREFERENCES_TRACKED_TRACKED_SPLIT_PREFERENCE_H_
+#define SERVICES_PREFERENCES_TRACKED_TRACKED_SPLIT_PREFERENCE_H_
+
+#include <stddef.h>
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "services/preferences/tracked/pref_hash_filter.h"
+#include "services/preferences/tracked/tracked_preference.h"
+#include "services/preferences/tracked/tracked_preference_helper.h"
+
+namespace prefs {
+namespace mojom {
+class TrackedPreferenceValidationDelegate;
+}
+}
+
+// A TrackedSplitPreference must be tracking a dictionary pref. Each top-level
+// entry in its dictionary is tracked and enforced independently. An optional
+// delegate is notified of the status of the preference during enforcement.
+// Note: preferences using this strategy must be kept in sync with
+// TrackedSplitPreferences in histograms.xml.
+class TrackedSplitPreference : public TrackedPreference {
+ public:
+ // Constructs a TrackedSplitPreference. |pref_path| must be a dictionary pref.
+ TrackedSplitPreference(
+ const std::string& pref_path,
+ size_t reporting_id,
+ size_t reporting_ids_count,
+ prefs::mojom::TrackedPreferenceMetadata::EnforcementLevel
+ enforcement_level,
+ prefs::mojom::TrackedPreferenceMetadata::ValueType value_type,
+ prefs::mojom::TrackedPreferenceValidationDelegate* delegate);
+
+ // TrackedPreference implementation.
+ TrackedPreferenceType GetType() const override;
+ void OnNewValue(const base::Value* value,
+ PrefHashStoreTransaction* transaction) const override;
+ bool EnforceAndReport(
+ base::DictionaryValue* pref_store_contents,
+ PrefHashStoreTransaction* transaction,
+ PrefHashStoreTransaction* external_validation_transaction) const override;
+
+ private:
+ const std::string pref_path_;
+ const TrackedPreferenceHelper helper_;
+ prefs::mojom::TrackedPreferenceValidationDelegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(TrackedSplitPreference);
+};
+
+#endif // SERVICES_PREFERENCES_TRACKED_TRACKED_SPLIT_PREFERENCE_H_
diff --git a/chromium/services/preferences/unittest_manifest.json b/chromium/services/preferences/unittest_manifest.json
new file mode 100644
index 00000000000..df6d7441066
--- /dev/null
+++ b/chromium/services/preferences/unittest_manifest.json
@@ -0,0 +1,16 @@
+{
+ "name": "prefs_unittests",
+ "display_name": "Prefs Unittests",
+ "interface_provider_specs": {
+ "service_manager:connector": {
+ "provides": {
+ "service_manager:service_factory": [
+ "service_manager::mojom::ServiceFactory"
+ ]
+ },
+ "requires": {
+ "preferences": [ "pref_client", "pref_control" ]
+ }
+ }
+ }
+}
diff --git a/chromium/services/resource_coordinator/BUILD.gn b/chromium/services/resource_coordinator/BUILD.gn
index 9c5f07ef5f1..bfa2df622f0 100644
--- a/chromium/services/resource_coordinator/BUILD.gn
+++ b/chromium/services/resource_coordinator/BUILD.gn
@@ -2,6 +2,9 @@
# 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 memory instrumentaiton coordinator. It is currently
+# in the browser process. So, only //content/browser should link to this target.
+# Others modules should only need the public targets.
source_set("lib") {
sources = [
"memory/coordinator/coordinator_impl.cc",
@@ -10,6 +13,7 @@ source_set("lib") {
public_deps = [
"//base",
+ "//mojo/public/cpp/bindings",
"//services/resource_coordinator/public/cpp",
"//services/resource_coordinator/public/interfaces",
]
@@ -20,12 +24,15 @@ source_set("tests") {
sources = [
"memory/coordinator/coordinator_impl_unittest.cc",
+ "public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc",
]
deps = [
":lib",
"//base",
"//mojo/public/cpp/bindings",
+ "//services/resource_coordinator/public/cpp",
+ "//services/resource_coordinator/public/interfaces",
"//testing/gtest",
]
}
diff --git a/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.cc b/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.cc
index 5c133f803c4..3f65716f9ae 100644
--- a/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.cc
+++ b/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.cc
@@ -4,40 +4,53 @@
#include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
+#include "base/bind.h"
#include "base/bind_helpers.h"
-#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/single_thread_task_runner.h"
+#include "base/threading/platform_thread.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_dump_request_args.h"
+#include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h"
+#include "services/resource_coordinator/public/interfaces/memory/constants.mojom.h"
#include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
-namespace memory_instrumentation {
-
namespace {
-base::LazyInstance<CoordinatorImpl>::Leaky g_coordinator =
- LAZY_INSTANCE_INITIALIZER;
+memory_instrumentation::CoordinatorImpl* g_coordinator_impl;
} // namespace
+namespace memory_instrumentation {
+
// static
CoordinatorImpl* CoordinatorImpl::GetInstance() {
- return g_coordinator.Pointer();
+ return g_coordinator_impl;
}
-// TODO(chiniforooshan): Initialize the global MemoryDumpManager instance here.
-// This is how the global MemoryDumpManager gets a reference to the delegate on
-// the service (read the browser) process for service process memory dumps. This
-// can be done when the delegate implementation is landed.
-CoordinatorImpl::CoordinatorImpl() : failed_memory_dump_count_(0) {}
+CoordinatorImpl::CoordinatorImpl(bool initialize_memory_dump_manager)
+ : failed_memory_dump_count_(0),
+ initialize_memory_dump_manager_(initialize_memory_dump_manager) {
+ if (initialize_memory_dump_manager) {
+ MemoryDumpManagerDelegateImpl::Config config(this);
+ auto delegate = base::MakeUnique<MemoryDumpManagerDelegateImpl>(config);
+ base::trace_event::MemoryDumpManager::GetInstance()->set_tracing_process_id(
+ mojom::kServiceTracingProcessId);
+ base::trace_event::MemoryDumpManager::GetInstance()->Initialize(
+ std::move(delegate));
+ }
+ g_coordinator_impl = this;
+}
-CoordinatorImpl::~CoordinatorImpl() {}
+CoordinatorImpl::~CoordinatorImpl() {
+ g_coordinator_impl = nullptr;
+}
void CoordinatorImpl::BindCoordinatorRequest(
mojom::CoordinatorRequest request) {
+ DCHECK(thread_checker_.CalledOnValidThread());
bindings_.AddBinding(this, std::move(request));
}
@@ -52,14 +65,14 @@ void CoordinatorImpl::RequestGlobalMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
const RequestGlobalMemoryDumpCallback& callback) {
DCHECK(thread_checker_.CalledOnValidThread());
-
bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty();
- // If this is a periodic memory dump request and there already is another
- // request in the queue with the same level of detail, there's no point in
- // enqueuing this request.
+ // If this is a periodic or peak memory dump request and there already is
+ // another request in the queue with the same level of detail, there's no
+ // point in enqueuing this request.
if (another_dump_already_in_progress &&
- args.dump_type == base::trace_event::MemoryDumpType::PERIODIC_INTERVAL) {
+ args.dump_type !=
+ base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED) {
for (const auto& request : queued_memory_dump_requests_) {
if (request.args.level_of_detail == args.level_of_detail) {
VLOG(1) << base::trace_event::MemoryDumpManager::kLogPrefix << " ("
@@ -88,7 +101,6 @@ void CoordinatorImpl::RequestGlobalMemoryDump(
void CoordinatorImpl::RegisterProcessLocalDumpManager(
mojom::ProcessLocalDumpManagerPtr process_manager) {
DCHECK(thread_checker_.CalledOnValidThread());
-
process_manager.set_connection_error_handler(
base::Bind(&CoordinatorImpl::UnregisterProcessLocalDumpManager,
base::Unretained(this), process_manager.get()));
@@ -101,7 +113,8 @@ void CoordinatorImpl::RegisterProcessLocalDumpManager(
void CoordinatorImpl::UnregisterProcessLocalDumpManager(
mojom::ProcessLocalDumpManager* process_manager) {
- DCHECK(process_managers_.erase(process_manager) == 1);
+ size_t num_deleted = process_managers_.erase(process_manager);
+ DCHECK(num_deleted == 1);
// Check if we are waiting for an ack from this process-local manager.
if (pending_process_managers_.find(process_manager) !=
@@ -109,7 +122,8 @@ void CoordinatorImpl::UnregisterProcessLocalDumpManager(
DCHECK(!queued_memory_dump_requests_.empty());
OnProcessMemoryDumpResponse(
process_manager, queued_memory_dump_requests_.front().args.dump_guid,
- false /* success */);
+ false /* success */,
+ base::Optional<base::trace_event::MemoryDumpCallbackResult>());
}
}
@@ -125,9 +139,9 @@ void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() {
failed_memory_dump_count_ = 0;
for (const auto& key_value : process_managers_) {
pending_process_managers_.insert(key_value.first);
- key_value.second->RequestProcessMemoryDump(
- args, base::Bind(&CoordinatorImpl::OnProcessMemoryDumpResponse,
- base::Unretained(this), key_value.first));
+ auto callback = base::Bind(&CoordinatorImpl::OnProcessMemoryDumpResponse,
+ base::Unretained(this), key_value.first);
+ key_value.second->RequestProcessMemoryDump(args, callback);
}
// Run the callback in case there are no process-local managers.
FinalizeGlobalMemoryDumpIfAllManagersReplied();
@@ -136,7 +150,8 @@ void CoordinatorImpl::PerformNextQueuedGlobalMemoryDump() {
void CoordinatorImpl::OnProcessMemoryDumpResponse(
mojom::ProcessLocalDumpManager* process_manager,
uint64_t dump_guid,
- bool success) {
+ bool success,
+ const base::Optional<base::trace_event::MemoryDumpCallbackResult>& result) {
auto it = pending_process_managers_.find(process_manager);
DCHECK(!queued_memory_dump_requests_.empty());
diff --git a/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.h b/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.h
index 80ce6aee23e..8281c41204b 100644
--- a/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.h
+++ b/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl.h
@@ -9,7 +9,6 @@
#include <set>
#include <unordered_map>
-#include "base/lazy_instance.h"
#include "base/memory/ref_counted.h"
#include "base/threading/thread_checker.h"
#include "base/trace_event/memory_dump_request_args.h"
@@ -22,14 +21,21 @@ namespace memory_instrumentation {
class CoordinatorImpl : public Coordinator, public mojom::Coordinator {
public:
+ // The getter of the unique instance.
static CoordinatorImpl* GetInstance();
+ explicit CoordinatorImpl(bool initialize_memory_dump_manager);
+
// Coordinator
void BindCoordinatorRequest(mojom::CoordinatorRequest) override;
+ bool initialize_memory_dump_manager() const {
+ return initialize_memory_dump_manager_;
+ }
+
private:
- friend class CoordinatorImplTest; // For testing
- friend struct base::DefaultLazyInstanceTraits<CoordinatorImpl>;
+ friend std::default_delete<CoordinatorImpl>; // For testing
+ friend class CoordinatorImplTest; // For testing
struct QueuedMemoryDumpRequest {
QueuedMemoryDumpRequest(const base::trace_event::MemoryDumpRequestArgs args,
@@ -39,7 +45,6 @@ class CoordinatorImpl : public Coordinator, public mojom::Coordinator {
const RequestGlobalMemoryDumpCallback callback;
};
- CoordinatorImpl();
~CoordinatorImpl() override;
// mojom::Coordinator
@@ -61,7 +66,9 @@ class CoordinatorImpl : public Coordinator, public mojom::Coordinator {
void OnProcessMemoryDumpResponse(
mojom::ProcessLocalDumpManager* process_manager,
uint64_t dump_guid,
- bool success);
+ bool success,
+ const base::Optional<base::trace_event::MemoryDumpCallbackResult>&
+ result);
void PerformNextQueuedGlobalMemoryDump();
void FinalizeGlobalMemoryDumpIfAllManagersReplied();
@@ -78,6 +85,8 @@ class CoordinatorImpl : public Coordinator, public mojom::Coordinator {
int failed_memory_dump_count_;
std::list<QueuedMemoryDumpRequest> queued_memory_dump_requests_;
+ const bool initialize_memory_dump_manager_;
+
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(CoordinatorImpl);
diff --git a/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc b/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc
index 1bc8254b902..521f8f205cf 100644
--- a/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc
+++ b/chromium/services/resource_coordinator/memory/coordinator/coordinator_impl_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "services/resource_coordinator/memory/coordinator/coordinator_impl.h"
+#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
@@ -20,14 +21,17 @@ class CoordinatorImplTest : public testing::Test {
public:
CoordinatorImplTest() {}
void SetUp() override {
- dump_response_args_ = {static_cast<uint64_t>(-1), false};
+ dump_response_args_ = {0U, false};
+ coordinator_.reset(new CoordinatorImpl(false));
}
+ void TearDown() override { coordinator_.reset(); }
+
void RegisterProcessLocalDumpManager(
mojom::ProcessLocalDumpManagerPtr process_manager) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&CoordinatorImpl::RegisterProcessLocalDumpManager,
- base::Unretained(&coordinator_),
+ base::Unretained(coordinator_.get()),
base::Passed(&process_manager)));
}
@@ -36,7 +40,7 @@ class CoordinatorImplTest : public testing::Test {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&CoordinatorImpl::RequestGlobalMemoryDump,
- base::Unretained(&coordinator_), args,
+ base::Unretained(coordinator_.get()), args,
base::Bind(&CoordinatorImplTest::OnGlobalMemoryDumpResponse,
base::Unretained(this), closure)));
}
@@ -57,11 +61,11 @@ class CoordinatorImplTest : public testing::Test {
DumpResponseArgs dump_response_args_;
private:
- CoordinatorImpl coordinator_;
+ std::unique_ptr<CoordinatorImpl> coordinator_;
base::MessageLoop message_loop_;
};
-class MockDumpManager : mojom::ProcessLocalDumpManager {
+class MockDumpManager : public mojom::ProcessLocalDumpManager {
public:
MockDumpManager(CoordinatorImplTest* test_coordinator, int expected_calls)
: binding_(this), expected_calls_(expected_calls) {
@@ -78,7 +82,8 @@ class MockDumpManager : mojom::ProcessLocalDumpManager {
const base::trace_event::MemoryDumpRequestArgs& args,
const RequestProcessMemoryDumpCallback& callback) override {
expected_calls_--;
- callback.Run(args.dump_guid, true);
+ base::trace_event::MemoryDumpCallbackResult result;
+ callback.Run(args.dump_guid, true, result);
}
private:
@@ -93,7 +98,7 @@ TEST_F(CoordinatorImplTest, NoProcessLocalManagers) {
base::trace_event::MemoryDumpLevelOfDetail::DETAILED};
RequestGlobalMemoryDump(args, run_loop.QuitClosure());
run_loop.Run();
- EXPECT_EQ(static_cast<uint64_t>(1234), dump_response_args_.dump_guid);
+ EXPECT_EQ(1234U, dump_response_args_.dump_guid);
EXPECT_TRUE(dump_response_args_.success);
}
@@ -109,7 +114,7 @@ TEST_F(CoordinatorImplTest, SeveralProcessLocalManagers) {
run_loop.Run();
- EXPECT_EQ(static_cast<uint64_t>(2345), dump_response_args_.dump_guid);
+ EXPECT_EQ(2345U, dump_response_args_.dump_guid);
EXPECT_TRUE(dump_response_args_.success);
}
@@ -132,7 +137,7 @@ TEST_F(CoordinatorImplTest, FaultyProcessLocalManager) {
run_loop.Run();
- EXPECT_EQ(static_cast<uint64_t>(3456), dump_response_args_.dump_guid);
+ EXPECT_EQ(3456U, dump_response_args_.dump_guid);
EXPECT_FALSE(dump_response_args_.success);
}
} // namespace memory_instrumentation
diff --git a/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc b/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc
index 7072b677548..1129bae1d11 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.cc
@@ -4,26 +4,34 @@
#include "services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "services/resource_coordinator/public/cpp/memory/coordinator.h"
#include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "services/service_manager/public/cpp/connector.h"
namespace memory_instrumentation {
-MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl(
- service_manager::InterfaceProvider* interface_provider)
- : is_coordinator_(false), binding_(this) {
- interface_provider->GetInterface(mojo::MakeRequest(&coordinator_));
- coordinator_->RegisterProcessLocalDumpManager(
- binding_.CreateInterfacePtrAndBind());
-}
+MemoryDumpManagerDelegateImpl::Config::~Config() {}
MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl(
- Coordinator* coordinator)
- : is_coordinator_(true), binding_(this) {
- coordinator->BindCoordinatorRequest(mojo::MakeRequest(&coordinator_));
+ const MemoryDumpManagerDelegateImpl::Config& config)
+ : binding_(this),
+ config_(config),
+ task_runner_(nullptr),
+ pending_memory_dump_guid_(0) {
+ if (config.connector() != nullptr) {
+ config.connector()->BindInterface(config.service_name(),
+ mojo::MakeRequest(&coordinator_));
+ } else {
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ config.coordinator()->BindCoordinatorRequest(
+ mojo::MakeRequest(&coordinator_));
+ }
coordinator_->RegisterProcessLocalDumpManager(
binding_.CreateInterfacePtrAndBind());
}
@@ -31,7 +39,7 @@ MemoryDumpManagerDelegateImpl::MemoryDumpManagerDelegateImpl(
MemoryDumpManagerDelegateImpl::~MemoryDumpManagerDelegateImpl() {}
bool MemoryDumpManagerDelegateImpl::IsCoordinator() const {
- return is_coordinator_;
+ return task_runner_ != nullptr;
}
void MemoryDumpManagerDelegateImpl::RequestProcessMemoryDump(
@@ -42,8 +50,47 @@ void MemoryDumpManagerDelegateImpl::RequestProcessMemoryDump(
void MemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
- const base::trace_event::MemoryDumpCallback& callback) {
- coordinator_->RequestGlobalMemoryDump(args, callback);
+ const base::trace_event::GlobalMemoryDumpCallback& callback) {
+ // Note: This condition is here to match the old behavior. If the delegate is
+ // in the browser process, we do not drop parallel requests in the delegate
+ // and so they will be queued by the Coordinator service (see
+ // CoordinatorImpl::RequestGlobalMemoryDump). If the delegate is in a child
+ // process, parallel requests will be cancelled.
+ //
+ // TODO(chiniforooshan): Unify the child and browser behavior.
+ if (IsCoordinator()) {
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&mojom::Coordinator::RequestGlobalMemoryDump,
+ base::Unretained(coordinator_.get()), args, callback));
+ return;
+ }
+
+ {
+ base::AutoLock lock(pending_memory_dump_guid_lock_);
+ if (pending_memory_dump_guid_) {
+ callback.Run(args.dump_guid, false);
+ return;
+ }
+ pending_memory_dump_guid_ = args.dump_guid;
+ }
+ auto callback_proxy =
+ base::Bind(&MemoryDumpManagerDelegateImpl::MemoryDumpCallbackProxy,
+ base::Unretained(this), callback);
+ coordinator_->RequestGlobalMemoryDump(args, callback_proxy);
+}
+
+void MemoryDumpManagerDelegateImpl::MemoryDumpCallbackProxy(
+ const base::trace_event::GlobalMemoryDumpCallback& callback,
+ uint64_t dump_guid,
+ bool success) {
+ DCHECK_NE(0U, pending_memory_dump_guid_);
+ pending_memory_dump_guid_ = 0;
+ callback.Run(dump_guid, success);
+}
+
+void MemoryDumpManagerDelegateImpl::SetAsNonCoordinatorForTesting() {
+ task_runner_ = nullptr;
}
} // namespace memory_instrumentation
diff --git a/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h b/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h
index 11766199736..ccff7191f6c 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h
@@ -5,43 +5,92 @@
#ifndef SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
#define SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_DUMP_MANAGER_DELEGATE_IMPL_H_
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/resource_coordinator/public/cpp/memory/coordinator.h"
#include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
+#include "services/service_manager/public/cpp/connector.h"
namespace memory_instrumentation {
+// This is the bridge between MemoryDumpManager and the Coordinator service.
+// This indirection is needed to avoid a dependency from //base, where
+// MemoryDumpManager lives, to //services, where the Coordinator service lives.
+//
+// This cannot just be implemented by the Coordinator service, because there is
+// no Coordinator service in child processes. So, in a child process, the
+// delegate remotely connects to the Coordinator service. In the browser
+// process, the delegate locally connects to the Coordinator service.
class MemoryDumpManagerDelegateImpl
: public base::trace_event::MemoryDumpManagerDelegate,
public mojom::ProcessLocalDumpManager {
public:
- // Use to bind to a remote coordinator.
- MemoryDumpManagerDelegateImpl(
- service_manager::InterfaceProvider* interface_provider);
+ class Config {
+ public:
+ Config(service_manager::Connector* connector,
+ const std::string& service_name)
+ : connector_(connector),
+ service_name_(service_name),
+ coordinator_(nullptr) {}
+ Config(Coordinator* coordinator)
+ : connector_(nullptr), coordinator_(coordinator) {}
+ ~Config();
- // Use to bind to a coordinator in the same process.
- MemoryDumpManagerDelegateImpl(Coordinator* coordinator);
+ service_manager::Connector* connector() const { return connector_; }
+
+ const std::string& service_name() const { return service_name_; }
+
+ Coordinator* coordinator() const { return coordinator_; }
+
+ private:
+ service_manager::Connector* connector_;
+ const std::string service_name_;
+ Coordinator* coordinator_;
+ bool is_test_config_;
+ };
+
+ explicit MemoryDumpManagerDelegateImpl(const Config& config);
~MemoryDumpManagerDelegateImpl() override;
- bool IsCoordinator() const;
+ bool IsCoordinator() const override;
// The base::trace_event::MemoryDumpManager calls this.
void RequestGlobalMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
- const base::trace_event::MemoryDumpCallback& callback) override;
+ const base::trace_event::GlobalMemoryDumpCallback& callback) override;
+
+ Config config() { return config_; }
+ void SetAsNonCoordinatorForTesting();
private:
+ friend std::default_delete<MemoryDumpManagerDelegateImpl>; // For testing
+ friend class MemoryDumpManagerDelegateImplTest; // For testing
+
// The ProcessLocalDumpManager interface. The coordinator calls this.
void RequestProcessMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
const RequestProcessMemoryDumpCallback& callback) override;
- bool is_coordinator_;
+ // A proxy callback for updating |pending_memory_dump_guid_|.
+ void MemoryDumpCallbackProxy(
+ const base::trace_event::GlobalMemoryDumpCallback& callback,
+ uint64_t dump_guid,
+ bool success);
+
mojom::CoordinatorPtr coordinator_;
mojo::Binding<mojom::ProcessLocalDumpManager> binding_;
+ const Config config_;
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+ uint64_t pending_memory_dump_guid_;
+
+ // Prevents racy access to |pending_memory_dump_guid_|.
+ base::Lock pending_memory_dump_guid_lock_;
+
+ // Prevents racy access to |initialized_|.
+ base::Lock initialized_lock_;
DISALLOW_COPY_AND_ASSIGN(MemoryDumpManagerDelegateImpl);
};
diff --git a/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc b/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc
new file mode 100644
index 00000000000..a0fcd2daec3
--- /dev/null
+++ b/chromium/services/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl_unittest.cc
@@ -0,0 +1,135 @@
+// 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/resource_coordinator/public/cpp/memory/memory_dump_manager_delegate_impl.h"
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_request_args.h"
+#include "base/trace_event/trace_config.h"
+#include "base/trace_event/trace_log.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/resource_coordinator/public/cpp/memory/coordinator.h"
+#include "services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using base::trace_event::MemoryDumpLevelOfDetail;
+using base::trace_event::MemoryDumpManager;
+using base::trace_event::MemoryDumpType;
+
+namespace memory_instrumentation {
+
+class MockCoordinator : public Coordinator, public mojom::Coordinator {
+ public:
+ void BindCoordinatorRequest(mojom::CoordinatorRequest request) override {
+ bindings_.AddBinding(this, std::move(request));
+ }
+
+ void RegisterProcessLocalDumpManager(
+ mojom::ProcessLocalDumpManagerPtr process_manager) override {}
+
+ void RequestGlobalMemoryDump(
+ const base::trace_event::MemoryDumpRequestArgs& args,
+ const RequestGlobalMemoryDumpCallback& callback) override {
+ callback.Run(args.dump_guid, true);
+ }
+
+ private:
+ mojo::BindingSet<mojom::Coordinator> bindings_;
+};
+
+class MemoryDumpManagerDelegateImplTest : public testing::Test {
+ public:
+ void SetUp() override {
+ message_loop_.reset(new base::MessageLoop());
+ coordinator_.reset(new MockCoordinator());
+ mdm_.reset(new MemoryDumpManager());
+ MemoryDumpManager::SetInstanceForTesting(mdm_.get());
+ MemoryDumpManagerDelegateImpl::Config config(coordinator_.get());
+ auto delegate = base::MakeUnique<MemoryDumpManagerDelegateImpl>(config);
+ delegate->SetAsNonCoordinatorForTesting();
+ mdm_->Initialize(std::move(delegate));
+
+ // Enable tracing.
+ std::string category_filter = "-*,";
+ category_filter += MemoryDumpManager::kTraceCategory;
+ base::trace_event::TraceConfig trace_config(category_filter, "");
+ base::trace_event::TraceLog::GetInstance()->SetEnabled(
+ trace_config, base::trace_event::TraceLog::RECORDING_MODE);
+
+ // Reset the counters.
+ expected_callback_calls_ = 0;
+ dump_requests_received_by_coordinator_ = 0;
+ quit_closure_.Reset();
+ }
+
+ void TearDown() override {
+ base::trace_event::TraceLog::GetInstance()->SetDisabled();
+ MemoryDumpManager::SetInstanceForTesting(nullptr);
+ mdm_.reset();
+ coordinator_.reset();
+ message_loop_.reset();
+ }
+
+ void OnGlobalMemoryDumpDone(int more_requests,
+ uint64_t dump_guid,
+ bool success) {
+ EXPECT_GT(expected_callback_calls_, 0);
+ EXPECT_FALSE(quit_closure_.is_null());
+
+ dump_requests_received_by_coordinator_ += success ? 1 : 0;
+ expected_callback_calls_--;
+ if (expected_callback_calls_ == 0)
+ quit_closure_.Run();
+
+ if (more_requests > 0)
+ SequentiallyRequestGlobalDumps(more_requests);
+ }
+
+ void SequentiallyRequestGlobalDumps(int num_requests) {
+ MemoryDumpManager::GetInstance()->RequestGlobalDump(
+ MemoryDumpType::EXPLICITLY_TRIGGERED, MemoryDumpLevelOfDetail::LIGHT,
+ base::Bind(&MemoryDumpManagerDelegateImplTest::OnGlobalMemoryDumpDone,
+ base::Unretained(this), num_requests - 1));
+ }
+
+ int expected_callback_calls_;
+ int dump_requests_received_by_coordinator_;
+ base::Closure quit_closure_;
+
+ private:
+ std::unique_ptr<base::MessageLoop> message_loop_;
+ std::unique_ptr<MockCoordinator> coordinator_;
+ std::unique_ptr<MemoryDumpManager> mdm_;
+};
+
+// Makes several global dump requests each after receiving the ACK for the
+// previous one. There should be no throttling and all requests should be
+// forwarded to the coordinator.
+TEST_F(MemoryDumpManagerDelegateImplTest, NonOverlappingMemoryDumpRequests) {
+ base::RunLoop run_loop;
+ expected_callback_calls_ = 3;
+ quit_closure_ = run_loop.QuitClosure();
+ SequentiallyRequestGlobalDumps(3);
+ run_loop.Run();
+ EXPECT_EQ(3, dump_requests_received_by_coordinator_);
+}
+
+// Makes several global dump requests without waiting for previous requests to
+// finish. Only the first request should make it to the coordinator. The rest
+// should be cancelled.
+TEST_F(MemoryDumpManagerDelegateImplTest, OverlappingMemoryDumpRequests) {
+ base::RunLoop run_loop;
+ expected_callback_calls_ = 3;
+ quit_closure_ = run_loop.QuitClosure();
+ SequentiallyRequestGlobalDumps(1);
+ SequentiallyRequestGlobalDumps(1);
+ SequentiallyRequestGlobalDumps(1);
+ run_loop.Run();
+ EXPECT_EQ(1, dump_requests_received_by_coordinator_);
+}
+
+} // namespace memory_instrumentation
diff --git a/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation.typemap b/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation.typemap
index 7dd28cf8827..32a2e41d640 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation.typemap
+++ b/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation.typemap
@@ -13,4 +13,7 @@ type_mappings = [
"memory_instrumentation.mojom.DumpType=base::trace_event::MemoryDumpType",
"memory_instrumentation.mojom.LevelOfDetail=base::trace_event::MemoryDumpLevelOfDetail",
"memory_instrumentation.mojom.RequestArgs=base::trace_event::MemoryDumpRequestArgs",
+ "memory_instrumentation.mojom.ChromeMemDump=base::trace_event::MemoryDumpCallbackResult::ChromeMemDump",
+ "memory_instrumentation.mojom.OSMemDump=base::trace_event::MemoryDumpCallbackResult::OSMemDump",
+ "memory_instrumentation.mojom.MemoryDumpCallbackResult=base::trace_event::MemoryDumpCallbackResult",
]
diff --git a/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.cc b/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.cc
index c1ad69010d8..7bb49b68f42 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.cc
+++ b/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.cc
@@ -104,4 +104,38 @@ bool StructTraits<memory_instrumentation::mojom::RequestArgsDataView,
return true;
}
+// static
+bool StructTraits<memory_instrumentation::mojom::ChromeMemDumpDataView,
+ base::trace_event::MemoryDumpCallbackResult::ChromeMemDump>::
+ Read(memory_instrumentation::mojom::ChromeMemDumpDataView input,
+ base::trace_event::MemoryDumpCallbackResult::ChromeMemDump* out) {
+ out->malloc_total_kb = input.malloc_total_kb();
+ out->partition_alloc_total_kb = input.partition_alloc_total_kb();
+ out->blink_gc_total_kb = input.blink_gc_total_kb();
+ out->v8_total_kb = input.v8_total_kb();
+ return true;
+}
+
+// static
+bool StructTraits<memory_instrumentation::mojom::OSMemDumpDataView,
+ base::trace_event::MemoryDumpCallbackResult::OSMemDump>::
+ Read(memory_instrumentation::mojom::OSMemDumpDataView input,
+ base::trace_event::MemoryDumpCallbackResult::OSMemDump* out) {
+ out->resident_set_kb = input.resident_set_kb();
+ return true;
+}
+
+// static
+bool StructTraits<
+ memory_instrumentation::mojom::MemoryDumpCallbackResultDataView,
+ base::trace_event::MemoryDumpCallbackResult>::
+ Read(memory_instrumentation::mojom::MemoryDumpCallbackResultDataView input,
+ base::trace_event::MemoryDumpCallbackResult* out) {
+ if (!input.ReadChromeDump(&out->chrome_dump))
+ return false;
+ if (!input.ReadOsDump(&out->os_dump))
+ return false;
+ return true;
+}
+
} // namespace mojo
diff --git a/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h b/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h
index c3b2761148f..c9c6770b783 100644
--- a/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h
+++ b/chromium/services/resource_coordinator/public/cpp/memory/memory_instrumentation_struct_traits.h
@@ -47,6 +47,59 @@ struct StructTraits<memory_instrumentation::mojom::RequestArgsDataView,
base::trace_event::MemoryDumpRequestArgs* out);
};
+template <>
+struct StructTraits<
+ memory_instrumentation::mojom::ChromeMemDumpDataView,
+ base::trace_event::MemoryDumpCallbackResult::ChromeMemDump> {
+ static uint32_t malloc_total_kb(
+ const base::trace_event::MemoryDumpCallbackResult::ChromeMemDump& args) {
+ return args.malloc_total_kb;
+ }
+ static uint32_t partition_alloc_total_kb(
+ const base::trace_event::MemoryDumpCallbackResult::ChromeMemDump& args) {
+ return args.partition_alloc_total_kb;
+ }
+ static uint32_t blink_gc_total_kb(
+ const base::trace_event::MemoryDumpCallbackResult::ChromeMemDump& args) {
+ return args.blink_gc_total_kb;
+ }
+ static uint32_t v8_total_kb(
+ const base::trace_event::MemoryDumpCallbackResult::ChromeMemDump& args) {
+ return args.v8_total_kb;
+ }
+ static bool Read(
+ memory_instrumentation::mojom::ChromeMemDumpDataView input,
+ base::trace_event::MemoryDumpCallbackResult::ChromeMemDump* out);
+};
+
+template <>
+struct StructTraits<memory_instrumentation::mojom::OSMemDumpDataView,
+ base::trace_event::MemoryDumpCallbackResult::OSMemDump> {
+ static uint32_t resident_set_kb(
+ const base::trace_event::MemoryDumpCallbackResult::OSMemDump& args) {
+ return args.resident_set_kb;
+ }
+ static bool Read(memory_instrumentation::mojom::OSMemDumpDataView input,
+ base::trace_event::MemoryDumpCallbackResult::OSMemDump* out);
+};
+
+template <>
+struct StructTraits<
+ memory_instrumentation::mojom::MemoryDumpCallbackResultDataView,
+ base::trace_event::MemoryDumpCallbackResult> {
+ static base::trace_event::MemoryDumpCallbackResult::OSMemDump os_dump(
+ const base::trace_event::MemoryDumpCallbackResult& args) {
+ return args.os_dump;
+ }
+ static base::trace_event::MemoryDumpCallbackResult::ChromeMemDump chrome_dump(
+ const base::trace_event::MemoryDumpCallbackResult& args) {
+ return args.chrome_dump;
+ }
+ static bool Read(
+ memory_instrumentation::mojom::MemoryDumpCallbackResultDataView input,
+ base::trace_event::MemoryDumpCallbackResult* out);
+};
+
} // namespace mojo
#endif // SERVICES_RESOURCE_COORDINATOR_PUBLIC_CPP_MEMORY_MEMORY_INSTRUMENTATION_STRUCT_TRAITS_H_
diff --git a/chromium/services/resource_coordinator/public/interfaces/BUILD.gn b/chromium/services/resource_coordinator/public/interfaces/BUILD.gn
index 959f3ecdee5..2fcf102d373 100644
--- a/chromium/services/resource_coordinator/public/interfaces/BUILD.gn
+++ b/chromium/services/resource_coordinator/public/interfaces/BUILD.gn
@@ -6,6 +6,12 @@ import("//mojo/public/tools/bindings/mojom.gni")
mojom("interfaces") {
sources = [
+ "memory/constants.mojom",
"memory/memory_instrumentation.mojom",
+ "tracing/tracing.mojom",
+ ]
+
+ public_deps = [
+ "//mojo/common:common_custom_types",
]
}
diff --git a/chromium/services/resource_coordinator/public/interfaces/memory/constants.mojom b/chromium/services/resource_coordinator/public/interfaces/memory/constants.mojom
new file mode 100644
index 00000000000..8a0387f8899
--- /dev/null
+++ b/chromium/services/resource_coordinator/public/interfaces/memory/constants.mojom
@@ -0,0 +1,7 @@
+// 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 memory_instrumentation.mojom;
+
+const uint64 kServiceTracingProcessId = 0xffffffffffffffff;
diff --git a/chromium/services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom b/chromium/services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom
index 3cdba345a4b..12244c62ba2 100644
--- a/chromium/services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom
+++ b/chromium/services/resource_coordinator/public/interfaces/memory/memory_instrumentation.mojom
@@ -22,12 +22,29 @@ struct RequestArgs {
LevelOfDetail level_of_detail;
};
+struct OSMemDump {
+ uint32 resident_set_kb = 0;
+};
+
+struct ChromeMemDump {
+ uint32 malloc_total_kb = 0;
+ uint32 partition_alloc_total_kb = 0;
+ uint32 blink_gc_total_kb = 0;
+ uint32 v8_total_kb = 0;
+};
+
+struct MemoryDumpCallbackResult {
+ OSMemDump os_dump;
+ ChromeMemDump chrome_dump;
+};
+
// There should be at most one implementation of this interface per process.
interface ProcessLocalDumpManager {
// When successful, the dump is appended in the process-local trace buffer of
- // the target process and only an ACK is returned.
+ // the target process and an ACK. A summary of the dump is also returned in
+ // case of success.
RequestProcessMemoryDump(RequestArgs args) =>
- (uint64 dump_guid, bool success);
+ (uint64 dump_guid, bool success, MemoryDumpCallbackResult? result);
};
// Memory Infra service implements this interface. ProcessLocalDumpManagers
diff --git a/chromium/services/resource_coordinator/public/interfaces/tracing/OWNERS b/chromium/services/resource_coordinator/public/interfaces/tracing/OWNERS
new file mode 100644
index 00000000000..08850f42120
--- /dev/null
+++ b/chromium/services/resource_coordinator/public/interfaces/tracing/OWNERS
@@ -0,0 +1,2 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/resource_coordinator/public/interfaces/tracing/tracing.mojom b/chromium/services/resource_coordinator/public/interfaces/tracing/tracing.mojom
new file mode 100644
index 00000000000..fb8cd3cbac5
--- /dev/null
+++ b/chromium/services/resource_coordinator/public/interfaces/tracing/tracing.mojom
@@ -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.
+
+module resource_coordinator.tracing.mojom;
+
+import "mojo/common/time.mojom";
+import "mojo/common/values.mojom";
+
+// The JSON type of data coming from a tracing agents.
+//
+// - All agents with the same label should have the same type.
+// - There can be multiple agents with the same label, if their data type is
+// ARRAY. Their data will be concatenated together and separated by commas.
+// - There can be only one agent with data type STRING.
+enum TraceDataType {
+ ARRAY,
+ STRING
+};
+
+// Tracing agents, like |chrome|, |etw|, |battor|, and |cros|, use this
+// interface to register themselves to the tracing service.
+interface Factory {
+ RegisterAgent(Agent agent, string name, string label, TraceDataType type,
+ bool supports_explicit_clock_sync_);
+};
+
+// There should be at most one implementation of this interface per process.
+// When the tracing service calls |StopAndFlush| on an agent, the agent begins
+// serializing data into the recorder that was given in the |StartTracing| call.
+// When finished, the agent should close the recorder connection to signal the
+// tracing service that no more data will be sent.
+interface Agent {
+ StartTracing(string categories, Recorder recorder);
+ StopAndFlush();
+ RequestClockSyncMarker() => (mojo.common.mojom.TimeTicks issue_ts,
+ mojo.common.mojom.TimeTicks issue_end_ts);
+ RequestBufferStatus() => (uint32 capacity, uint32 count);
+};
+
+// An agent can make several calls to |AddChunk|. Chunks will be concatenated
+// with no separator (type STRING) or using comma as the separator (type ARRAY).
+// There should be only one agent of type STRING per agent label; otherwise
+// their trace data would be mixed up.
+interface Recorder {
+ AddChunk(string chunk);
+ AddMetadata(mojo.common.mojom.DictionaryValue metadata);
+};
+
+// A tracing controller uses this interface to coordinate trace data collection
+// from all registered agents. At any given time, there should be at most one
+// connected controller.
+interface Coordinator {
+ StartTracing(handle<data_pipe_producer> stream, string categories);
+ StopAndFlush();
+ IsTracing() => (bool is_tracing);
+ RequestBufferUsage() => (float percent_full, uint32 approximate_count);
+};
diff --git a/chromium/services/service_manager/README.md b/chromium/services/service_manager/README.md
index bc54399f819..99578695c2d 100644
--- a/chromium/services/service_manager/README.md
+++ b/chromium/services/service_manager/README.md
@@ -1,27 +1,30 @@
# Service Manager User Guide
+[TOC]
+
## What is the Service Manager?
-The Service Manager is a tool that brokers connections and capabilities between
-and manages instances of components, referred to henceforth as “services”.
+The **Service Manager** is a tool that brokers connections and capabilities
+between -- and manages instances of -- system components referred to henceforth
+as **services**.
The Service Manager performs the following functions:
-* Brokering connections between services, including communicating policies such
- as capabilities (which include access to interfaces), user identity, etc.
-* Launching and managing the lifecycle services and processes (though services
- may also create their own processes and tell the Service Manager about them).
-* Tracks running services, and provides an API that allows services to
- understand whatÂ’s running.
-
-The Service Manager presents a series of Mojo interfaces to services, though in
-practice interacting with the Service is made simpler with a client library.
-Currently, there is only a client library written in C++, since that meets the
-needs of most of the use cases in Chrome.
+* Brokers interface requests between service instances, enforcing static
+ capability policies declared by the services involved.
+* Launches and manages the lifecycle of services and processes.
+* Isolates service instances and interface requests among them according to
+ user identity.
+* Tracks running service instances and exposes privileged APIs for querying
+ system state.
-## Details
+The Service Manager presents a series of Mojo
+[interfaces](https://cs.chromium.org/chromium/src/services/service_manager/public/interfaces)
+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).
-### Mojo Recap
+## Mojo Recap
The Mojo system provides two key components of interest here - a lightweight
message pipe concept allowing two endpoints to communicate, and a bindings layer
@@ -29,776 +32,506 @@ that allows interfaces to be described to bind to those endpoints, with
ergonomic bindings for languages used in Chrome.
Mojo message pipes are designed to be lightweight and may be read from/written
-to and passed around from one process to the next. In most situations however
-the developer wonÂ’t interact with the pipes directly, rather with a generated
-types encapsulating a bound interface.
-
-To use the bindings, a developer defines their interface in the Mojo IDL format,
-**mojom**. With some build magic, the generated headers can then be included and
-used from C++, JS and Java.
-
-It is important to note here that Mojo Interfaces have fully qualified
-identifiers in string form, generated from the module path and interface name:
-“**`module.path.InterfaceName`**”. This is how interfaces are referenced in
-Service Manifests, and how they will be referenced throughout this document.
-
-This would be a good place for me to refer to this in-depth Mojo User Guide,
-which spells all of this out in great detail.
-
-### Services
-
-A Service is any bit of code the Service Manager knows about. This could be a
-unique process, or just a bit of code run in some existing process.
-
-The Service Manager disambiguates services by their **Identity**. Every service
-has its own unique Identity. From the Service ManagerÂ’s perspective, a serviceÂ’s
-Identity is represented by the tuple of the its Name, UserId and Instance Name.
-The Name is a formatted string that superficially represents a scheme:host pair,
-but actually isnÂ’t a URL. More on the structure of these names later. The UserId
-is a string GUID, representing the user the service is run as. The Instance Name
-is a string, typically (but not necessarily) derived from the Name, which can be
-used to allow multiple instances of a service to exist for the same Name,UserId
-pair. In Chrome an example of this would be multiple instances of the renderer
-or the same profile.
-
-A Service implements the Mojo interface service_manager.mojom.Service, which is
-the primary means the Service Manager has of communicating with its service.
-Service has two methods: OnStart(), called once at when the Service Manager
-first learns about the service, and OnConnect(), which the Service Manager calls
- every time some other service tries to connect to this one.
-
-Services have a link back to the Service Manager too, primarily in the form of
-the service_manager.mojom.Connector interface. The Connector allows services to
-open connections to other services.
-
-A unique connection from the Service Manager to a service is called an
-“instance,” each with its own unique identifier, called an instance id. Every
-instance has a unique Identity. It is possible to locate an existing instance
-purely using its Identity.
-
-Services define their own lifetimes. Services in processes started by other
-services (rather than the Service Manager) may even outlive the connection with
-the Service Manager. For processes launched by the Service Manager, when a
-service wishes to terminate it closes the Service pipe with the Service Manager
-and the Service Manager destroys its corresponding instance and asks the process
-to exit.
-
-#### A simple Service example
-
-Consider this simple application that implements the Service interface:
-
-**my_service.cc:**
-
- #include "services/service_manager/public/c/main.h"
- #include "services/service_manager/public/cpp/service.h"
- #include "services/service_manager/public/cpp/service_runner.h"
-
- class MyService : public service_manager::Service {
- public:
- MyService() {}
- ~MyService() override {}
-
- // Overridden from service_manager::Service:
- void OnStart() override {
- }
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override {
- return true;
+to and passed around from one process to another. In most situations a developer
+won't interact with the pipes directly, but rather with bindings types generated
+to encapsulate a bound interface. To use the bindings, a developer defines their
+interface in the [Mojom IDL format](/mojo/public/tools/bindings). With some
+build magic, the generated definitions can then be referenced from C++,
+JavaScript and Java code.
+
+See the [Mojo documentation](/mojo) for a complete overview, detailed
+explanations, and API references.
+
+## Services
+
+A **service** is a collection of one or more private implementations of public
+Mojo interfaces which are reachable via the Service Manager. Every service is
+comprised of the following pieces:
+
+* A set of public Mojo interface definitions
+* A **service manifest** declarating arbitrarily named capabilities which are
+ each comprised of one or more exposed Mojo interfaces.
+* Private implementation code which responds to lifecycle events and incoming
+ interface requests, all driven by the Service Manager.
+
+The Service Manager is responsible for starting new service instances on-demand,
+and a given service many have any number of concurrently running instances. The
+Service Manager disambiguates service instances by their unique
+**identity**. A service's identity is represented by the 3-tuple of the its
+**service name**, **user ID**, and **instance qualifier**:
+
+* The service name is a free-form -- typically short -- string identifying the
+ the specific service being run in the instance.
+* The user ID is a GUID string representing the identity of a user in the system.
+ Every running service instance is associated with a specific user ID.
+* Finally, the instance qualifier is an arbitrary free-form string used to
+ disambiguate multiple instances of a service for the same user.
+
+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)
+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)
+interface. This interface is driven by messages from the Service Manager and is
+used to receive incoming interface requests the Service Manager brokers from
+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)
+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.
+
+## A Simple Service Example
+
+This section walks through the creation of a simple skeleton service.
+
+### Private Implementation
+
+Consider this implementation of the `service_manager::Service` interface:
+
+**`//services//my_service/my_service.h`**
+``` cpp
+#include "base/macros.h"
+#include "services/service_manager/public/cpp/service.h"
+
+namespace my_service {
+
+class MyService : public service_manager::Service {
+ public:
+ MyService();
+ ~MyService() override;
+
+ // service_manager::Service:
+ void OnStart() override;
+ void OnBindInterface(const service_manager::ServiceInfo& remote_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle handle) override;
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MyService);
+};
+
+} // namespace my_service
+```
+
+**`//services//my_service/my_service.cc`**
+``` cpp
+#include "services/my_service/my_service.h"
+
+namespace my_service {
+
+MyService::MyService() = default;
+
+MyService::~MyService() = default;
+
+void MyService::OnStart() {
+}
+
+void MyService::OnBindInterface(const service_manager::ServiceInfo& remote_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle handle) {
+}
+
+} // namespace my_service
+```
+
+### Main Entry Point
+
+While services do not need to define a main entry point -- *e.g.* they may only
+intend to be embedded in other running processes -- for the sake of completeness
+we also define a `ServiceMain` definition so that the service can be run in its
+own process:
+
+**`//services/my_service/my_service_main.cc`**
+``` cpp
+#include "services/my_service/my_service.h"
+#include "services/service_manager/public/c/main.h"
+#include "services/service_manager/public/cpp/service_runner.h"
+
+MojoResult ServiceMain(MojoHandle service_request_handle) {
+ return service_manager::ServiceRunner(new MyService).Run(
+ service_request_handle);
+}
+```
+
+### Manifest
+
+A static manifest is provided to the Service Manager by each service to declare
+the capabilities exposed and required by the service:
+
+**`//services/my_service/manifest.json`**
+``` json
+{
+ "name": "my_service",
+ "display_name": "My Service",
+ "interface_provider_spec": {
+ "service_manager:connector": {}
+ }
+}
+```
+
+See [Service Manifests](#Service-Manifests) for more information.
+
+### Build Targets
+
+Finally some build targets corresponding to the above things:
+
+**`//services/my_service/BUILD.gn`**
+``` python
+import("//services/service_manager/public/cpp/service.gni")
+import("//services/service_manager/public/service_manifest.gni")
+
+source_set("lib") {
+ public = [ "my_service.h" ]
+ sources = [ "my_service.cc" ]
+
+ public_deps = [
+ "//base",
+ "//services/service_manager/public/cpp",
+ ]
+}
+
+service("my_service") {
+ sources = [
+ "my_service_main.cc",
+ ]
+ deps = [
+ ":lib",
+ "//services/service_manager/public/c",
+ ]
+}
+
+service_manifest("manifest") {
+ name = "my_service"
+ source = "manifest.json"
+}
+```
+
+Building the `my_service` target produces a `my_service.service` (or on Windows,
+`my_service.service.exe`) binary in the output directory. This can be run as
+a standalone executable, but it will exit immediately without doing anything
+interesting, because it won't have a `Service` pipe to drive it. The Service
+Manager knows how to provide such a pipe when launching a service executable.
+
+This service doesn't do much of anything. It will simply run forever (or at
+least until the Service Manager itself shuts down), ignoring all incoming
+messages. Before we expand on the definition of this service, let's look at some
+of the details of the `service_manager::Service` interface.
+
+### OnStart
+
+The `Service` implementation is guaranteed to receive a single `OnStart()`
+invocation from the Service Manager before anything else hapens. Once this
+method is called, the implementation can access it
+`service_manager::ServiceContext` via `context()`. This object itself exposes a
+few values:
+
+* `service_info()` is a `service_manager::ServiceInfo` structure describing the
+ running service from the Service Manager's perspective. This includes the
+ `service_manager::Identity` which uniquely identifies the running instance,
+ as well as the `service_manager::InterfaceProviderSpec` describing the
+ capability specifications outlined in the service's manifest.
+* `identity()` is a shortcut to the `Identity` stored in the
+ `ServiceInfo`.
+* `connector()` is a `service_manager::Connector` which can be used to make
+ outgoing interface requests to other services.
+
+For example, we could modify `MyService` to connect out to logger service on
+startup:
+
+``` cpp
+void MyService::OnStart() {
+ logger::mojom::LoggerPtr logger;
+ context()->connector()->BindInterface("logger", &logger);
+ logger->Log("Started MyService!");
+}
+```
+
+### OnBindInterface
+
+The `OnBindInterface` method on `service_manager::Service` is invoked by the
+Service Manager any time another service instance uses its own `Connector` to
+request an interface from this `my_service` instance. The Service Manager only
+invokes this method once it has already validated that the request meets the
+mutual constraints specified in each involved service's manifest.
+
+The arguments to `OnBindInterface` are as follows:
+
+* `remote_info` is the `service_manager::ServiceInfo` corresponding to the
+ remote service which is requesting this interface. The information in this
+ structure is provided authoritatively by the Service Manager and can be
+ trusted in any context.
+* `interface_name` is the (`std::string`) name of the interface being requested
+ by the remote service. The Service Manager has already validated that the
+ remote service requires at least one capability which exposes this interface
+ from the local service.
+* `handle` is the `mojo::ScopedMessagePipeHandle` of an interface pipe which
+ the remote service expects us to bind to a concrete implementation of
+ the requested interface.
+
+The Service Manager client library provides a
+`service_manager::InterfaceRegistry` class definition which can make it easier
+for services to bind incoming interface requests. Typesafe binding callbacks are
+added to an `InterfaceRegistry` ahead of time, and the incoming arguments to
+`OnBindInterface` can be forwarded to the registry, which will bind the message
+pipe if it knows how. For example, we could modify our `MyService`
+implementation as follows:
+
+``` cpp
+namespace {
+
+void BindDatabase(my_service::mojom::DatabaseRequest request) {
+ mojo::MakeStrongBinding(base::MakeUnique<my_service::DatabaseImpl>(),
+ std::move(request));
+}
+
+} // namespace
+
+MyService::MyService() {
+ // Imagine |registry_| is added as a member of MyService, with type
+ // service_manager::InterfaceRegistry.
+
+ // The |my_service::mojom::Database| interface type is inferred by the
+ // compiler in the AddInterface call, and this effectively adds the bound
+ // function to an internal map keyed on the interface name, i.e.
+ // "my_service::mojom::Database" in this case.
+ registry_.AddInterface(base::Bind(&BindDatabase));
+}
+
+void MyService::OnBindInterface(const service_manager::ServiceInfo& remote_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle handle) {
+ registry_.BindInterface(interface_name, std::move(handle));
+}
+```
+
+For more details regarding the definition of Mojom interfaces, implementing them
+in C++, and working with C++ types like `InterfaceRequest`, see the
+[Mojom IDL and Bindings Generator](/mojo/public/tools/bindings) and
+[Mojo C++ Bindings API](/mojo/public/cpp/bindings) documentation.
+
+## Service Manifests
+
+If some service were to come along and attempt to connect to `my_servce` and
+bind the `my_service::mojom::Database` interface, we might see the Service
+Manager spit out an error log complaining that `InterfaceProviderSpec` prevented
+a connection to `my_service`.
+
+In order for the interface to be reachable by other services, we must first fix
+its manifest's **interface provider spec**. The interface provider spec is
+a dictionary keyed by **interface provider name**, with each value representing
+the **capability spec** for that provider.
+
+Each capability spec defines an optional `"provides"` key and an optional
+`"requires"` key.
+
+The `provides` key value is a dictionary which is itself keyed by arbitrary
+free-form strings (capability names, implicitly scoped to the manifest's own
+service) whose values are lists of Mojom interface names exposed as part of that
+capability.
+
+The `requires` key value is also a dictionary, but it's one which is keyed by
+remote service name. Each value is a list of capabilities required from the
+corresponding remote service.
+
+Finally, every interface provider spec (often exclusively) contains one standard
+capability spec named "service_manager:connector". This is the capability spec
+enforced when inter-service connections are made from a service's `Connector`
+interface.
+
+Let's update the `my_service` manifest as follows:
+
+**`//services/my_service/manifest.json`**
+``` json
+{
+ "name": "my_service",
+ "display_name": "My Service",
+ "interface_provider_spec": {
+ "service_manager:connector": {
+ "provides": {
+ "database": [
+ "my_service::mojom::Database"
+ ]
}
- };
-
- MojoResult ServiceMain(MojoHandle service_request_handle) {
- return service_manager::ServiceRunner(new MyService).Run(
- service_request_handle);
}
-
-**manifest.json:**
-
- {
- "name": "my_service",
- "display_name": "My Service",
- "inteface_provider_spec": {
- "service_manager:connector": {}
+ }
+}
+```
+
+This means that `my_service` has defined a `database` capability comprised
+solely of the `my_service::mojom::Database` interface. Any service which
+requires this capability can bind that interface from `my_service`.
+
+For the sake of this example, let's define another service manifest:
+
+**`//services/other_service/manifest.json`**
+``` json
+{
+ "name": "other_service",
+ "display_name": "Other Service",
+ "interface_provider_spec": {
+ "service_manager:connector": {
+ "requires": {
+ "my_service": [ "database" ]
}
}
-
-**BUILD.gn:**
-
- import("//services/service_manager/public/cpp/service.gni")
- import("//services/service_manager/public/service_manifest.gni")
-
- service("my_service") {
- sources = [ "my_service.cc" ]
- deps = [ "//base", "//services/service_manager/public/cpp" ]
- }
-
- service_manifest("manifest") {
- name = "my_service"
- source = "manifest.json"
- }
-
-What does all this do? Building the app target produces two files in the output
-directory: Packages/my_service/my_service.library and
-Packages/my_service/manifest.json. app.library is a DSO loaded by the Service
-Manager in its own process when another service connects to the
-service:my_service name. This is not the only way (nor even the most likely one)
- you can implement a Service, but it's the simplest and easiest to reason about.
-
-This service doesn't do much. Its implementation of OnStart() is empty, and its
-implementation of OnConnect just returns true to allow the inbound connection to
-complete. Let's study the parameters to these methods though, since they'll be
-important as we begin to do more in our service.
-
-##### OnStart Parameters
-
-###### const service_manager::ServiceInfo& info
-ServiceInfo is a struct containing two fields, Identity and
-InterfaceProviderSpec. The Identity field identifies this Service instance in
-the Service Manager, and contains three components - the service name, the user
-id the instance is run as, and an instance qualifier. The InterfaceProviderSpec
-contains the definitions of the capabilities exposed and consumed by this
-service that are statically declared in its manifest.
-
-##### OnConnect Parameters
-
-###### const service_manager::ServiceInfo& remote_info
-Like the ServiceInfo parameter passed to OnStart, but defines the remote Service
-that initiated the connection. The Service Manager client library uses this
-information to limit what capabilities are exposed to the remote via the
-InterfaceRegistry parameter.
-
-###### service_manager::InterfaceRegistry* registry
-An object the local service uses to expose interfaces to be consumed by the
-remote. This object is constructed by the Service Manager client library and
-uses the InterfaceProviderSpecs of both the local and the remote service to
-limit which interfaces can be bound by the remote. This object implements
-service_manager::mojom::InterfaceProvider, which encapsulates the physical link
-between the two services. The InterfaceRegistry is owned by the ServiceContext,
-and will outlive the underlying pipe.
-
-The service can decide to block the connection outright by returning false from
-this method. In that scenario the underlying pipe will be closed and the remote
-end will see an error and have the chance to recover.
-
-Before we add any functionality to our service, such as exposing an interface,
-we should look at how we connect to another service and bind an interface from
-it. This will lay the groundwork to understanding how to export an interface.
-
-### Connecting
-
-Once we have a Connector, we can connect to other services and bind interfaces
-from them. In the trivial app above we can do this directly in OnStart:
-
- void OnStart(const service_manager::ServiceInfo& info) override {
- std::unique_ptr<service_manager::Connection> connection =
- connector()->Connect("service:other_service");
- mojom::SomeInterfacePtr some_interface;
- connection->GetInterface(&some_interface);
- some_interface->Foo();
- }
-
-This assumes an interface called 'mojo.SomeInterface' with a method 'Foo()'
-exported by another service identified by the name 'service:other_service'.
-
-What is happening here? Let's look line-by-line
-
-
- std::unique_ptr<service_manager::Connection> connection =
- connector->Connect("service:other_service");
-
-This asks the Service Manager to open a connection to the service named
-'service:other_service'. The Connect() method returns a Connection object similar
- to the one received by OnConnect() - in fact this Connection object binds the
- other ends of the pipes of the Connection object received by OnConnect in the
-remote service. This time, the caller of Connect() takes ownership of the
-Connection, and when it is destroyed the connection (and the underlying pipes)
-is closed. A note on this later.
-
- mojom::SomeInterfacePtr some_interface;
-
-This is a shorthand from the mojom bindings generator, producing an
-instantiation of a mojo::InterfacePtr<mojom::SomeInterface>. At this point the
-InterfacePtr is unbound (has no pipe handle), and calling is_bound() on it will
-return false. Before we can call any methods, we need to bind it to a Mojo
-message pipe. This is accomplished on the following line:
-
- connection->GetInterface(&some_interface);
-
-Calling this method allocates a Mojo message pipe, binds the client handle to
-the provided InterfacePtr, and sends the server handle to the remote service,
-where it will eventually (asynchronously) be bound to an object implementing the
-requested interface. Now that our InterfacePtr has been bound, we can start
-calling methods on it:
-
- some_interface->Foo();
-
-Now an important note about lifetimes. At this point the Connection returned by
-Connect() goes out of scope, and is destroyed. This closes the underlying
-InterfaceProvider pipes with the remote service. But Mojo methods are
-asynchronous. Does this mean that the call to Foo() above is lost? No. Before
-closing, queued writes to the pipe are flushed.
-
-### Implementing an Interface
-
-Let's look at how to implement an interface now from a service and expose it to
-inbound connections from other services. To do this we'll need to implement
-OnConnect() in our Service implementation, and implement a couple of other
-interfaces. For the sake of this example, we'll imagine now we're writing the
-'service:other_service' service, implementing the interface defined in this
-mojom:
-
-**some_interface.mojom:**
-
- module mojom;
-
- interface SomeInterface {
- Foo();
- };
-
-To build this mojom we need to invoke the mojom gn template from
-`//mojo/public/tools/bindings/mojom.gni`. Once we do that and look at the
-output, we can see that the C++ class mojom::SomeInterface is generated and can
-be #included from the same path as the .mojom file at some_interface.mojom.h.
-In our implementation of the service:other_service, we'll need to derive
-from this class to implement the interface. But that's not enough. We'll also have
-to find a way to bind inbound requests to bind this interface to the object that
-implements it. Let's look at a snippet of a class that does all of this:
-
-**other_service.cc:**
-
- class Service : public service_manager::Service,
- public service_manager::InterfaceFactory<mojom::SomeInterface>,
- public mojom::SomeInterface {
- public:
- ..
-
- // Overridden from service_manager::Service:
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override {
- registry->AddInterface<mojom::SomeInterface>(this);
- return true;
- }
-
- // Overridden from service_manager::InterfaceFactory<mojom::SomeInterface>:
- void Create(const service_manager::Identity& remote_identity,
- mojom::SomeInterfaceRequest request) override {
- bindings_.AddBinding(this, std::move(request));
- }
-
- // Overridden from mojom::SomeInterface:
- void Foo() override { /* .. */ }
-
- mojo::BindingSet<mojom::SomeInterface> bindings_;
- };
-
-Let's study what's going on, starting with the obvious - we derive from
-`mojom::SomeInterface` and implement `Foo()`. How do we bind this implementation
-to a pipe handle from a connected service? First we have to advertise the
-interface to the service via the registry provided at the incoming connection.
-This is accomplished in OnConnect():
-
- registry->AddInterface<mojom::SomeInterface>(this);
-
-This adds the `mojom.SomeInterface` interface name to the inbound
-InterfaceRegistry, and tells it to consult this object when it needs to
-construct an implementation to bind. Why this object? Well in addition to
-Service and SomeInterface, we also implement an instantiation of the generic
-interface InterfaceFactory. InterfaceFactory is the missing piece - it binds a
-request for SomeInterface (in the form of a message pipe server handle) to the
-object that implements the interface (this). This is why we implement Create():
-
- bindings_.AddBinding(this, std::move(request));
-
-In this case, this single instance binds requests for this interface from all
-connected services, so we use a mojo::BindingSet to hold them all.
-Alternatively, we could construct an object per request, and use mojo::Binding.
-
-### Statically Declaring Capabilities
-
-While the code above looks like it should work, if we were to type it all in,
-build it and run it it still wouldn't. In fact, if we ran it, we'd see this
-error in the console:
-
-`InterfaceProviderSpec prevented connection from: service:my_service to service:other_service`
-
-The answer lies in an omission in one of the files I didn't discuss earlier, the
-manifest.json, specifically the empty 'interface_provider_specs' dictionary.
-
-When held, a capability controls some behavior in a service, including the
-ability to bind specific interfaces. At a primitive level, a simple way to think
-about a capability is the ability to bind a pipe and communicate over it.
-
-At the top level, the Service Manager implements the delegation of capabilities
-in accordance with rules spelled out in each service's manifest.
-
-Each service produces a manifest file with some typical metadata about itself,
-and an 'interface_provider_spec'. An interface_provider_spec describes
-capabilities offered by the service and those consumed from other services.
-Let's study a fairly complete interface_provider_spec from another service's
-manifest:
-
- "interface_provider_specs": {
- "service_manager:connector": {
- "provides": {
- "web": ["if1", "if2"],
- "uid": []
- },
- "requires": {
- "*": ["c1", "c2"],
- "service:foo": ["c3"]
- }
- }
- }
-
-At the top level of the interface_provider_spec dictionary are one or more
-sub-dictionaries, each corresponding to an individual InterfaceProviderSpec
-definition. In all cases, there is a dictionary called
-"service_manager:connector". The name here means that the spec is meaningful to
-the Service Manager, and relates to the service_manager::mojom::InterfaceProvider
-pair expressed via the Connector interface. This is the spec that controls what
-capabilities are exposed between services via the Connect()/OnConnect() methods.
-
-Within each spec definition there are two sub-dictionaries:
-
-#### Provided Capabilities
-
-The provides dictionary enumerates the capabilities provided by the service. A
-capability is an alias, either to some special behavior exposed by the service
-to remote services that request that capability, or to a set of interfaces
-exposed by the service to remote services. In the former case, in the
-dictionary we provide an empty array as the value of the capability key, in the
-latter case we provide an array with a list of the fully qualified Mojo
-interface names (module.path.InterfaceName). A special case of array is one that
-contains the single entry "*", which means 'all interfaces'.
-
-Let's consider our previous example the `service:other_service`, which we want
-our `service:my_service` to connect to, and bind mojom::SomeInterface. Every
-interface that a service provides that is intended to be reachable via
-Connect()/OnConnect() must be statically declared in the manifest as exported
-in the providing service's manifest as part of a named capability. A capability
-name is just a string that provider and consumer agree upon. Here's what
-`service:other_service`'s manifest must then look like:
-
- {
- "name": "service:other_service",
- "display_name": "Other Service",
- "interface_provider_specs": {
- "service_manager:connector": {
- "provides": {
- "other_capability": [ "mojom.SomeInterface" ]
- }
- }
- }
- }
-
-#### Required Capabilities
-
-The requires dictionary enumerates the capabilities required by the service. The
-keys into this dictionary are the names of the services it intends to connect
-to, and the values for each key are an array of capability names required of
-that service. A "*" key in the 'requires' dictionary allows the service to provide
-a capability spec that must be adhered to by all services it connects to.
-
-A consequence of this is that a service must statically declare every interface
-it provides in at least one capability in its manifest.
-
-Armed with this knowledge, we can return to manifest.json from the first
-example and fill out the interface_provider_specs:
-
- {
- "name": "service:my_service",
- "display_name": "My Service",
- "interface_provider_specs": {
- "service_manager:connector": {
- "requires": {
- "service:other_service": [],
- }
- }
- }
- }
-
-If we just run now, it still won't work, and we'll see this error:
-
- InterfaceProviderSpec "service_manager:connector" prevented service:
- service:my_service from binding interface mojom.SomeInterface exposed by:
- service:other_service
-
-The connection was allowed to complete, but the attempt to bind
-`mojom.SomeInterface` was blocked. As it happens, this interface is provided as
-part of the capability `other_capability` exported by `service:other_service`.
-We need to add that capability to the array in our manifest:
-
- "requires": {
- "service:other_service": [ "other_capability" ],
- }
-
-Now everything should work.
-
-### Testing
-
-Now that we've built a simple application and service, it's time to write a test
-for them. The Service Manager client library provides a gtest base class
-**service_manager::test::ServiceTest** that makes writing integration tests of
-services straightforward. Let's look at a simple test of our service:
-
- #include "base/bind.h"
- #include "base/run_loop.h"
- #include "services/service_manager/public/cpp/service_test.h"
- #include "path/to/some_interface.mojom.h"
-
- void QuitLoop(base::RunLoop* loop) {
- loop->Quit();
- }
-
- class Test : public service_manager::test::ServiceTest {
- public:
- Test() : service_manager::test::ServiceTest("exe:service_unittest") {}
- ~Test() override {}
- }
-
- TEST_F(Test, Basic) {
- mojom::SomeInterface some_interface;
- connector()->ConnectToInterface("service:other_service", &some_interface);
- base::RunLoop loop;
- some_interface->Foo(base::Bind(&QuitLoop, &loop));
- loop.Run();
- }
-
-The BUILD.gn for this test file looks like any other using the test() template.
-It must also depend on
-//services/service_manager/public/cpp:service_test_support.
-
-ServiceTest does a few things, but most importantly it register the test itself
-as a Service, with the name you pass it via its constructor. In the example
-above, we supplied the name 'exe:service_unittest'. This name is has no special
-meaning other than that henceforth it will be used to identify the test service.
-
-Behind the scenes, ServiceTest spins up the Service Manager on a background
-thread, and asks it to create an instance for the test service on the main
-thread, with the name supplied. ServiceTest blocks the main thread while the
-Service Manager thread does this initialization. Once the Service Manager has
-created the instance, it calls OnStart() (as for any other service), and the
-main thread continues, running the test. At this point accessors defined in
-service_test.h like connector() can be used to connect to other services.
-
-You'll note in the example above I made Foo() take a callback, this is to give
-the test something interesting to do. In the mojom for SomeInterface we'd have
-the Foo() method return an empty response. In service:other_service, we'd have
-Foo() take the callback as a parameter, and run it. In the test, we spin a
-RunLoop until we get that response. In real world cases we can pass back state &
-validate expectations. You can see real examples of this test framework in use
-in the Service Manager's own suite of tests, under
-//services/service_manager/tests.
-
-### Packaging
-
-By default a .library statically links its dependencies, so having many of them
-will yield an installed product many times larger than Chrome today. For this
-reason it's desirable to package several Services together in a single binary.
-The Service Manager provides an interface **service_manager.mojom.ServiceFactory**:
-
- interface ServiceFactory {
- CreateService(Service& service, string name);
- };
-
-When implemented by a service, the service becomes a 'package' of other
-services, which are instantiated by this interface. Imagine we have two services
-service:service1 and service:service2, and we wish to package them together in a
-single package service:services. We write the Service implementations for
-service:service1 and service:service2, and then a Service implementation for
-service:services - the latter implements ServiceFactory and instantiates the
-other two:
-
- using service_manager::mojom::ServiceFactory;
- using service_manager::mojom::ServiceRequest;
-
- class Services : public service_manager::Service,
- public service_manager::InterfaceFactory<ServiceFactory>,
- public ServiceFactory {
-
- // Expose ServiceFactory to inbound connections and implement
- // InterfaceFactory to bind requests for it to this object.
- void CreateService(ServiceRequest request,
- const std::string& name) {
- if (name == "service:service1")
- new Service1(std::move(request));
- else if (name == "service:service2")
- new Service2(std::move(request));
- }
- }
-
-This is only half the story though. While this does mean that service:service1
-and service:service2 are now packaged (statically linked) with service:services,
-as it stands to connect to either packaged service you'd have to connect to
-service:services first, and call CreateService yourself. This is undesirable for
-a couple of reasons, firstly in that it complicates the connect flow, secondly
-in that it forces details of the packaging, which are a distribution-level
-implementation detail on services wishing to use a service.
-
-To solve this, the Service Manager actually automates resolving packaged service
-names to the package service. The Service Manager considers the name of a
-service provided by some other package service to be an 'alias' to that package
-service. The Service Manager resolves these aliases based on information found,
-you guessed it, in the manifests for the package service.
-
-Let's imagine service:service1 and service:service2 have typical manifests of the
-form we covered earlier. Now imagine service:services, the package service that
-combines the two. In the package install directory rather than the following
-structure:
-
- service1/service1.library,manifest.json
- service2/service2.library,manifest.json
-
-Instead we'll have:
-
- package/services.library,manifest.json
-
-The manifest for the package service describes not only itself, but includes the
-manifests of all the services it provides. Fortunately there is some GN build
-magic that automates generating this meta-manifest, so you don't need to write
-it by hand. In the service_manifest() template instantiation for services, we
-add the following lines:
-
- deps = [ ":service1_manifest", ":service2_manifest" ]
- packaged_services = [ "service1", "service2" ]
-
-The deps line lists the service_manifest targets for the packaged services to be
-consumed, and the packaged_services line provides the service names, without the
-'service:' prefix. The presence of these two lines will cause the Manifest Collator
-script to run, merging the dependent manifests into the package manifest. You
-can study the resulting manifest to see what gets generated.
-
-At startup, the Service Manager will scan the package directory and consume the
-manifests it finds, so it can learn about how to resolve aliases that it might
-encounter subsequently.
-
-### Executables
-
-Thus far, the examples we've covered have packaged Services in .library files.
-It's also possible to have a conventional executable provide a Service. There
-are two different ways to use executables with the Service Manager, the first is
-to have the Service Manager start the executable itself, the second is to have
-some other executable start the process and then tell the Service Manager about
-it. In both cases, the target executable has to perform a handshake with the
-Service Manager early on so it can bind the Service request the Service Manager
-sends it.
-
-Assuming you have an executable that properly initializes the Mojo EDK, you add
-the following lines at some point early in application startup to establish the
-connection with the Service Manager:
-
- #include "services/service_manager/public/cpp/service.h"
- #include "services/service_manager/public/cpp/service_context.h"
- #include "services/service_manager/runner/child/runner_connection.h"
-
- class MyService : public service_manager::Service {
- ..
- };
-
- service_manager::mojom::ServiceRequest request;
- std::unique_ptr<service_manager::RunnerConnection> connection(
- service_manager::RunnerConnection::ConnectToRunner(
- &request, ScopedMessagePipeHandle()));
- MyService service;
- service_manager::ServiceContext context(&service, std::move(request));
-
-What's happening here? The Service/ServiceContext usage should be familiar from
-our earlier examples. The interesting part here happens in
-`RunnerConnection::ConnectToRunner()`. Before we look at what ConnectToRunner
-does, it's important to cover how this process is launched. In this example,
-this process is launched by the Service Manager. This is achieved through the
-use of the 'exe' Service Name type. The Service Names we've covered thus far
-have looked like 'service:foo'. The 'mojo' prefix means that the Service Manager
-should look for a .library file at 'foo/foo.library' alongside the Service Manager
-executable. If the code above was linked into an executable 'app.exe' alongside
-the Service Manager executable in the output directory, it can be launched by
-connecting to the name 'exe:app'. When the Service Manager launches an
-executable, it passes a pipe to it on the command line, which the executable is
-expected to bind to receive a ServiceRequest on. Now back to ConnectToRunner.
-It spins up a background 'control' thread with the Service Manager, binds the
-pipe from the command line parameter, and blocks the main thread until the
-ServiceRequest arrives and can be bound.
-
-Like services provided from .library files, we have to provide a manifest for
-services provided from executables. The format is identical, but in the
-service_manifest template we need to set the type property to 'exe' to cause the
-generation step to put the manifest in the right place (it gets placed alongside
-the executable, with the name <exe_name>_manifest.json.)
-
-### Service-Launched Processes
-
-There are some scenarios where a service will need to launch its own process,
-rather than relying on the Service Manager to do it. The Connector API provides
-the ability to tell the Service Manager about a process that the service has or
-will create. The executable that the service launches (henceforth referred to as
-the 'target') should be written using RunnerConnection as discussed in the
-previous section. The connect flow in the service that launches the target
-(henceforth referred to as the driver) works like this:
-
- base::FilePath target_path;
- base::PathService::Get(base::DIR_EXE, &target_path);
- target_path = target_path.Append(FILE_PATH_LITERAL("target.exe"));
- base::CommandLine target_command_line(target_path);
-
- mojo::edk::PlatformChannelPair pair;
- mojo::edk::HandlePassingInformation info;
- pair.PrepareToPassClientHandleToChildProcess(&target_command_line, &info);
-
- mojo::edk::PendingProcessConnection connection;
- std::string token;
- mojo::ScopedMessagePipeHandle pipe = connection.CreateMessagePipe(&token);
- target_command_line.AppendSwitchASCII(switches::kPrimordialPipeToken,
- token);
-
- service_manager::Identity target("exe:target",
- service_manager::mojom::kInheritUserID);
- service_manager::mojom::PIDReceiverPtr receiver;
- connector->RegisterService(target, std::move(pipe), MakeRequest(&receiver));
-
- base::LaunchOptions options;
- options.handles_to_inherit = &info;
- base::Process process = base::LaunchProcess(target_command_line, options);
- connection.Connect(process.Handle(), pair.PassServerHandle());
-
-That's a lot. But it boils down to these steps:
-1. Creating the message pipe to connect the target process and the Service
-Manager.
-2. Putting the server end of the pipe onto the command line to the target
-process.
-3. Binding the client end to a ServiceFactoryPtr, constructing an Identity for
-the target process and passing both through Connector::Connect().
-4. Starting the process with the configured command line.
-
-In this example the target executable could be the same as the previous example.
-
-A word about process lifetimes. Processes created by the Service Manager are
-also managed by the Service Manager. While a service-launched process may quit
-itself at any point, when the Service Manager shuts down it will also shut down
-any process it started. Processes created by services themselves are left to
-those services to manage.
-
-### Other InterfaceProviderSpecs
-
-We discussed InterfaceProviderSpecs in detail in the section above about
-exchange of capabilities between services. That section focused on how
-interfaces are exposed via Connect()/OnConnect(). Looking at the structure of
-service manifests:
-
- "interface_provider_specs": {
- "service_manager:connector": {
- "provides": {
- ...
- },
- "requires": {
- ...
- }
- }
- }
-
-It was discussed that the "service_manager:connector" dictionary described
-capabilities of interest to the Service Manager. While our use cases thus far
-have focused on this single InterfaceProviderSpec, it's possible (and desirable)
-to use others, any time an InterfaceProvider is used. Why? Well
-InterfaceProvider is a generic interface - it can theoretically be used to bind,
-anything and as such it's useful to be able to statically assert what interfaces
-are exposed to what contexts. In Chromium, manifest files get security review,
-which provides an extra layer of care when we think about what capabilities are
-being exposed between contexts at different trust levels. A concrete example
-from Chrome - a pair of InterfaceProviders is used to expose frame-specific
-interfaces between browser and renderer processes. To define another spec, we do
-this:
-
- "interface_provider_specs": {
- "service_manager:connector": {
- "provides": {
- ...
- },
- "requires": {
- ...
- }
- },
- "my_spec_name": {
- "provides": {
- ...
- },
- "requires": {
- ...
- }
+ }
+}
+```
+
+Now if `other_service` attempts to bind the database interface:
+
+``` cpp
+void OtherService::OnStart() {
+ my_service::mojom::DatabasePtr database;
+ context()->connector()->BindInterface("my_service", &database);
+ database->AddTable(...);
+}
+```
+
+The Service Manager will approve of the request and forward it on to the
+`my_service` instance's `OnBindInterface` method.
+
+## Testing
+
+Now that we've built a simple service it's time to write a test for it.
+The Service Manager client library provides a test fixture base class in
+[`service_manager::test::ServiceTest`](https://cs.chromium.org/chromium/src/services/service_manager/public/cpp/service_test.h) that makes writing service integration tests straightforward. This test fixture
+runs an in-process Service Manager on a background thread which allows test
+service instances to be injected at runtime.
+
+Let's look at a simple test of our service:
+
+**`//services/my_service/my_service_unittest.cc`**
+``` cpp
+#include "base/bind.h"
+#include "base/run_loop.h"
+#include "services/service_manager/public/cpp/service_test.h"
+#include "path/to/some_interface.mojom.h"
+
+class MyServiceTest : public service_manager::test::ServiceTest {
+ public:
+ // Our tests run as service instances themselves. In this case each instance
+ // identifies as the service named "my_service_unittests".
+ MyServiceTest() : service_manager::test::ServiceTest("my_service_unittests") {
+ }
+
+ ~MyServiceTest() override {}
+}
+
+TEST_F(MyServiceTest, Basic) {
+ my_service::mojom::DatabsaePtr database;
+ connector()->BindInterface("my_service", &database);
+
+ base::RunLoop loop;
+
+ // This assumes DropTable expects a response with no arugments. When the
+ // response is received, the RunLoop is quit.
+ database->DropTable("foo", loop.QuitClosure());
+
+ loop.Run();
+}
+```
+
+If adding a new test binary for these tests, we can augment our `BUILD.gn` to
+use the `service_test` GN template like so:
+
+**`//services/my_service/BUILD.gn`**
+``` cpp
+import("//services/catalog/public/tools/catalog.gni")
+import("//services/service_manager/public/tools/test/service_test.gni")
+
+service_test("my_service_unittests") {
+ sources = [
+ "my_service_unittest.cc",
+ ]
+ deps = [
+ "//services/my_service/public/interfaces",
+ ]
+ catalog = ":my_service_unittests_catalog"
+}
+
+service_manifest("my_service_unittests_manifest") {
+ name = "my_service_unittests"
+ manifest = "my_service_unittests_manifest.json"
+}
+
+catalog("my_service_unittests_catalog") {
+ testonly = true
+ embedded_services = [ ":my_service_unittests_manifest" ]
+ standalone_services = [ ":manifest" ]
+}
+```
+
+Alright, there's a lot going on here. First we also have to create a service
+manifest for the test service itself, as the Service Manager needs to be able
+to reason about the test's own required capabilities with respect to the
+service-under-test.
+
+We can do something like:
+
+**`//services/my_service/my_service_unittests_manifest.json`**
+``` json
+{
+ "name": "my_service_unittests",
+ "display_name": "my_service tests",
+ "interface_provider_spec": {
+ "service_manager:connector": {
+ "requires": {
+ "my_service": [ "database" ]
}
}
+ }
+}
+```
-And here again we can define capabilities & consume them. To actually hook up
-this new spec in code, we must do what `service_manager::ServiceContext` does
-for us with the `service_manager:connector` spec, and configure a
-`service_manager::InterfaceRegistry` appropriately:
-
- void OnStart(const service_manager::ServiceInfo& info) override {
- registry_ =
- base::MakeUnique<service_manager::InterfaceRegistry>("my_spec_name");
- registry_->AddInterface<mojom::Foo>(this);
- registry_->AddInterface<mojom::Bar>(this);
-
- // Store this so we can use it when we Bind() registry_.
- local_info_ = info;
- }
-
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* remote) override {
- remote_info_ = remote_info;
- registry->AddInterface<mojom::MyInterface>(this);
- return true;
- }
-
- ...
-
- // mojom::MyInterface:
- void GetInterfaceProvider(
- service_manager::mojom::InterfaceProviderRequest request) override {
- service_manager::InterfaceProviderSpec my_spec, remote_spec;
- service_manager::GetInterfaceProviderSpec(
- "my_spec_name", local_info_.interface_provider_specs, &my_spec);
- service_manager::GetInterfaceProviderSpec(
- "my_spec_name", remote_info_.interface_provider_specs, &remote_spec);
- registry_->Bind(std::move(request), local_info_.identity, my_spec,
- remote_info_.identity, remote_spec);
- // |registry_| is now bound to the remote, and its GetInterface()
- // implementation is now controlled via the rules set out in
- // `my_spec_name` declared in this service's and the remote service's
- // manifests.
- }
+You may also notice that we have suddenly introduced a **catalog** in the
+`service_test` target incantation. Any runtime environment which hosts a
+Service Manager must provide the Service Manager implementation with a catalog
+of service manifests. This catalog defines the complete set of services
+recognized by the Service Manager instance and can be used in all kinds of
+interesting ways to control how various services are started in the system. See
+[Service Manager Catalogs](#Service-Manager-Catalogs) for more information.
- ...
+For now let's just accept that we have to create a `catalog` rule for our test
+suite and plug it into the `service_test` target.
- std::unique_ptr<service_manager::InterfaceRegistry> registry_;
- service_manager::ServiceInfo local_info_;
- service_manager::ServiceInfo remote_info_;
+In practice, we typically try to avoid introducing new unittest binaries for
+individual services. Instead we have an aggregate `service_unittests` target
+defined in [`//services/BUILD.gn`](https://cs.chromium.org/chromium/src/services/BUILD.gn).
+There are several examples of other services adding their service tests to this
+suite.
-When we construct an `InterfaceRegistry` we pass the name of the spec that
-controls it. When our service is started we're given (by the Service Manager)
-our own spec. This allows us to know everything we provide. When we receive a
-connection request from another service, the Service Manager provides us with
-the remote service's spec. This is enough information that when we're asked to
-bind the InterfaceRegistry to a pipe from the remote, the appropriate filtering
-is performed.
+## Service Manager Catalogs
+A **catalog** is an aggregation of service manifests which comprises a complete
+runtime configuration of the Service Manager.
-***
+The GN `catalog` target template defined in
+[`//services/catalog/public/tools/catalog.gni`](https://cs.chromium.org/chromium/src/services/catalog/public/tools/catalog.gni).
+provides a simple means of aggregating service manifests into a single build
+artifact. See the comments on the template for detailed documentation.
-TBD:
+This GNI also defines a `catalog_cpp_source` target which can generate a static
+C++ representation of an aggregated catalog manifest so that it can be passed
+the Service Manager at runtime.
-Instances & Processes
+In general, service developers should never be concerned with creating new
+catalogs or instantiating the Service Manager, but it's important to be aware
+of these concepts. When introducing a new service into any runtime environment
+-- including Chrome, Content, or various unit test suites such as
+`service_unittests` discussed in the previous section -- your service manifest
+must be added to the catalog used in that environment.
-Service lifetime strategies
+TODO - expand on this
-Process lifetimes.
+## Packaging Services
-Under the Hood
-Four major components: Service Manager API (Mojom), Service Manager, Catalog,
-Service Manager Client Lib.
-The connect flow, catalog, etc.
-Capability brokering in the Service Manager
-Userids
+TODO
-Finer points:
+## Chrome and Chrome OS Service Manager Integration
-Service Names: mojo, exe
+TODO
diff --git a/chromium/services/service_manager/connect_params.cc b/chromium/services/service_manager/connect_params.cc
index e8464a8b04b..7947a756eb5 100644
--- a/chromium/services/service_manager/connect_params.cc
+++ b/chromium/services/service_manager/connect_params.cc
@@ -7,6 +7,9 @@
namespace service_manager {
ConnectParams::ConnectParams() {}
-ConnectParams::~ConnectParams() {}
+ConnectParams::~ConnectParams() {
+ if (!start_service_callback_.is_null())
+ start_service_callback_.Run(result_, resolved_identity_);
+}
} // namespace service_manager
diff --git a/chromium/services/service_manager/connect_params.h b/chromium/services/service_manager/connect_params.h
index 8c8787a454c..c0cbf65ae73 100644
--- a/chromium/services/service_manager/connect_params.h
+++ b/chromium/services/service_manager/connect_params.h
@@ -10,9 +10,9 @@
#include "base/callback.h"
#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/interface_provider.mojom.h"
#include "services/service_manager/public/interfaces/service.mojom.h"
namespace service_manager {
@@ -29,13 +29,6 @@ class ConnectParams {
void set_target(const Identity& target) { target_ = target; }
const Identity& target() const { return target_; }
- void set_remote_interfaces(mojom::InterfaceProviderRequest value) {
- remote_interfaces_ = std::move(value);
- }
- mojom::InterfaceProviderRequest TakeRemoteInterfaces() {
- return std::move(remote_interfaces_);
- }
-
void set_client_process_info(
mojom::ServicePtr service,
mojom::PIDReceiverRequest pid_receiver_request) {
@@ -68,20 +61,15 @@ class ConnectParams {
return std::move(interface_pipe_);
}
- void set_connect_callback(const mojom::Connector::ConnectCallback& value) {
- connect_callback_ = value;
- }
- const mojom::Connector::ConnectCallback& connect_callback() const {
- return connect_callback_;
+ void set_start_service_callback(
+ const Connector::StartServiceCallback& callback) {
+ start_service_callback_ = callback;
}
- void set_bind_interface_callback(
- const mojom::Connector::BindInterfaceCallback& callback) {
- bind_interface_callback_ = callback;
- }
- const mojom::Connector::BindInterfaceCallback&
- bind_interface_callback() const {
- return bind_interface_callback_;
+ void set_response_data(mojom::ConnectResult result,
+ const Identity& resolved_identity) {
+ result_ = result;
+ resolved_identity_ = resolved_identity;
}
private:
@@ -91,13 +79,16 @@ class ConnectParams {
// The identity of the application being connected to.
Identity target_;
- mojom::InterfaceProviderRequest remote_interfaces_;
mojom::ServicePtr service_;
mojom::PIDReceiverRequest pid_receiver_request_;
std::string interface_name_;
mojo::ScopedMessagePipeHandle interface_pipe_;
- mojom::Connector::ConnectCallback connect_callback_;
- mojom::Connector::BindInterfaceCallback bind_interface_callback_;
+ mojom::Connector::StartServiceCallback start_service_callback_;
+
+ // These values are supplied to the response callback for StartService()/
+ // BindInterface() etc. when the connection is completed.
+ mojom::ConnectResult result_ = mojom::ConnectResult::INVALID_ARGUMENT;
+ Identity resolved_identity_;
DISALLOW_COPY_AND_ASSIGN(ConnectParams);
};
diff --git a/chromium/services/service_manager/connect_util.cc b/chromium/services/service_manager/connect_util.cc
index 2ac6ec4b501..085fdf601d9 100644
--- a/chromium/services/service_manager/connect_util.cc
+++ b/chromium/services/service_manager/connect_util.cc
@@ -7,24 +7,30 @@
#include <memory>
#include <utility>
+#include "base/bind.h"
#include "services/service_manager/connect_params.h"
#include "services/service_manager/service_manager.h"
namespace service_manager {
+namespace {
+
+void EmptyStartServiceCallback(mojom::ConnectResult result,
+ const Identity& resolved_identity) {}
+}
+
mojo::ScopedMessagePipeHandle BindInterface(
ServiceManager* service_manager,
const Identity& source,
const Identity& target,
const std::string& interface_name) {
- mojom::InterfaceProviderPtr remote_interfaces;
std::unique_ptr<ConnectParams> params(new ConnectParams);
params->set_source(source);
params->set_target(target);
- params->set_remote_interfaces(mojo::MakeRequest(&remote_interfaces));
- service_manager->Connect(std::move(params));
mojo::MessagePipe pipe;
- remote_interfaces->GetInterface(interface_name, std::move(pipe.handle1));
+ params->set_interface_request_info(interface_name, std::move(pipe.handle1));
+ params->set_start_service_callback(base::Bind(&EmptyStartServiceCallback));
+ service_manager->Connect(std::move(params));
return std::move(pipe.handle0);
}
diff --git a/chromium/services/service_manager/embedder/BUILD.gn b/chromium/services/service_manager/embedder/BUILD.gn
new file mode 100644
index 00000000000..2d21eed9021
--- /dev/null
+++ b/chromium/services/service_manager/embedder/BUILD.gn
@@ -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.
+
+component("embedder") {
+ sources = [
+ "main.cc",
+ "main.h",
+ "main_delegate.h",
+ "service_manager_embedder_export.h",
+ "set_process_title.cc",
+ "set_process_title.h",
+ "set_process_title_linux.cc",
+ "set_process_title_linux.h",
+ "shared_file_util.cc",
+ "shared_file_util.h",
+ "switches.cc",
+ "switches.h",
+ ]
+
+ if (is_mac) {
+ sources += [
+ "mac_init.h",
+ "mac_init.mm",
+ ]
+
+ libs = [ "Foundation.framework" ]
+ }
+
+ deps = [
+ "//base",
+ "//base/allocator:features",
+ "//mojo/edk/system",
+ "//ui/base",
+ ]
+
+ defines = [ "SERVICE_MANAGER_EMBEDDER_IMPL" ]
+}
diff --git a/chromium/services/service_manager/embedder/DEPS b/chromium/services/service_manager/embedder/DEPS
new file mode 100644
index 00000000000..e7cf2c6ff61
--- /dev/null
+++ b/chromium/services/service_manager/embedder/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+ui/base",
+]
diff --git a/chromium/services/service_manager/embedder/README.md b/chromium/services/service_manager/embedder/README.md
new file mode 100644
index 00000000000..7b9004dcf71
--- /dev/null
+++ b/chromium/services/service_manager/embedder/README.md
@@ -0,0 +1,17 @@
+# Service Manager Embedder API
+
+The Service Manager is a library for opaquely managing service process launch,
+sandboxing, and lifetime; and for brokering Mojo interface connections among
+services.
+
+The Service Manager must be configured with a static set of declarative service
+definitions. The embedder API provides a means of embedding core Service Manager
+functionality into a standalone executable, delegating configuration and
+assorted implementation details to the embedder.
+
+As one example, the Content layer of Chromium embeds the Service Manager via
+this API, and there it's used [WIP] to drive all process management and IPC
+setup across the system.
+
+This API is a work in progress, and more details will be documented here as the
+API is stabilized.
diff --git a/chromium/services/service_manager/embedder/mac_init.h b/chromium/services/service_manager/embedder/mac_init.h
new file mode 100644
index 00000000000..8999d02f908
--- /dev/null
+++ b/chromium/services/service_manager/embedder/mac_init.h
@@ -0,0 +1,15 @@
+// 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_SERVICE_MANAGER_EMBEDDER_MAC_INIT_H_
+#define SERVICES_SERVICE_MANAGER_EMBEDDER_MAC_INIT_H_
+
+namespace service_manager {
+
+// Perform any necessary Mac initialization.
+void InitializeMac();
+
+} // namespace service_manager
+
+#endif // SERVICES_SERVICE_MANAGER_EMBEDDER_MAC_INIT_H_
diff --git a/chromium/services/service_manager/embedder/mac_init.mm b/chromium/services/service_manager/embedder/mac_init.mm
new file mode 100644
index 00000000000..64953e77601
--- /dev/null
+++ b/chromium/services/service_manager/embedder/mac_init.mm
@@ -0,0 +1,25 @@
+// 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/service_manager/embedder/mac_init.h"
+
+#import <Cocoa/Cocoa.h>
+
+namespace service_manager {
+
+void InitializeMac() {
+ [[NSUserDefaults standardUserDefaults] registerDefaults:@{
+ // Exceptions routed to -[NSApplication reportException:] should crash
+ // immediately, as opposed being swallowed or presenting UI that gives the
+ // user a choice in the matter.
+ @"NSApplicationCrashOnExceptions" : @YES,
+
+ // Prevent Cocoa from turning command-line arguments into -[NSApplication
+ // application:openFile:], because they are handled directly. @"NO" looks
+ // like a mistake, but the value really is supposed to be a string.
+ @"NSTreatUnknownArgumentsAsOpen" : @"NO",
+ }];
+}
+
+} // namespace service_manager
diff --git a/chromium/services/service_manager/embedder/main.cc b/chromium/services/service_manager/embedder/main.cc
new file mode 100644
index 00000000000..0debd91780b
--- /dev/null
+++ b/chromium/services/service_manager/embedder/main.cc
@@ -0,0 +1,200 @@
+// 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/service_manager/embedder/main.h"
+#include "base/allocator/features.h"
+#include "base/command_line.h"
+#include "base/debug/activity_tracker.h"
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+#include "base/process/memory.h"
+#include "mojo/edk/embedder/embedder.h"
+#include "services/service_manager/embedder/main_delegate.h"
+#include "services/service_manager/embedder/set_process_title.h"
+#include "services/service_manager/embedder/shared_file_util.h"
+#include "services/service_manager/embedder/switches.h"
+
+#if defined(OS_WIN)
+#include "base/win/process_startup_helper.h"
+#include "ui/base/win/atl_module.h"
+#endif
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+#include <locale.h>
+#include <signal.h>
+
+#include "base/file_descriptor_store.h"
+#include "base/posix/global_descriptors.h"
+#endif
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "services/service_manager/embedder/mac_init.h"
+
+#if BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
+#include "base/allocator/allocator_shim.h"
+#endif
+#endif // defined(OS_MACOSX)
+
+namespace service_manager {
+
+namespace {
+
+// Maximum message size allowed to be read from a Mojo message pipe in any
+// service manager embedder process.
+constexpr size_t kMaximumMojoMessageSize = 128 * 1024 * 1024;
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+
+// Setup signal-handling state: resanitize most signals, ignore SIGPIPE.
+void SetupSignalHandlers() {
+ // Sanitise our signal handling state. Signals that were ignored by our
+ // parent will also be ignored by us. We also inherit our parent's sigmask.
+ sigset_t empty_signal_set;
+ CHECK_EQ(0, sigemptyset(&empty_signal_set));
+ CHECK_EQ(0, sigprocmask(SIG_SETMASK, &empty_signal_set, NULL));
+
+ struct sigaction sigact;
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = SIG_DFL;
+ static const int signals_to_reset[] = {
+ SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
+ SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP}; // SIGPIPE is set below.
+ for (unsigned i = 0; i < arraysize(signals_to_reset); i++) {
+ CHECK_EQ(0, sigaction(signals_to_reset[i], &sigact, NULL));
+ }
+
+ // Always ignore SIGPIPE. We check the return value of write().
+ CHECK_NE(SIG_ERR, signal(SIGPIPE, SIG_IGN));
+}
+
+void PopulateFDsFromCommandLine() {
+ const std::string& shared_file_param =
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
+ switches::kSharedFiles);
+ if (shared_file_param.empty())
+ return;
+
+ base::Optional<std::map<int, std::string>> shared_file_descriptors =
+ service_manager::ParseSharedFileSwitchValue(shared_file_param);
+ if (!shared_file_descriptors)
+ return;
+
+ for (const auto& descriptor : *shared_file_descriptors) {
+ base::MemoryMappedFile::Region region;
+ const std::string& key = descriptor.second;
+ base::ScopedFD fd = base::GlobalDescriptors::GetInstance()->TakeFD(
+ descriptor.first, &region);
+ base::FileDescriptorStore::GetInstance().Set(key, std::move(fd), region);
+ }
+}
+
+#endif // defined(OS_POSIX) && !defined(OS_ANDROID)
+
+} // namespace
+
+MainParams::MainParams(MainDelegate* delegate) : delegate(delegate) {}
+
+MainParams::~MainParams() {}
+
+int Main(const MainParams& params) {
+ MainDelegate* delegate = params.delegate;
+ DCHECK(delegate);
+
+#if defined(OS_MACOSX) && BUILDFLAG(USE_EXPERIMENTAL_ALLOCATOR_SHIM)
+ base::allocator::InitializeAllocatorShim();
+#endif
+ base::EnableTerminationOnOutOfMemory();
+
+#if defined(OS_WIN)
+ base::win::RegisterInvalidParamHandler();
+ ui::win::CreateATLModuleIfNeeded();
+#endif // defined(OS_WIN)
+
+// On Android setlocale() is not supported, and we don't override the signal
+// handlers so we can get a stack trace when crashing.
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+ // Set C library locale to make sure CommandLine can parse argument values in
+ // the correct encoding.
+ setlocale(LC_ALL, "");
+
+ SetupSignalHandlers();
+#endif
+
+#if !defined(OS_ANDROID)
+ // On Android, the command line is initialized when library is loaded.
+ int argc = 0;
+ const char** argv = nullptr;
+
+#if defined(OS_POSIX)
+ // argc/argv are ignored on Windows; see command_line.h for details.
+ argc = params.argc;
+ argv = params.argv;
+#endif
+
+ base::CommandLine::Init(argc, argv);
+
+#if defined(OS_POSIX)
+ PopulateFDsFromCommandLine();
+#endif
+
+ base::EnableTerminationOnHeapCorruption();
+
+#if defined(OS_WIN)
+ base::win::SetupCRT(*base::CommandLine::ForCurrentProcess());
+#endif
+
+ SetProcessTitleFromCommandLine(argv);
+#endif // !defined(OS_ANDROID)
+
+ MainDelegate::InitializeParams init_params;
+
+#if defined(OS_MACOSX)
+ // We need this pool for all the objects created before we get to the event
+ // loop, but we don't want to leave them hanging around until the app quits.
+ // Each "main" needs to flush this pool right before it goes into its main
+ // event loop to get rid of the cruft.
+ std::unique_ptr<base::mac::ScopedNSAutoreleasePool> autorelease_pool =
+ base::MakeUnique<base::mac::ScopedNSAutoreleasePool>();
+ init_params.autorelease_pool = autorelease_pool.get();
+ InitializeMac();
+#endif
+
+ mojo::edk::SetMaxMessageSize(kMaximumMojoMessageSize);
+ mojo::edk::Init();
+
+ base::debug::GlobalActivityTracker* tracker =
+ base::debug::GlobalActivityTracker::Get();
+ int exit_code = delegate->Initialize(init_params);
+ if (exit_code >= 0) {
+ if (tracker) {
+ tracker->SetProcessPhase(
+ base::debug::GlobalActivityTracker::PROCESS_LAUNCH_FAILED);
+ tracker->process_data().SetInt("exit-code", exit_code);
+ }
+ return exit_code;
+ }
+
+ exit_code = delegate->Run();
+ if (tracker) {
+ if (exit_code == 0) {
+ tracker->SetProcessPhaseIfEnabled(
+ base::debug::GlobalActivityTracker::PROCESS_EXITED_CLEANLY);
+ } else {
+ tracker->SetProcessPhaseIfEnabled(
+ base::debug::GlobalActivityTracker::PROCESS_EXITED_WITH_CODE);
+ tracker->process_data().SetInt("exit-code", exit_code);
+ }
+ }
+
+#if defined(OS_MACOSX)
+ autorelease_pool.reset();
+#endif
+
+ delegate->ShutDown();
+
+ return exit_code;
+}
+
+} // namespace service_manager
diff --git a/chromium/services/service_manager/embedder/main.h b/chromium/services/service_manager/embedder/main.h
new file mode 100644
index 00000000000..e86697a26d0
--- /dev/null
+++ b/chromium/services/service_manager/embedder/main.h
@@ -0,0 +1,33 @@
+// 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_SERVICE_MANAGER_EMBEDDER_MAIN_H_
+#define SERVICES_SERVICE_MANAGER_EMBEDDER_MAIN_H_
+
+#include "build/build_config.h"
+#include "services/service_manager/embedder/service_manager_embedder_export.h"
+
+namespace service_manager {
+
+class MainDelegate;
+
+struct SERVICE_MANAGER_EMBEDDER_EXPORT MainParams {
+ explicit MainParams(MainDelegate* delegate);
+ ~MainParams();
+
+ MainDelegate* const delegate;
+
+#if defined(OS_POSIX) && !defined(OS_ANDROID)
+ int argc = 0;
+ const char** argv = nullptr;
+#endif
+};
+
+// Main function which should be called as early as possible by any executable
+// embedding the service manager.
+int SERVICE_MANAGER_EMBEDDER_EXPORT Main(const MainParams& params);
+
+} // namespace service_manager
+
+#endif // SERVICES_SERVICE_MANAGER_EMBEDDER_MAIN_H_
diff --git a/chromium/services/service_manager/embedder/main_delegate.h b/chromium/services/service_manager/embedder/main_delegate.h
new file mode 100644
index 00000000000..f9222959ece
--- /dev/null
+++ b/chromium/services/service_manager/embedder/main_delegate.h
@@ -0,0 +1,50 @@
+// 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_SERVICE_MANAGER_EMBEDDER_MAIN_DELEGATE_H_
+#define SERVICES_SERVICE_MANAGER_EMBEDDER_MAIN_DELEGATE_H_
+
+#include "services/service_manager/embedder/service_manager_embedder_export.h"
+
+namespace base {
+namespace mac {
+class ScopedNSAutoreleasePool;
+}
+}
+
+namespace service_manager {
+
+// An interface which must be implemented by Service Manager embedders to
+// control basic process initialization and shutdown, as well as early branching
+// to run specific types of subprocesses.
+class MainDelegate {
+ public:
+ // Extra parameters passed to MainDelegate::Initialize.
+ struct InitializeParams {
+#if defined(OS_MACOSX)
+ // The outermost autorelease pool, allocated by internal service manager
+ // logic. This is guaranteed to live throughout the extent of Run().
+ base::mac::ScopedNSAutoreleasePool* autorelease_pool = nullptr;
+#endif
+ };
+
+ virtual ~MainDelegate() {}
+
+ // Perform early process initialization. Returns -1 if successful, or the exit
+ // code with which the process should be terminated due to initialization
+ // failure.
+ virtual int Initialize(const InitializeParams& params) = 0;
+
+ // Runs the main process logic. Called exactly once, and only after a
+ // successful call to Initialize(). Returns the exit code to use when
+ // terminating the process after Run() (and then ShutDown()) completes.
+ virtual int Run() = 0;
+
+ // Called after Run() returns, before exiting the process.
+ virtual void ShutDown() = 0;
+};
+
+} // namespace service_manager
+
+#endif // SERVICES_SERVICE_MANAGER_EMBEDDER_MAIN_DELEGATE_H_
diff --git a/chromium/services/service_manager/embedder/service_manager_embedder_export.h b/chromium/services/service_manager/embedder/service_manager_embedder_export.h
new file mode 100644
index 00000000000..b29c7782a41
--- /dev/null
+++ b/chromium/services/service_manager/embedder/service_manager_embedder_export.h
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_SERVICE_MANAGER_SERVICE_MANAGER_EMBEDDER_EXPORT_H_
+#define SERVICES_SERVICE_MANAGER_SERVICE_MANAGER_EMBEDDER_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(SERVICE_MANAGER_EMBEDDER_IMPL)
+#define SERVICE_MANAGER_EMBEDDER_EXPORT __declspec(dllexport)
+#else
+#define SERVICE_MANAGER_EMBEDDER_EXPORT __declspec(dllimport)
+#endif // defined(SERVICE_MANAGER_EMBEDDER_IMPL)
+
+#else // defined(WIN32)
+#if defined(SERVICE_MANAGER_EMBEDDER_IMPL)
+#define SERVICE_MANAGER_EMBEDDER_EXPORT __attribute__((visibility("default")))
+#else
+#define SERVICE_MANAGER_EMBEDDER_EXPORT
+#endif // defined(SERVICE_MANAGER_EMBEDDER_IMPL)
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define SERVICE_MANAGER_EMBEDDER_EXPORT
+#endif
+
+#endif // SERVICES_SERVICE_MANAGER_SERVICE_MANAGER_EMBEDDER_EXPORT_H_
diff --git a/chromium/services/service_manager/embedder/set_process_title.cc b/chromium/services/service_manager/embedder/set_process_title.cc
new file mode 100644
index 00000000000..80b9a0ab2ff
--- /dev/null
+++ b/chromium/services/service_manager/embedder/set_process_title.cc
@@ -0,0 +1,94 @@
+// 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/service_manager/embedder/set_process_title.h"
+
+#include <stddef.h>
+
+#include "build/build_config.h"
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_SOLARIS)
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "base/command_line.h"
+#endif // defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_SOLARIS)
+
+#if defined(OS_LINUX)
+#include <sys/prctl.h>
+
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/process/process_metrics.h"
+#include "base/strings/string_util.h"
+#include "base/threading/platform_thread.h"
+// Linux/glibc doesn't natively have setproctitle().
+#include "services/service_manager/embedder/set_process_title_linux.h"
+#endif // defined(OS_LINUX)
+
+namespace service_manager {
+
+// TODO(jrg): Find out if setproctitle or equivalent is available on Android.
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_SOLARIS) && \
+ !defined(OS_ANDROID)
+
+void SetProcessTitleFromCommandLine(const char** main_argv) {
+ // Build a single string which consists of all the arguments separated
+ // by spaces. We can't actually keep them separate due to the way the
+ // setproctitle() function works.
+ std::string title;
+ bool have_argv0 = false;
+
+#if defined(OS_LINUX)
+ DCHECK_EQ(base::PlatformThread::CurrentId(), getpid());
+
+ if (main_argv)
+ setproctitle_init(main_argv);
+
+ // In Linux we sometimes exec ourselves from /proc/self/exe, but this makes us
+ // show up as "exe" in process listings. Read the symlink /proc/self/exe and
+ // use the path it points at for our process title. Note that this is only for
+ // display purposes and has no TOCTTOU security implications.
+ base::FilePath target;
+ base::FilePath self_exe(base::kProcSelfExe);
+ if (base::ReadSymbolicLink(self_exe, &target)) {
+ have_argv0 = true;
+ title = target.value();
+ // If the binary has since been deleted, Linux appends " (deleted)" to the
+ // symlink target. Remove it, since this is not really part of our name.
+ const std::string kDeletedSuffix = " (deleted)";
+ if (base::EndsWith(title, kDeletedSuffix, base::CompareCase::SENSITIVE))
+ title.resize(title.size() - kDeletedSuffix.size());
+
+ // PR_SET_NAME is available in Linux 2.6.9 and newer.
+ // When available at run time, this sets the short process name that shows
+ // when the full command line is not being displayed in most process
+ // listings.
+ prctl(PR_SET_NAME, base::FilePath(title).BaseName().value().c_str());
+ }
+#endif // defined(OS_LINUX)
+
+ const base::CommandLine* command_line =
+ base::CommandLine::ForCurrentProcess();
+ for (size_t i = 1; i < command_line->argv().size(); ++i) {
+ if (!title.empty())
+ title += " ";
+ title += command_line->argv()[i];
+ }
+ // Disable prepending argv[0] with '-' if we prepended it ourselves above.
+ setproctitle(have_argv0 ? "-%s" : "%s", title.c_str());
+}
+
+#else
+
+// All other systems (basically Windows & Mac) have no need or way to implement
+// this function.
+void SetProcessTitleFromCommandLine(const char** /* main_argv */) {}
+
+#endif
+
+} // namespace service_manager
diff --git a/chromium/services/service_manager/embedder/set_process_title.h b/chromium/services/service_manager/embedder/set_process_title.h
new file mode 100644
index 00000000000..27fe092785a
--- /dev/null
+++ b/chromium/services/service_manager/embedder/set_process_title.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 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_SERVICE_MANAGER_EMBEDDER_SET_PROCESS_TITLE_H_
+#define SERVICES_SERVICE_MANAGER_EMBEDDER_SET_PROCESS_TITLE_H_
+
+#include "services/service_manager/embedder/service_manager_embedder_export.h"
+
+namespace service_manager {
+
+// Sets OS-specific process title information based on the command line. This
+// does nothing if the OS doesn't support or need this capability.
+//
+// Pass in the argv from main(). On Windows, where there is no argv, you can
+// pass NULL or just don't call this function, since it does nothing. This
+// argv pointer will be cached so if you call this function again, you can pass
+// NULL in the second call. This is to support the case where it's called once
+// at startup, and later when a zygote is fork()ed. The later call doesn't have
+// easy access to main's argv.
+//
+// On non-Mac Unix platforms, we exec ourselves from /proc/self/exe, but that
+// makes the process name that shows up in "ps" etc. for the child processes
+// show as "exe" instead of "chrome" or something reasonable. This function
+// will try to fix it so the "effective" command line shows up instead.
+SERVICE_MANAGER_EMBEDDER_EXPORT
+void SetProcessTitleFromCommandLine(const char** main_argv);
+
+} // namespace service_manager
+
+#endif // SERVICES_SERVICE_MANAGER_EMBEDDER_SET_PROCESS_TITLE_H_
diff --git a/chromium/services/service_manager/embedder/set_process_title_linux.cc b/chromium/services/service_manager/embedder/set_process_title_linux.cc
new file mode 100644
index 00000000000..e0a5f3b7999
--- /dev/null
+++ b/chromium/services/service_manager/embedder/set_process_title_linux.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2009 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.
+
+// This file implements BSD-style setproctitle() for Linux.
+// It is written such that it can easily be compiled outside Chromium.
+//
+// The Linux kernel sets up two locations in memory to pass arguments and
+// environment variables to processes. First, there are two char* arrays stored
+// one after another: argv and environ. A pointer to argv is passed to main(),
+// while glibc sets the global variable |environ| to point at the latter. Both
+// of these arrays are terminated by a NULL pointer; the environment array is
+// also followed by some empty space to allow additional variables to be added.
+//
+// These arrays contain pointers to a second location in memory, where the
+// strings themselves are stored one after another: first all the arguments,
+// then the environment variables. The kernel will allocate a single page of
+// memory for this purpose, so the end of the page containing argv[0] is the
+// end of the storage potentially available to store the process title.
+//
+// When the kernel reads the command line arguments for a process, it looks at
+// the range of memory within this page that it initially used for the argument
+// list. If the terminating '\0' character is still where it expects, nothing
+// further is done. If it has been overwritten, the kernel will scan up to the
+// size of a page looking for another. (Note, however, that in general not that
+// much space is actually mapped, since argv[0] is rarely page-aligned and only
+// one page is mapped.)
+//
+// Thus to change the process title, we must move any environment variables out
+// of the way to make room for a potentially longer title, and then overwrite
+// the memory pointed to by argv[0] with a single replacement string, making
+// sure its size does not exceed the available space.
+//
+// It is perhaps worth noting that patches to add a system call to Linux for
+// this, like in BSD, have never made it in: this is the "official" way to do
+// this on Linux. Presumably it is not in glibc due to some disagreement over
+// this position within the glibc project, leaving applications caught in the
+// middle. (Also, only a very few applications need or want this anyway.)
+
+#include "services/service_manager/embedder/set_process_title_linux.h"
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+extern char** environ;
+
+static char** g_main_argv = NULL;
+static char* g_orig_argv0 = NULL;
+
+void setproctitle(const char* fmt, ...) {
+ va_list ap;
+ size_t i, avail_size;
+ uintptr_t page_size, page, page_end;
+ // Sanity check before we try and set the process title.
+ // The BSD version allows fmt == NULL to restore the original title.
+ if (!g_main_argv || !environ || !fmt)
+ return;
+ if (!g_orig_argv0) {
+ // Save the original argv[0].
+ g_orig_argv0 = strdup(g_main_argv[0]);
+ if (!g_orig_argv0)
+ return;
+ }
+ page_size = sysconf(_SC_PAGESIZE);
+ // Get the page on which the argument list and environment live.
+ page = (uintptr_t)g_main_argv[0];
+ page -= page % page_size;
+ page_end = page + page_size;
+ // Move the environment out of the way. Note that we are moving the values,
+ // not the environment array itself (which may not be on the page we need
+ // to overwrite anyway).
+ for (i = 0; environ[i]; ++i) {
+ uintptr_t env_i = (uintptr_t)environ[i];
+ // Only move the value if it's actually in the way. This avoids
+ // leaking copies of the values if this function is called again.
+ if (page <= env_i && env_i < page_end) {
+ char* copy = strdup(environ[i]);
+ // Be paranoid. Check for allocation failure and bail out.
+ if (!copy)
+ return;
+ environ[i] = copy;
+ }
+ }
+ // Put the title in argv[0]. We have to zero out the space first since the
+ // kernel doesn't actually look for a null terminator unless we make the
+ // argument list longer than it started.
+ avail_size = page_end - (uintptr_t)g_main_argv[0];
+ memset(g_main_argv[0], 0, avail_size);
+ va_start(ap, fmt);
+ if (fmt[0] == '-') {
+ vsnprintf(g_main_argv[0], avail_size, &fmt[1], ap);
+ } else {
+ size_t size = snprintf(g_main_argv[0], avail_size, "%s ", g_orig_argv0);
+ if (size < avail_size)
+ vsnprintf(g_main_argv[0] + size, avail_size - size, fmt, ap);
+ }
+ va_end(ap);
+ g_main_argv[1] = NULL;
+}
+
+// A version of this built into glibc would not need this function, since
+// it could stash the argv pointer in __libc_start_main(). But we need it.
+void setproctitle_init(const char** main_argv) {
+ if (g_main_argv)
+ return;
+
+ uintptr_t page_size = sysconf(_SC_PAGESIZE);
+ // Check that the argv array is in fact on the same page of memory
+ // as the environment array just as an added measure of protection.
+ if (((uintptr_t)environ) / page_size == ((uintptr_t)main_argv) / page_size)
+ g_main_argv = const_cast<char**>(main_argv);
+}
diff --git a/chromium/services/service_manager/embedder/set_process_title_linux.h b/chromium/services/service_manager/embedder/set_process_title_linux.h
new file mode 100644
index 00000000000..690c9270b6d
--- /dev/null
+++ b/chromium/services/service_manager/embedder/set_process_title_linux.h
@@ -0,0 +1,22 @@
+// 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_SERVICE_MANAGER_EMBEDDER_SET_PROCESS_TITLE_LINUX_H_
+#define SERVICES_SERVICE_MANAGER_EMBEDDER_SET_PROCESS_TITLE_LINUX_H_
+
+// Set the process title that will show in "ps" and similar tools. Takes
+// printf-style format string and arguments. After calling setproctitle()
+// the original main() argv[] array should not be used. By default, the
+// original argv[0] is prepended to the format; this can be disabled by
+// including a '-' as the first character of the format string.
+//
+// This signature and naming is to be compatible with most other Unix
+// implementations of setproctitle().
+void setproctitle(const char* fmt, ...);
+
+// Initialize state needed for setproctitle() on Linux. Pass the argv pointer
+// from main() to setproctitle_init() before calling setproctitle().
+void setproctitle_init(const char** main_argv);
+
+#endif // SERVICES_SERVICE_MANAGER_EMBEDDER_SET_PROCESS_TITLE_LINUX_H_
diff --git a/chromium/services/service_manager/public/cpp/lib/shared_file_util.cc b/chromium/services/service_manager/embedder/shared_file_util.cc
index f996ed8a3c6..2081c24a03f 100644
--- a/chromium/services/service_manager/public/cpp/lib/shared_file_util.cc
+++ b/chromium/services/service_manager/embedder/shared_file_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/service_manager/public/cpp/shared_file_util.h"
+#include "services/service_manager/embedder/shared_file_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
diff --git a/chromium/services/service_manager/public/cpp/shared_file_util.h b/chromium/services/service_manager/embedder/shared_file_util.h
index b184b29e491..d524ec5a1d1 100644
--- a/chromium/services/service_manager/public/cpp/shared_file_util.h
+++ b/chromium/services/service_manager/embedder/shared_file_util.h
@@ -2,18 +2,19 @@
// 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_SHARED_FILE_UTIL_H_
-#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_SHARED_FILE_UTIL_H_
+#ifndef SERVICES_SERVICE_MANAGER_EMBEDDER_SHARED_FILE_UTIL_H_
+#define SERVICES_SERVICE_MANAGER_EMBEDDER_SHARED_FILE_UTIL_H_
#include <map>
#include <string>
#include "base/command_line.h"
#include "base/optional.h"
+#include "services/service_manager/embedder/service_manager_embedder_export.h"
namespace service_manager {
-class SharedFileSwitchValueBuilder final {
+class SERVICE_MANAGER_EMBEDDER_EXPORT SharedFileSwitchValueBuilder final {
public:
void AddEntry(const std::string& key_str, int key_id);
const std::string& switch_value() const { return switch_value_; }
@@ -22,9 +23,9 @@ class SharedFileSwitchValueBuilder final {
std::string switch_value_;
};
-base::Optional<std::map<int, std::string>> ParseSharedFileSwitchValue(
- const std::string& value);
+SERVICE_MANAGER_EMBEDDER_EXPORT base::Optional<std::map<int, std::string>>
+ParseSharedFileSwitchValue(const std::string& value);
} // namespace service_manager
-#endif // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_SHARED_FILE_UTIL_H_ \ No newline at end of file
+#endif // SERVICES_SERVICE_MANAGER_EMBEDDER_SHARED_FILE_UTIL_H_
diff --git a/chromium/services/service_manager/embedder/switches.cc b/chromium/services/service_manager/embedder/switches.cc
new file mode 100644
index 00000000000..8492cfafb5e
--- /dev/null
+++ b/chromium/services/service_manager/embedder/switches.cc
@@ -0,0 +1,20 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/service_manager/embedder/switches.h"
+
+namespace switches {
+
+// Describes the file descriptors passed to a child process in the following
+// list format:
+//
+// <file_id>:<descriptor_id>,<file_id>:<descriptor_id>,...
+//
+// where <file_id> is an ID string from the manifest of the service being
+// launched and <descriptor_id> is the numeric identifier of the descriptor for
+// the child process can use to retrieve the file descriptor from the
+// global descriptor table.
+const char kSharedFiles[] = "shared-files";
+
+} // namespace switches
diff --git a/chromium/services/service_manager/embedder/switches.h b/chromium/services/service_manager/embedder/switches.h
new file mode 100644
index 00000000000..8282dfae9a6
--- /dev/null
+++ b/chromium/services/service_manager/embedder/switches.h
@@ -0,0 +1,16 @@
+// 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_SERVICE_MANAGER_EMBEDDER_SWITCHES_H_
+#define SERVICES_SERVICE_MANAGER_EMBEDDER_SWITCHES_H_
+
+#include "services/service_manager/embedder/service_manager_embedder_export.h"
+
+namespace switches {
+
+SERVICE_MANAGER_EMBEDDER_EXPORT extern const char kSharedFiles[];
+
+} // namespace service_manager
+
+#endif // SERVICES_SERVICE_MANAGER_EMBEDDER_SWITCHES_H_
diff --git a/chromium/services/service_manager/public/cpp/BUILD.gn b/chromium/services/service_manager/public/cpp/BUILD.gn
index 57e529c13ee..a2452f5c0d0 100644
--- a/chromium/services/service_manager/public/cpp/BUILD.gn
+++ b/chromium/services/service_manager/public/cpp/BUILD.gn
@@ -13,7 +13,6 @@ static_library("sources") {
sources = [
"binder_registry.h",
"connect.h",
- "connection.h",
"connector.h",
"identity.h",
"interface_binder.h",
@@ -25,8 +24,6 @@ static_library("sources") {
"lib/binder_registry.cc",
"lib/callback_binder.cc",
"lib/callback_binder.h",
- "lib/connection_impl.cc",
- "lib/connection_impl.h",
"lib/connector_impl.cc",
"lib/connector_impl.h",
"lib/identity.cc",
@@ -39,13 +36,11 @@ static_library("sources") {
"lib/service_context_ref.cc",
"lib/service_info.cc",
"lib/service_runner.cc",
- "lib/shared_file_util.cc",
"service.h",
"service_context.h",
"service_context_ref.h",
"service_info.h",
"service_runner.h",
- "shared_file_util.h",
]
public_deps = [
diff --git a/chromium/services/service_manager/public/cpp/connection.h b/chromium/services/service_manager/public/cpp/connection.h
deleted file mode 100644
index 28eee4d44f8..00000000000
--- a/chromium/services/service_manager/public/cpp/connection.h
+++ /dev/null
@@ -1,96 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTION_H_
-#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTION_H_
-
-#include "base/memory/weak_ptr.h"
-#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
-#include "services/service_manager/public/interfaces/connector.mojom.h"
-
-namespace service_manager {
-
-class InterfaceProvider;
-
-// Represents a connection to another application. An implementation of this
-// interface is returned from Connector::Connect().
-class Connection {
- public:
- virtual ~Connection() {}
-
- enum class State {
- // The service manager has not yet processed the connection.
- PENDING,
-
- // The service manager processed the connection and it was established.
- // GetResult() returns mojom::ConnectionResult::SUCCESS.
- CONNECTED,
-
- // The service manager processed the connection and establishment was
- // prevented by an error, call GetResult().
- DISCONNECTED
- };
-
- class TestApi {
- public:
- explicit TestApi(Connection* connection) : connection_(connection) {}
- base::WeakPtr<Connection> GetWeakPtr() {
- return connection_->GetWeakPtr();
- }
-
- private:
- Connection* connection_;
- };
-
- // 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) {
- GetRemoteInterfaces()->GetInterface(ptr);
- }
- template <typename Interface>
- void GetInterface(mojo::InterfaceRequest<Interface> request) {
- GetRemoteInterfaces()->GetInterface(std::move(request));
- }
-
- // Returns the remote identity. While the connection is in the pending state,
- // the user_id() field will be the value passed via Connect(). After the
- // connection is completed, it will change to the value assigned by the
- // service manager. Call AddConnectionCompletedClosure() to schedule a closure
- // to be run when the resolved user id is available.
- virtual const Identity& GetRemoteIdentity() const = 0;
-
- // Register a handler to receive an error notification on the pipe to the
- // remote application's InterfaceProvider.
- virtual void SetConnectionLostClosure(const base::Closure& handler) = 0;
-
- // Returns the result of the connection. This function should only be called
- // when the connection state is not pending. Call
- // AddConnectionCompletedClosure() to schedule a closure to be run when the
- // connection is processed by the service manager.
- virtual mojom::ConnectResult GetResult() const = 0;
-
- // Returns true if the connection has not yet been processed by the service
- // manager.
- virtual bool IsPending() const = 0;
-
- // Register a closure to be run when the connection has been completed by the
- // service manager and remote metadata is available. Useful only for
- // connections created
- // via Connector::Connect(). Once the connection is complete, metadata is
- // available immediately.
- virtual void AddConnectionCompletedClosure(const base::Closure& callback) = 0;
-
- // Returns an object encapsulating a remote InterfaceProvider.
- virtual InterfaceProvider* GetRemoteInterfaces() = 0;
-
- protected:
- virtual base::WeakPtr<Connection> GetWeakPtr() = 0;
-};
-
-} // namespace service_manager
-
-#endif // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_CONNECTION_H_
diff --git a/chromium/services/service_manager/public/cpp/connector.h b/chromium/services/service_manager/public/cpp/connector.h
index 793fe91d02e..ae15116292a 100644
--- a/chromium/services/service_manager/public/cpp/connector.h
+++ b/chromium/services/service_manager/public/cpp/connector.h
@@ -7,7 +7,6 @@
#include <memory>
-#include "services/service_manager/public/cpp/connection.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"
@@ -17,45 +16,74 @@ namespace service_manager {
// An interface that encapsulates the Service Manager's brokering interface, by
// which
-// connections between services are established. Once Connect() is called,
-// this class is bound to the thread the call was made on and it cannot be
-// passed to another thread without calling Clone().
+// connections between services are established. Once either StartService() or
+// BindInterface() is called, this class is bound to the thread the call was
+// made on and it cannot be passed to another thread without calling Clone().
//
// An instance of this class is created internally by ServiceContext for use
// on the thread ServiceContext is instantiated on.
//
// To use this interface on another thread, call Clone() and pass the new
-// instance to the desired thread before calling Connect().
+// instance to the desired thread before calling StartService() or
+// BindInterface().
//
// While instances of this object are owned by the caller, the underlying
// connection with the service manager is bound to the lifetime of the instance
-// that
-// created it, i.e. when the application is terminated the Connector pipe is
-// closed.
+// that created it, i.e. when the application is terminated the Connector pipe
+// is closed.
class Connector {
public:
+ using StartServiceCallback =
+ base::Callback<void(mojom::ConnectResult, const Identity& identity)>;
+
+ class TestApi {
+ public:
+ using Binder = base::Callback<void(mojo::ScopedMessagePipeHandle)>;
+ explicit TestApi(Connector* connector) : connector_(connector) {}
+ ~TestApi() { connector_->ResetStartServiceCallback(); }
+
+ // 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,
+ const std::string& interface_name,
+ const Binder& binder) {
+ connector_->OverrideBinderForTesting(service_name, interface_name,
+ binder);
+ }
+ void ClearBinderOverrides() { connector_->ClearBinderOverrides(); }
+
+ // Register a callback to be run with the result of an attempt to start a
+ // service. This will be run in response to calls to StartService() or
+ // BindInterface().
+ void SetStartServiceCallback(const StartServiceCallback& callback) {
+ connector_->SetStartServiceCallback(callback);
+ }
+
+ private:
+ Connector* connector_;
+ };
+
virtual ~Connector() {}
// Creates a new Connector instance and fills in |*request| with a request
// for the other end the Connector's interface.
static std::unique_ptr<Connector> Create(mojom::ConnectorRequest* request);
+ // Creates an instance of a service for |identity|.
+ virtual void StartService(const Identity& identity) = 0;
+
+ // Creates an instance of the service |name| inheriting the caller's identity.
+ virtual void StartService(const std::string& name) = 0;
+
// Creates an instance of a service for |identity| in a process started by the
- // client (or someone else). Must be called before Connect() may be called to
- // |identity|.
+ // client (or someone else). Must be called before BindInterface() may be
+ // called to |identity|.
virtual void StartService(
const Identity& identity,
mojom::ServicePtr service,
mojom::PIDReceiverRequest pid_receiver_request) = 0;
- // Requests a new connection to a service. Returns a pointer to the
- // connection if the connection is permitted by that service, nullptr
- // otherwise. Once this method is called, this object is bound to the thread
- // on which the call took place. To pass to another thread, call Clone() and
- // pass the result.
- virtual std::unique_ptr<Connection> Connect(const std::string& name) = 0;
- virtual std::unique_ptr<Connection> Connect(const Identity& target) = 0;
-
// Connect to |target| & request to bind |Interface|.
template <typename Interface>
void BindInterface(const Identity& target,
@@ -80,12 +108,24 @@ class Connector {
mojo::ScopedMessagePipeHandle interface_pipe) = 0;
// Creates a new instance of this class which may be passed to another thread.
- // The returned object may be passed multiple times until Connect() is called,
- // at which point this method must be called again to pass again.
+ // The returned object may be passed multiple times until StartService() or
+ // BindInterface() is called, at which point this method must be called again
+ // to pass again.
virtual std::unique_ptr<Connector> Clone() = 0;
// Binds a Connector request to the other end of this Connector.
virtual void BindConnectorRequest(mojom::ConnectorRequest request) = 0;
+
+ virtual base::WeakPtr<Connector> GetWeakPtr() = 0;
+
+ protected:
+ virtual void OverrideBinderForTesting(const std::string& service_name,
+ const std::string& interface_name,
+ const TestApi::Binder& binder) = 0;
+ virtual void ClearBinderOverrides() = 0;
+ virtual void SetStartServiceCallback(
+ const StartServiceCallback& callback) = 0;
+ virtual void ResetStartServiceCallback() = 0;
};
} // namespace service_manager
diff --git a/chromium/services/service_manager/public/cpp/lib/connection_impl.cc b/chromium/services/service_manager/public/cpp/lib/connection_impl.cc
deleted file mode 100644
index bd4ca44913f..00000000000
--- a/chromium/services/service_manager/public/cpp/lib/connection_impl.cc
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "services/service_manager/public/cpp/lib/connection_impl.h"
-
-#include <stdint.h>
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/logging.h"
-#include "services/service_manager/public/cpp/connection.h"
-#include "services/service_manager/public/cpp/interface_binder.h"
-
-namespace service_manager {
-namespace internal {
-
-////////////////////////////////////////////////////////////////////////////////
-// ConnectionImpl, public:
-
-ConnectionImpl::ConnectionImpl()
- : weak_factory_(this) {}
-
-ConnectionImpl::ConnectionImpl(const Identity& remote, State initial_state)
- : remote_(remote),
- state_(initial_state),
- weak_factory_(this) {
-}
-
-ConnectionImpl::~ConnectionImpl() {}
-
-void ConnectionImpl::SetRemoteInterfaces(
- std::unique_ptr<InterfaceProvider> remote_interfaces) {
- remote_interfaces_owner_ = std::move(remote_interfaces);
- set_remote_interfaces(remote_interfaces_owner_.get());
-}
-
-service_manager::mojom::Connector::ConnectCallback
-ConnectionImpl::GetConnectCallback() {
- return base::Bind(&ConnectionImpl::OnConnectionCompleted,
- weak_factory_.GetWeakPtr());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ConnectionImpl, Connection implementation:
-
-const Identity& ConnectionImpl::GetRemoteIdentity() const {
- return remote_;
-}
-
-void ConnectionImpl::SetConnectionLostClosure(const base::Closure& handler) {
- remote_interfaces_->SetConnectionLostClosure(handler);
-}
-
-service_manager::mojom::ConnectResult ConnectionImpl::GetResult() const {
- return result_;
-}
-
-bool ConnectionImpl::IsPending() const {
- return state_ == State::PENDING;
-}
-
-void ConnectionImpl::AddConnectionCompletedClosure(
- const base::Closure& callback) {
- if (IsPending())
- connection_completed_callbacks_.push_back(callback);
- else
- callback.Run();
-}
-
-InterfaceProvider* ConnectionImpl::GetRemoteInterfaces() {
- return remote_interfaces_;
-}
-
-base::WeakPtr<Connection> ConnectionImpl::GetWeakPtr() {
- return weak_factory_.GetWeakPtr();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// ConnectionImpl, private:
-
-void ConnectionImpl::OnConnectionCompleted(
- service_manager::mojom::ConnectResult result,
- const std::string& target_user_id) {
- DCHECK(State::PENDING == state_);
-
- result_ = result;
- state_ = result_ == service_manager::mojom::ConnectResult::SUCCEEDED
- ? State::CONNECTED
- : State::DISCONNECTED;
- remote_.set_user_id(target_user_id);
- std::vector<base::Closure> callbacks;
- callbacks.swap(connection_completed_callbacks_);
- for (auto callback : callbacks)
- callback.Run();
-}
-
-} // namespace internal
-} // namespace service_manager
diff --git a/chromium/services/service_manager/public/cpp/lib/connection_impl.h b/chromium/services/service_manager/public/cpp/lib/connection_impl.h
deleted file mode 100644
index a1fabf52eba..00000000000
--- a/chromium/services/service_manager/public/cpp/lib/connection_impl.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
-#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
-
-#include <stdint.h>
-
-#include <set>
-#include <string>
-
-#include "base/callback.h"
-#include "mojo/public/cpp/bindings/binding.h"
-#include "services/service_manager/public/cpp/connection.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"
-
-namespace service_manager {
-namespace internal {
-
-// A ConnectionImpl represents each half of a connection between two
-// applications, allowing customization of which interfaces are published to the
-// other.
-class ConnectionImpl : public Connection {
- public:
- ConnectionImpl();
- ConnectionImpl(const Identity& remote, State initial_state);
- ~ConnectionImpl() override;
-
- // Sets the remote provider, transferring ownership to the ConnectionImpl.
- void SetRemoteInterfaces(
- std::unique_ptr<InterfaceProvider> remote_interfaces);
-
- // Sets the remote provider, without transferring ownership.
- void set_remote_interfaces(InterfaceProvider* remote_interfaces) {
- remote_interfaces_ = remote_interfaces;
- }
-
- service_manager::mojom::Connector::ConnectCallback GetConnectCallback();
-
- private:
- // Connection:
- const Identity& GetRemoteIdentity() const override;
- void SetConnectionLostClosure(const base::Closure& handler) override;
- service_manager::mojom::ConnectResult GetResult() const override;
- bool IsPending() const override;
- void AddConnectionCompletedClosure(const base::Closure& callback) override;
- InterfaceProvider* GetRemoteInterfaces() override;
- base::WeakPtr<Connection> GetWeakPtr() override;
-
- void OnConnectionCompleted(service_manager::mojom::ConnectResult result,
- const std::string& target_user_id);
-
- Identity remote_;
-
- State state_;
- service_manager::mojom::ConnectResult result_ =
- service_manager::mojom::ConnectResult::SUCCEEDED;
- std::vector<base::Closure> connection_completed_callbacks_;
-
- InterfaceProvider* remote_interfaces_ = nullptr;
-
- std::unique_ptr<InterfaceProvider> remote_interfaces_owner_;
-
- base::WeakPtrFactory<ConnectionImpl> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(ConnectionImpl);
-};
-
-} // namespace internal
-} // namespace service_manager
-
-#endif // SERVICES_SERVICE_MANAGER_PUBLIC_CPP_LIB_CONNECTION_IMPL_H_
diff --git a/chromium/services/service_manager/public/cpp/lib/connector_impl.cc b/chromium/services/service_manager/public/cpp/lib/connector_impl.cc
index b9c1811e03d..0040a320e8d 100644
--- a/chromium/services/service_manager/public/cpp/lib/connector_impl.cc
+++ b/chromium/services/service_manager/public/cpp/lib/connector_impl.cc
@@ -6,21 +6,16 @@
#include "base/memory/ptr_util.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/cpp/lib/connection_impl.h"
namespace service_manager {
-namespace {
-void EmptyBindCallback(mojom::ConnectResult, const std::string&) {}
-}
-
ConnectorImpl::ConnectorImpl(mojom::ConnectorPtrInfo unbound_state)
- : unbound_state_(std::move(unbound_state)) {
+ : unbound_state_(std::move(unbound_state)), weak_factory_(this) {
thread_checker_.DetachFromThread();
}
ConnectorImpl::ConnectorImpl(mojom::ConnectorPtr connector)
- : connector_(std::move(connector)) {
+ : connector_(std::move(connector)), weak_factory_(this) {
connector_.set_connection_error_handler(
base::Bind(&ConnectorImpl::OnConnectionError, base::Unretained(this)));
}
@@ -32,6 +27,17 @@ void ConnectorImpl::OnConnectionError() {
connector_.reset();
}
+void ConnectorImpl::StartService(const Identity& identity) {
+ if (BindConnectorIfNecessary())
+ connector_->StartService(identity,
+ base::Bind(&ConnectorImpl::StartServiceCallback,
+ weak_factory_.GetWeakPtr()));
+}
+
+void ConnectorImpl::StartService(const std::string& name) {
+ StartService(Identity(name, mojom::kInheritUserID));
+}
+
void ConnectorImpl::StartService(
const Identity& identity,
mojom::ServicePtr service,
@@ -40,33 +46,11 @@ void ConnectorImpl::StartService(
return;
DCHECK(service.is_bound() && pid_receiver_request.is_pending());
- connector_->StartService(identity,
- service.PassInterface().PassHandle(),
- std::move(pid_receiver_request));
-}
-
-std::unique_ptr<Connection> ConnectorImpl::Connect(const std::string& name) {
- return Connect(Identity(name, mojom::kInheritUserID));
-}
-
-std::unique_ptr<Connection> ConnectorImpl::Connect(const Identity& target) {
- if (!BindConnectorIfNecessary())
- return nullptr;
-
- DCHECK(thread_checker_.CalledOnValidThread());
-
- mojom::InterfaceProviderPtr remote_interfaces;
- mojom::InterfaceProviderRequest remote_request(&remote_interfaces);
- std::unique_ptr<internal::ConnectionImpl> connection(
- new internal::ConnectionImpl(target, Connection::State::PENDING));
- std::unique_ptr<InterfaceProvider> remote_interface_provider(
- new InterfaceProvider);
- remote_interface_provider->Bind(std::move(remote_interfaces));
- connection->SetRemoteInterfaces(std::move(remote_interface_provider));
-
- connector_->Connect(target, std::move(remote_request),
- connection->GetConnectCallback());
- return std::move(connection);
+ connector_->StartServiceWithProcess(
+ identity, service.PassInterface().PassHandle(),
+ std::move(pid_receiver_request),
+ base::Bind(&ConnectorImpl::StartServiceCallback,
+ weak_factory_.GetWeakPtr()));
}
void ConnectorImpl::BindInterface(
@@ -76,8 +60,18 @@ void ConnectorImpl::BindInterface(
if (!BindConnectorIfNecessary())
return;
+ auto service_overrides_iter = local_binder_overrides_.find(target.name());
+ 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()) {
+ override_iter->second.Run(std::move(interface_pipe));
+ return;
+ }
+ }
+
connector_->BindInterface(target, interface_name, std::move(interface_pipe),
- base::Bind(&EmptyBindCallback));
+ base::Bind(&ConnectorImpl::StartServiceCallback,
+ weak_factory_.GetWeakPtr()));
}
std::unique_ptr<Connector> ConnectorImpl::Clone() {
@@ -96,6 +90,29 @@ void ConnectorImpl::BindConnectorRequest(mojom::ConnectorRequest request) {
connector_->Clone(std::move(request));
}
+base::WeakPtr<Connector> ConnectorImpl::GetWeakPtr() {
+ return weak_factory_.GetWeakPtr();
+}
+
+void ConnectorImpl::OverrideBinderForTesting(const std::string& service_name,
+ const std::string& interface_name,
+ const TestApi::Binder& binder) {
+ local_binder_overrides_[service_name][interface_name] = binder;
+}
+
+void ConnectorImpl::ClearBinderOverrides() {
+ local_binder_overrides_.clear();
+}
+
+void ConnectorImpl::SetStartServiceCallback(
+ const Connector::StartServiceCallback& callback) {
+ start_service_callback_ = callback;
+}
+
+void ConnectorImpl::ResetStartServiceCallback() {
+ start_service_callback_.Reset();
+}
+
bool ConnectorImpl::BindConnectorIfNecessary() {
// Bind this object to the current thread the first time it is used to
// connect.
@@ -119,6 +136,12 @@ bool ConnectorImpl::BindConnectorIfNecessary() {
return true;
}
+void ConnectorImpl::StartServiceCallback(mojom::ConnectResult result,
+ const Identity& user_id) {
+ if (!start_service_callback_.is_null())
+ start_service_callback_.Run(result, user_id);
+}
+
std::unique_ptr<Connector> Connector::Create(mojom::ConnectorRequest* request) {
mojom::ConnectorPtr proxy;
*request = mojo::MakeRequest(&proxy);
diff --git a/chromium/services/service_manager/public/cpp/lib/connector_impl.h b/chromium/services/service_manager/public/cpp/lib/connector_impl.h
index 7c719a84809..b07fb2b4648 100644
--- a/chromium/services/service_manager/public/cpp/lib/connector_impl.h
+++ b/chromium/services/service_manager/public/cpp/lib/connector_impl.h
@@ -5,6 +5,7 @@
#ifndef SERVICES_SERVICE_MANAGER_PUBLIC_CPP_LIB_CONNECTOR_IMPL_H_
#define SERVICES_SERVICE_MANAGER_PUBLIC_CPP_LIB_CONNECTOR_IMPL_H_
+#include <map>
#include <memory>
#include "base/callback.h"
@@ -24,24 +25,42 @@ class ConnectorImpl : public Connector {
void OnConnectionError();
// Connector:
+ void StartService(const Identity& identity) override;
+ void StartService(const std::string& name) override;
void StartService(const Identity& identity,
mojom::ServicePtr service,
mojom::PIDReceiverRequest pid_receiver_request) override;
- std::unique_ptr<Connection> Connect(const std::string& name) override;
- std::unique_ptr<Connection> Connect(const Identity& target) override;
void BindInterface(const Identity& target,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override;
std::unique_ptr<Connector> Clone() override;
void BindConnectorRequest(mojom::ConnectorRequest request) override;
+ base::WeakPtr<Connector> GetWeakPtr() override;
+ void OverrideBinderForTesting(const std::string& service_name,
+ const std::string& interface_name,
+ const TestApi::Binder& binder) override;
+ void ClearBinderOverrides() override;
+ void SetStartServiceCallback(const StartServiceCallback& callback) override;
+ void ResetStartServiceCallback() override;
bool BindConnectorIfNecessary();
+ // Callback passed to mojom methods StartService()/BindInterface().
+ void StartServiceCallback(mojom::ConnectResult result,
+ const Identity& user_id);
+
+ using BinderOverrideMap = std::map<std::string, TestApi::Binder>;
+
mojom::ConnectorPtrInfo unbound_state_;
mojom::ConnectorPtr connector_;
base::ThreadChecker thread_checker_;
+ std::map<std::string, BinderOverrideMap> local_binder_overrides_;
+ Connector::StartServiceCallback start_service_callback_;
+
+ base::WeakPtrFactory<ConnectorImpl> weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(ConnectorImpl);
};
diff --git a/chromium/services/service_manager/public/cpp/lib/identity.cc b/chromium/services/service_manager/public/cpp/lib/identity.cc
index 4fa2ff2abbb..409bee11b6c 100644
--- a/chromium/services/service_manager/public/cpp/lib/identity.cc
+++ b/chromium/services/service_manager/public/cpp/lib/identity.cc
@@ -5,10 +5,11 @@
#include "services/service_manager/public/cpp/identity.h"
#include "base/guid.h"
+#include "services/service_manager/public/interfaces/connector.mojom.h"
namespace service_manager {
-Identity::Identity() {}
+Identity::Identity() : Identity("", mojom::kInheritUserID, "") {}
Identity::Identity(const std::string& name, const std::string& user_id)
: Identity(name, user_id, "") {}
diff --git a/chromium/services/service_manager/public/cpp/lib/interface_registry.cc b/chromium/services/service_manager/public/cpp/lib/interface_registry.cc
index 9fb605d8100..e74df3c7e67 100644
--- a/chromium/services/service_manager/public/cpp/lib/interface_registry.cc
+++ b/chromium/services/service_manager/public/cpp/lib/interface_registry.cc
@@ -9,7 +9,6 @@
#include "base/memory/ptr_util.h"
#include "mojo/public/cpp/bindings/message.h"
-#include "services/service_manager/public/cpp/connection.h"
namespace service_manager {
namespace {
diff --git a/chromium/services/service_manager/public/cpp/lib/service.cc b/chromium/services/service_manager/public/cpp/lib/service.cc
index 2b40a6c6813..b6a20a03b45 100644
--- a/chromium/services/service_manager/public/cpp/lib/service.cc
+++ b/chromium/services/service_manager/public/cpp/lib/service.cc
@@ -6,8 +6,6 @@
#include "base/logging.h"
#include "services/service_manager/public/cpp/service_context.h"
-#include "services/service_manager/public/interfaces/interface_provider.mojom.h"
-#include "services/service_manager/public/interfaces/interface_provider_spec.mojom.h"
namespace service_manager {
@@ -17,30 +15,9 @@ Service::~Service() = default;
void Service::OnStart() {}
-bool Service::OnConnect(const ServiceInfo& remote_info,
- InterfaceRegistry* registry) {
- return false;
-}
-
void Service::OnBindInterface(const ServiceInfo& source_info,
const std::string& interface_name,
- mojo::ScopedMessagePipeHandle interface_pipe) {
- // TODO(beng): Eliminate this implementation once everyone is migrated to
- // OnBindInterface().
- mojom::InterfaceProviderPtr interface_provider;
- InterfaceProviderSpec source_spec, target_spec;
- GetInterfaceProviderSpec(
- mojom::kServiceManager_ConnectorSpec,
- service_context_->local_info().interface_provider_specs,
- &target_spec);
- GetInterfaceProviderSpec(
- mojom::kServiceManager_ConnectorSpec,
- source_info.interface_provider_specs,
- &source_spec);
- service_context_->CallOnConnect(source_info, source_spec, target_spec,
- MakeRequest(&interface_provider));
- interface_provider->GetInterface(interface_name, std::move(interface_pipe));
-}
+ mojo::ScopedMessagePipeHandle interface_pipe) {}
bool Service::OnServiceManagerConnectionLost() {
return true;
@@ -64,11 +41,6 @@ void ForwardingService::OnStart() {
target_->OnStart();
}
-bool ForwardingService::OnConnect(const ServiceInfo& remote_info,
- InterfaceRegistry* registry) {
- return target_->OnConnect(remote_info, registry);
-}
-
void ForwardingService::OnBindInterface(
const ServiceInfo& remote_info,
const std::string& interface_name,
diff --git a/chromium/services/service_manager/public/cpp/lib/service_context.cc b/chromium/services/service_manager/public/cpp/lib/service_context.cc
index 64594597f96..0b53f8c7101 100644
--- a/chromium/services/service_manager/public/cpp/lib/service_context.cc
+++ b/chromium/services/service_manager/public/cpp/lib/service_context.cc
@@ -7,15 +7,8 @@
#include <utility>
#include "base/bind.h"
-#include "base/callback_helpers.h"
#include "base/logging.h"
-#include "base/memory/ptr_util.h"
-#include "base/message_loop/message_loop.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "mojo/public/cpp/bindings/interface_ptr.h"
#include "mojo/public/cpp/bindings/interface_request.h"
-#include "services/service_manager/public/cpp/interface_provider_spec.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
#include "services/service_manager/public/cpp/lib/connector_impl.h"
#include "services/service_manager/public/cpp/service.h"
@@ -88,22 +81,6 @@ void ServiceContext::OnStart(const ServiceInfo& info,
service_->OnStart();
}
-void ServiceContext::OnConnect(
- const ServiceInfo& source_info,
- mojom::InterfaceProviderRequest interfaces,
- const OnConnectCallback& callback) {
- InterfaceProviderSpec source_spec, target_spec;
- GetInterfaceProviderSpec(mojom::kServiceManager_ConnectorSpec,
- local_info_.interface_provider_specs, &target_spec);
- GetInterfaceProviderSpec(mojom::kServiceManager_ConnectorSpec,
- source_info.interface_provider_specs, &source_spec);
-
- // Acknowledge the request regardless of whether it's accepted.
- callback.Run();
-
- CallOnConnect(source_info, source_spec, target_spec, std::move(interfaces));
-}
-
void ServiceContext::OnBindInterface(
const ServiceInfo& source_info,
const std::string& interface_name,
@@ -119,26 +96,6 @@ void ServiceContext::OnBindInterface(
////////////////////////////////////////////////////////////////////////////////
// ServiceContext, private:
-void ServiceContext::CallOnConnect(const ServiceInfo& source_info,
- const InterfaceProviderSpec& source_spec,
- const InterfaceProviderSpec& target_spec,
- mojom::InterfaceProviderRequest interfaces) {
- auto registry =
- base::MakeUnique<InterfaceRegistry>(mojom::kServiceManager_ConnectorSpec);
- registry->Bind(std::move(interfaces), local_info_.identity, target_spec,
- source_info.identity, source_spec);
-
- if (!service_->OnConnect(source_info, registry.get()))
- return;
-
- InterfaceRegistry* raw_registry = registry.get();
- registry->AddConnectionLostClosure(base::Bind(
- &ServiceContext::OnRegistryConnectionError, base::Unretained(this),
- raw_registry));
- connection_interface_registries_.insert(
- std::make_pair(raw_registry, std::move(registry)));
-}
-
void ServiceContext::OnConnectionError() {
if (service_->OnServiceManagerConnectionLost()) {
// CAUTION: May delete |this|.
@@ -146,21 +103,4 @@ void ServiceContext::OnConnectionError() {
}
}
-void ServiceContext::OnRegistryConnectionError(InterfaceRegistry* registry) {
- // NOTE: We destroy the InterfaceRegistry asynchronously since it's calling
- // into us from its own connection error handler which may continue to access
- // the InterfaceRegistry's own state after we return.
- base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::Bind(&ServiceContext::DestroyConnectionInterfaceRegistry,
- weak_factory_.GetWeakPtr(), registry));
-}
-
-void ServiceContext::DestroyConnectionInterfaceRegistry(
- InterfaceRegistry* registry) {
- auto it = connection_interface_registries_.find(registry);
- CHECK(it != connection_interface_registries_.end());
- connection_interface_registries_.erase(it);
-}
-
} // namespace service_manager
diff --git a/chromium/services/service_manager/public/cpp/lib/service_test.cc b/chromium/services/service_manager/public/cpp/lib/service_test.cc
index 0c938f2b7a3..30fd49b12a3 100644
--- a/chromium/services/service_manager/public/cpp/lib/service_test.cc
+++ b/chromium/services/service_manager/public/cpp/lib/service_test.cc
@@ -27,11 +27,10 @@ void ServiceTestClient::OnStart() {
context()->identity().user_id());
}
-bool ServiceTestClient::OnConnect(const ServiceInfo& remote_info,
- InterfaceRegistry* registry) {
- return false;
-}
-
+void ServiceTestClient::OnBindInterface(
+ const ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {}
ServiceTest::ServiceTest() {}
@@ -89,8 +88,8 @@ void ServiceTest::SetUp() {
void ServiceTest::TearDown() {
background_service_manager_.reset();
- message_loop_.reset();
context_.reset();
+ message_loop_.reset();
}
} // namespace test
diff --git a/chromium/services/service_manager/public/cpp/service.h b/chromium/services/service_manager/public/cpp/service.h
index db5ad501705..9d0c04e856a 100644
--- a/chromium/services/service_manager/public/cpp/service.h
+++ b/chromium/services/service_manager/public/cpp/service.h
@@ -12,7 +12,6 @@
namespace service_manager {
-class InterfaceRegistry;
class ServiceContext;
struct ServiceInfo;
@@ -28,16 +27,6 @@ class Service {
// will be made before this.
virtual void OnStart();
- // Called each time a connection to this service is brokered by the Service
- // Manager. Implement this to expose interfaces to other services.
- //
- // Return true if the connection should succeed or false if the connection
- // should be rejected.
- //
- // The default implementation returns false.
- virtual bool OnConnect(const ServiceInfo& remote_info,
- InterfaceRegistry* registry);
-
// Called when the service identified by |source_info| requests this service
// bind a request for |interface_name|. If this method has been called, the
// service manager has already determined that policy permits this interface
@@ -89,8 +78,6 @@ class ForwardingService : public Service {
// Service:
void OnStart() override;
- bool OnConnect(const ServiceInfo& remote_info,
- InterfaceRegistry* registry) override;
void OnBindInterface(const ServiceInfo& remote_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override;
diff --git a/chromium/services/service_manager/public/cpp/service_context.h b/chromium/services/service_manager/public/cpp/service_context.h
index f843462bbc7..8cfea216708 100644
--- a/chromium/services/service_manager/public/cpp/service_context.h
+++ b/chromium/services/service_manager/public/cpp/service_context.h
@@ -108,33 +108,16 @@ class ServiceContext : public mojom::Service {
private:
friend class service_manager::Service;
- using InterfaceRegistryMap =
- std::map<InterfaceRegistry*, std::unique_ptr<InterfaceRegistry>>;
-
// mojom::Service:
void OnStart(const ServiceInfo& info,
const OnStartCallback& callback) override;
- void OnConnect(const ServiceInfo& source_info,
- mojom::InterfaceProviderRequest interfaces,
- const OnConnectCallback& callback) override;
void OnBindInterface(
const ServiceInfo& source_info,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe,
const OnBindInterfaceCallback& callback) override;
- void CallOnConnect(const ServiceInfo& source_info,
- const InterfaceProviderSpec& source_spec,
- const InterfaceProviderSpec& target_spec,
- mojom::InterfaceProviderRequest request);
-
void OnConnectionError();
- void OnRegistryConnectionError(InterfaceRegistry* registry);
- void DestroyConnectionInterfaceRegistry(InterfaceRegistry* registry);
-
- // We track the lifetime of incoming connection registries as a convenience
- // for the client.
- InterfaceRegistryMap connection_interface_registries_;
// A pending Connector request which will eventually be passed to the Service
// Manager.
diff --git a/chromium/services/service_manager/public/cpp/service_test.h b/chromium/services/service_manager/public/cpp/service_test.h
index 1ee7b9a9dca..a4bfc74206b 100644
--- a/chromium/services/service_manager/public/cpp/service_test.h
+++ b/chromium/services/service_manager/public/cpp/service_test.h
@@ -43,8 +43,9 @@ class ServiceTestClient : public Service {
protected:
void OnStart() override;
- bool OnConnect(const ServiceInfo& remote_info,
- InterfaceRegistry* registry) override;
+ void OnBindInterface(const ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
private:
ServiceTest* test_;
diff --git a/chromium/services/service_manager/public/cpp/test/BUILD.gn b/chromium/services/service_manager/public/cpp/test/BUILD.gn
index c1adadf217f..c1697a3db02 100644
--- a/chromium/services/service_manager/public/cpp/test/BUILD.gn
+++ b/chromium/services/service_manager/public/cpp/test/BUILD.gn
@@ -21,4 +21,8 @@ source_set("run_all_service_tests") {
"//services/catalog:lib",
"//services/service_manager/background:lib",
]
+
+ if (is_android) {
+ deps += [ "//mojo/android:libsystem_java" ]
+ }
}
diff --git a/chromium/services/service_manager/public/interfaces/connector.mojom b/chromium/services/service_manager/public/interfaces/connector.mojom
index 3c759cbbe91..63168e4a15a 100644
--- a/chromium/services/service_manager/public/interfaces/connector.mojom
+++ b/chromium/services/service_manager/public/interfaces/connector.mojom
@@ -6,50 +6,51 @@ module service_manager.mojom;
import "services/service_manager/public/interfaces/interface_provider.mojom";
+// TODO(beng): Determine who (if anyone) uses kRootUserID.
const string kRootUserID = "505C0EE9-3013-43C0-82B0-A84F50CF8D84";
const string kInheritUserID = "D26290E4-4485-4EAE-81A2-66D1EEB40A9D";
const uint32 kInvalidInstanceID = 0;
+// TODO(beng): Evalute the utility of this enum. There are some inconsistencies
+// in its use with BindInterface/StartService.
enum ConnectResult {
- // The connection was established successfully.
+ // The operation was established successfully.
SUCCEEDED,
// The name or user id supplied was malformed, or the service specified by
// |name| could not be loaded.
INVALID_ARGUMENT,
- // The connection was blocked by policy. Either connections to |name| are
- // forbidden from this app by the CapabilityFilter, or the service attempted
- // to connect using a user id other than its own, |kInheritUserID| or
- // |kRootUserID|.
+ // Policy prevented the successful completion of this operation. Either
+ // requests to bind to |name| are forbidden from the calling service by its
+ // manifest, or the service attempted to connect using a user id other than
+ // its own, |kInheritUserID| or |kRootUserID|.
ACCESS_DENIED
};
// A collection of metadata that disambiguates instances in the service manager.
struct Identity {
- // A service: or exe: name identifying a service.
+ // A name identifying a service.
string name;
- // The user id of the target service instance to connect to. If no such
- // instance exists, the service manager may start one. This user id will be
- // passed to the new instance via Initialize().
- //
- // When connecting to other services, services must generally pass
- // kInheritUserID for this value, and the service manager will either connect
- // to an existing instance matching the caller's user id, create a new
- // instance matching the caller's user id, or connect to an existing instance
- // running as kRootUserID. By default, services do not have the ability to set
- // arbitrary values to this field, and doing so will result in a connection
- // error on the remote service provider.
+ // The user id of the target service instance to bind to. If no such instance
+ // exists, the service manager may start one. This user id will be passed to
+ // the new instance via Initialize().
+ //
+ // When binding to other services, services must generally pass kInheritUserID
+ // for this value, and the service manager will either bind to an existing
+ // instance matching the caller's user id, create a new instance matching the
+ // caller's user id, or bind to an existing instance running as kRootUserID.
+ // By default, services do not have the ability to set arbitrary values to
+ // this field, and doing so will result in an error response.
//
// A service with the ability to launch other services with arbitrary user ids
- // (e.g. a login service) may set this value to something meaningful to it.
- // The user id string is a valid guid of the form
- // "%08X-%04X-%04X-%04X-%012llX", and (aside from the root user whose
- // guid is defined above) intended to be not-guessable.
+ // (e.g. a login service) may set this value. The user id string is a valid
+ // guid of the form "%08X-%04X-%04X-%04X-%012llX", and (aside from the root
+ // user whose guid is defined above) intended to be not-guessable.
//
- // When a service is initialized or receives a connection from another
+ // When a service is initialized or receives a bind request from another
// service, this value is always the resolved user id, never |kInheritUserID|.
string user_id;
@@ -67,76 +68,99 @@ interface PIDReceiver {
SetPID(uint32 pid);
};
-// Encapsulates establishing connections with other Services.
+// An interface that allows the holder to start other services & bind to
+// interfaces exposed by them.
interface Connector {
- // Typically, the service manager will start a process for a service the first
- // time it receives a connection request for it. This struct allows a client
- // to start the process itself and provide the service manager the pipes it
- // needs to communicate with it. When this function is called, the client owns
- // the lifetime of the child process it started, not the service manager. The
- // service manager binds the |service| pipe, and when it closes destroys the
- // associated instance but the process stays alive.
+ // Asks the service manager to route a request to bind an implementation of
+ // the interface to a named service instance.
+ //
+ // A service's ability to bind interfaces exposed by another is controlled by
+ // policy set out in each service's manifest. See
+ // //services/service_manager/README.md for more information on manifests.
+ // If policy prevents the requesting service from binding the specified
+ // interface, the request pipe will be closed.
//
// Parameters:
//
- // service
- // A pipe to an implementation of Service that the service manager can use
- // to communicate with the service.
+ // target
+ // The identity of the service instance to route the request to. If no
+ // instance exists, the service will be started.
//
- // pid_receiver_request
- // Allows the client process launcher to tell the service manager the PID of
- // the process it created (the pid isn't supplied directly here as the
- // process may not have been launched by the time Connect() is called.)
+ // interface_name
+ // The name of the interface to be bound. If the target service does not
+ // expose an interface of this name, the request pipe will be closed.
//
- StartService(Identity name,
- handle<message_pipe> service,
- PIDReceiver& pid_receiver_request);
-
- // Requests a connection with another service. The service originating the
- // request is referred to as the "source" and the one receiving the "target".
+ // interface_pipe
+ // A message pipe endpoint encapsulating a request for an interface named
+ // |interface_name|.
+ //
+ // Response parameters:
+ //
+ // result
+ // Indicates the result of the BindInterface() operation.
//
- // The connection is embodied by a pair of message pipes binding the
- // InterfaceProvider interface, which allows both the source and target
- // services to export interfaces to one another. The interfaces bound via
- // these InterfaceProviders are brokered by the service manager according to
- // the security policy defined by each service in its manifest.
+ // identity
+ // The fully resolved identity of the instance in the service manager, with
+ // a resolved user id. Typically the client passes |kInheritUserID| as the
+ // user id to BindInterface(), which will be resolved by the service
+ // manager into a concrete user id.
//
- // If the target service is not running, the service manager will run it,
- // calling its OnStart() method before completing the connection.
+ BindInterface(Identity target,
+ string interface_name,
+ handle<message_pipe> interface_pipe) =>
+ (ConnectResult result, Identity user_id);
+
+ // Asks the service manager to create an instance for a service. No action is
+ // taken if an instance is already present. If the service is not yet running,
+ // it will be initialized and its OnStart() method will be called. A process
+ // may be allocated.
//
// Parameters:
//
// target
- // Identifies the target service instance to connect to.
- //
- // remote_interfaces
- // Allows the source service access to interface implementations exposed by
- // the target service. The interfaces accessible via this InterfaceProvider
- // are filtered by the security policy described by the source and target
- // service manifests.
+ // The identity of the service to start.
//
// Response parameters:
//
// result
- // Indicates the result of the Connect() operation.
+ // Indicates the result of the StartService() operation.
//
- // user_id
- // The user id the service manager ran the target service as. Typically a
- // client passes |kInheritUserID| as the user id to Connect(), which is
- // resolved by the service manager into a valid user id returned through
- // this callback.
+ // identity
+ // The fully resolved identity of the instance in the service manager, with
+ // a resolved user id. Typically the client passes |kInheritUserID| as the
+ // user id to BindInterface(), which will be resolved by the service
+ // manager into a concrete user id.
//
- Connect(Identity target, InterfaceProvider&? remote_interfaces) =>
- (ConnectResult result, string user_id);
+ StartService(Identity target) => (ConnectResult result, Identity identity);
- // Variant of Connect() above. Will (gradually) replace it. Think of this like
- // a combination of Connect() and InterfaceProvider::GetInteface() - requests
- // a connection to a service and binds an interface in one step.
- // TODO(beng): Update this comment once the implementation is complete.
- BindInterface(Identity target,
- string interface_name,
- handle<message_pipe> interface_pipe) =>
- (ConnectResult result, string user_id);
+ // Typically, the service manager will start a process for a service the first
+ // time it receives a bind interface request for it, or when StartService() is
+ // called. This struct allows a client to start the process itself and provide
+ // the service manager the pipes it needs to communicate with it. When this
+ // function is called, the client owns the lifetime of the child process it
+ // started, not the service manager. The service manager binds the |service|
+ // pipe, and when it closes destroys the associated instance but the process
+ // stays alive.
+ //
+ // Parameters:
+ //
+ // target
+ // The identity of the service to create the instance for.
+ //
+ // service
+ // A pipe to an implementation of Service that the service manager can use
+ // to communicate with the service.
+ //
+ // pid_receiver_request
+ // Allows the client process launcher to tell the service manager the PID of
+ // the process it created (the pid isn't supplied directly here as the
+ // process may not have been launched by the time BindInterface() is
+ // called.)
+ //
+ StartServiceWithProcess(Identity target,
+ handle<message_pipe> service,
+ PIDReceiver& pid_receiver_request) =>
+ (ConnectResult result, Identity identity);
// Clones this Connector so it can be passed to another thread.
Clone(Connector& request);
diff --git a/chromium/services/service_manager/public/interfaces/service.mojom b/chromium/services/service_manager/public/interfaces/service.mojom
index 207da8cd96e..a0f14f46a38 100644
--- a/chromium/services/service_manager/public/interfaces/service.mojom
+++ b/chromium/services/service_manager/public/interfaces/service.mojom
@@ -48,26 +48,6 @@ interface Service {
OnStart(ServiceInfo info) => (Connector&? connector_request,
associated ServiceControl&? control_request);
- // Called when another service attempts to open a connection to this
- // service. A service implements this method to complete the exchange
- // of interface implementations with the remote service. See also
- // documentation in service_manager.mojom for Connect(). The service
- // originating the request is referred to as the "source" and the one
- // receiving the "target".
- //
- // The Service must respond to acknowledge receipt of the request.
- //
- // Parameters:
- //
- // source_info
- // Contains the source identity and interface provider specs.
- //
- // interfaces
- // A request for an InterfaceProvider by which the source service may
- // seek to bind interface implementations exported by the target.
- //
- OnConnect(ServiceInfo source_info, InterfaceProvider&? interfaces) => ();
-
// Called when a request to bind an interface is received from another
// ("source") service. This is the result of that service calling
// BindInterface() on a Connector. By the time this method is called, the
@@ -91,7 +71,6 @@ interface Service {
// the source's capability requirements to the target. This seems
// undesirable. The metadata supplied here should be germane to
// fulfilling this request and no more.
- // TODO(beng): This should replace OnConnect().
OnBindInterface(ServiceInfo source_info,
string interface_name,
handle<message_pipe> interface_pipe) => ();
diff --git a/chromium/services/service_manager/public/java/BUILD.gn b/chromium/services/service_manager/public/java/BUILD.gn
index 4d09091ce8f..a1af30194ea 100644
--- a/chromium/services/service_manager/public/java/BUILD.gn
+++ b/chromium/services/service_manager/public/java/BUILD.gn
@@ -7,6 +7,7 @@ import("//build/config/android/rules.gni")
android_library("service_manager_java") {
java_files = [
"src/org/chromium/services/service_manager/InterfaceFactory.java",
+ "src/org/chromium/services/service_manager/InterfaceProvider.java",
"src/org/chromium/services/service_manager/InterfaceRegistry.java",
]
deps = [
diff --git a/chromium/services/service_manager/public/tools/test/service_test.gni b/chromium/services/service_manager/public/tools/test/service_test.gni
index dd36135838c..91369833df7 100644
--- a/chromium/services/service_manager/public/tools/test/service_test.gni
+++ b/chromium/services/service_manager/public/tools/test/service_test.gni
@@ -31,6 +31,7 @@ template("service_test") {
}
catalog_cpp_source(catalog_source_target) {
+ testonly = true
catalog = invoker.catalog
generated_function_name = "service_manager::test::CreateTestCatalog"
}
diff --git a/chromium/services/service_manager/runner/host/service_process_launcher.cc b/chromium/services/service_manager/runner/host/service_process_launcher.cc
index 759df006481..52077bbb9c8 100644
--- a/chromium/services/service_manager/runner/host/service_process_launcher.cc
+++ b/chromium/services/service_manager/runner/host/service_process_launcher.cc
@@ -189,15 +189,23 @@ void ServiceProcessLauncher::DoLaunch(
}
if (child_process_.IsValid()) {
- DVLOG(0) << "Launched child process pid=" << child_process_.Pid()
- << ", instance=" << target_.instance()
- << ", name=" << target_.name()
- << ", user_id=" << target_.user_id();
+#if defined(OS_CHROMEOS)
+ // Always log instead of DVLOG because knowing which pid maps to which
+ // service is vital for interpreting crashes after-the-fact and Chrome OS
+ // devices generally run release builds, even in development.
+ VLOG(0)
+#else
+ DVLOG(0)
+#endif
+ << "Launched child process pid=" << child_process_.Pid()
+ << ", instance=" << target_.instance() << ", name=" << target_.name()
+ << ", user_id=" << target_.user_id();
if (mojo_ipc_channel_.get()) {
mojo_ipc_channel_->ChildProcessLaunched();
- process_connection_.Connect(child_process_.Handle(),
- mojo_ipc_channel_->PassServerHandle());
+ process_connection_.Connect(
+ child_process_.Handle(),
+ mojo::edk::ConnectionParams(mojo_ipc_channel_->PassServerHandle()));
}
}
start_child_process_event_.Signal();
diff --git a/chromium/services/service_manager/service_manager.cc b/chromium/services/service_manager/service_manager.cc
index 99b9869ee5b..d29b0c9ad96 100644
--- a/chromium/services/service_manager/service_manager.cc
+++ b/chromium/services/service_manager/service_manager.cc
@@ -51,30 +51,6 @@ bool Succeeded(mojom::ConnectResult result) {
return result == mojom::ConnectResult::SUCCEEDED;
}
-bool RunConnectCallback(ConnectParams* params,
- mojom::ConnectResult result,
- const std::string& user_id) {
- if (!params->connect_callback().is_null()) {
- params->connect_callback().Run(result, user_id);
- return true;
- }
- return false;
-}
-
-void RunBindInterfaceCallback(ConnectParams* params,
- mojom::ConnectResult result,
- const std::string& user_id) {
- if (!params->bind_interface_callback().is_null())
- params->bind_interface_callback().Run(result, user_id);
-}
-
-void RunCallback(ConnectParams* params,
- mojom::ConnectResult result,
- const std::string& user_id) {
- if (!RunConnectCallback(params, result, user_id))
- RunBindInterfaceCallback(params, result, user_id);
-}
-
} // namespace
Identity CreateServiceManagerIdentity() {
@@ -107,7 +83,6 @@ class ServiceManager::Instance
: public mojom::Connector,
public mojom::PIDReceiver,
public Service,
- public InterfaceFactory<mojom::ServiceManager>,
public mojom::ServiceManager,
public mojom::ServiceControl {
public:
@@ -153,36 +128,10 @@ class ServiceManager::Instance
Stop();
}
- bool CallOnConnect(std::unique_ptr<ConnectParams>* in_params) {
- if (!service_.is_bound()) {
- RunConnectCallback(in_params->get(), mojom::ConnectResult::ACCESS_DENIED,
- identity_.user_id());
- return false;
- }
-
- std::unique_ptr<ConnectParams> params(std::move(*in_params));
- RunConnectCallback(params.get(), mojom::ConnectResult::SUCCEEDED,
- identity_.user_id());
-
- InterfaceProviderSpecMap specs;
- Instance* source =
- service_manager_->GetExistingInstance(params->source());
- if (source)
- specs = source->interface_provider_specs_;
-
- pending_service_connections_++;
- service_->OnConnect(ServiceInfo(params->source(), specs),
- params->TakeRemoteInterfaces(),
- base::Bind(&Instance::OnConnectComplete,
- base::Unretained(this)));
- return true;
- }
-
bool CallOnBindInterface(std::unique_ptr<ConnectParams>* in_params) {
if (!service_.is_bound()) {
- RunBindInterfaceCallback(in_params->get(),
- mojom::ConnectResult::ACCESS_DENIED,
- identity_.user_id());
+ (*in_params)
+ ->set_response_data(mojom::ConnectResult::ACCESS_DENIED, identity_);
return false;
}
@@ -207,13 +156,11 @@ class ServiceManager::Instance
<< params->source().name() << " from binding interface: "
<< params->interface_name() << " exposed by: " << identity_.name();
LOG(ERROR) << ss.str();
- params->bind_interface_callback().Run(mojom::ConnectResult::ACCESS_DENIED,
- identity_.user_id());
+ params->set_response_data(mojom::ConnectResult::ACCESS_DENIED, identity_);
return false;
}
- params->bind_interface_callback().Run(mojom::ConnectResult::SUCCEEDED,
- identity_.user_id());
+ params->set_response_data(mojom::ConnectResult::SUCCEEDED, identity_);
pending_service_connections_++;
service_->OnBindInterface(
@@ -277,17 +224,19 @@ class ServiceManager::Instance
uint32_t id() const { return id_; }
// Service:
- bool OnConnect(const ServiceInfo& remote_info,
- InterfaceRegistry* registry) override {
+ void OnBindInterface(const ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
Instance* source =
- service_manager_->GetExistingInstance(remote_info.identity);
+ service_manager_->GetExistingInstance(source_info.identity);
DCHECK(source);
- if (HasCapability(source->GetConnectionSpec(),
+ if (interface_name == mojom::ServiceManager::Name_ &&
+ HasCapability(source->GetConnectionSpec(),
kCapability_ServiceManager)) {
- registry->AddInterface<mojom::ServiceManager>(this);
- return true;
+ mojom::ServiceManagerRequest request =
+ mojo::MakeRequest<mojom::ServiceManager>(std::move(interface_pipe));
+ service_manager_bindings_.AddBinding(this, std::move(request));
}
- return false;
}
private:
@@ -304,65 +253,67 @@ class ServiceManager::Instance
};
// mojom::Connector implementation:
- void StartService(
- const Identity& in_target,
- mojo::ScopedMessagePipeHandle service_handle,
- mojom::PIDReceiverRequest pid_receiver_request) override {
- Identity target = in_target;
- mojom::ConnectResult result =
- ValidateConnectParams(&target, nullptr, nullptr);
- if (!Succeeded(result))
- return;
-
- std::unique_ptr<ConnectParams> params(new ConnectParams);
- params->set_source(identity_);
- params->set_target(target);
-
- mojom::ServicePtr service;
- service.Bind(mojom::ServicePtrInfo(std::move(service_handle), 0));
- params->set_client_process_info(std::move(service),
- std::move(pid_receiver_request));
- service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
- }
-
- void Connect(const service_manager::Identity& in_target,
- mojom::InterfaceProviderRequest remote_interfaces,
- const ConnectCallback& callback) override {
- Identity target = in_target;
- mojom::ConnectResult result =
- ValidateConnectParams(&target, nullptr, nullptr);
- if (!Succeeded(result)) {
- callback.Run(result, mojom::kInheritUserID);
- return;
- }
-
- std::unique_ptr<ConnectParams> params(new ConnectParams);
- params->set_source(identity_);
- params->set_target(target);
- params->set_remote_interfaces(std::move(remote_interfaces));
- params->set_connect_callback(callback);
- service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
- }
-
- void BindInterface(const service_manager::Identity& in_target,
- const std::string& interface_name,
- mojo::ScopedMessagePipeHandle interface_pipe,
- const BindInterfaceCallback& callback) override {
- Identity target = in_target;
- mojom::ConnectResult result =
- ValidateConnectParams(&target, nullptr, nullptr);
- if (!Succeeded(result)) {
- callback.Run(result, mojom::kInheritUserID);
- return;
- }
-
- std::unique_ptr<ConnectParams> params(new ConnectParams);
- params->set_source(identity_);
- params->set_target(target);
- params->set_interface_request_info(interface_name,
- std::move(interface_pipe));
- params->set_bind_interface_callback(callback);
- service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
+ void BindInterface(const service_manager::Identity& in_target,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe,
+ const BindInterfaceCallback& callback) override {
+ Identity target = in_target;
+ mojom::ConnectResult result =
+ ValidateConnectParams(&target, nullptr, nullptr);
+ if (!Succeeded(result)) {
+ callback.Run(result, Identity());
+ return;
+ }
+
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+ params->set_source(identity_);
+ params->set_target(target);
+ params->set_interface_request_info(interface_name,
+ std::move(interface_pipe));
+ params->set_start_service_callback(callback);
+ service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
+ }
+
+ void StartService(const Identity& in_target,
+ const StartServiceCallback& callback) override {
+ Identity target = in_target;
+ mojom::ConnectResult result =
+ ValidateConnectParams(&target, nullptr, nullptr);
+ if (!Succeeded(result)) {
+ callback.Run(result, Identity());
+ return;
+ }
+
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+ params->set_source(identity_);
+ params->set_target(target);
+ params->set_start_service_callback(callback);
+ service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
+ }
+
+ void StartServiceWithProcess(
+ const Identity& in_target,
+ mojo::ScopedMessagePipeHandle service_handle,
+ mojom::PIDReceiverRequest pid_receiver_request,
+ const StartServiceWithProcessCallback& callback) override {
+ Identity target = in_target;
+ mojom::ConnectResult result =
+ ValidateConnectParams(&target, nullptr, nullptr);
+ if (!Succeeded(result)) {
+ callback.Run(result, Identity());
+ return;
+ }
+
+ std::unique_ptr<ConnectParams> params(new ConnectParams);
+ params->set_source(identity_);
+ params->set_target(target);
+
+ mojom::ServicePtr service;
+ service.Bind(mojom::ServicePtrInfo(std::move(service_handle), 0));
+ params->set_client_process_info(std::move(service),
+ std::move(pid_receiver_request));
+ params->set_start_service_callback(callback);
+ service_manager_->Connect(std::move(params), weak_factory_.GetWeakPtr());
}
void Clone(mojom::ConnectorRequest request) override {
@@ -374,12 +325,6 @@ class ServiceManager::Instance
PIDAvailable(pid);
}
- // InterfaceFactory<mojom::ServiceManager>:
- void Create(const Identity& remote_identity,
- mojom::ServiceManagerRequest request) override {
- service_manager_bindings_.AddBinding(this, std::move(request));
- }
-
// mojom::ServiceManager implementation:
void AddListener(mojom::ServiceManagerListenerPtr listener) override {
// TODO(beng): this should only track the instances matching this user, and
@@ -536,14 +481,6 @@ class ServiceManager::Instance
OnServiceLost(service_manager_->GetWeakPtr());
}
- void EmptyConnectCallback(mojom::ConnectResult result,
- const std::string& user_id) {}
- void BindCallbackWrapper(const BindInterfaceCallback& wrapped,
- mojom::ConnectResult result,
- const std::string& user_id) {
- wrapped.Run(result, user_id);
- }
-
service_manager::ServiceManager* const service_manager_;
// An id that identifies this instance. Distinct from pid, as a single process
@@ -563,7 +500,7 @@ class ServiceManager::Instance
base::ProcessId pid_ = base::kNullProcessId;
State state_;
- // The number of outstanding OnConnect requests which are in flight.
+ // The number of outstanding OnBindInterface requests which are in flight.
int pending_service_connections_ = 0;
base::WeakPtrFactory<Instance> weak_factory_;
@@ -578,22 +515,24 @@ class ServiceManager::ServiceImpl : public Service {
~ServiceImpl() override {}
// Service:
- bool OnConnect(const ServiceInfo& remote_info,
- InterfaceRegistry* registry) override {
+ void OnBindInterface(const ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
// The only interface ServiceManager exposes is mojom::ServiceManager, and
// access to this interface is brokered by a policy specific to each caller,
// managed by the caller's instance. Here we look to see who's calling,
// and forward to the caller's instance to continue.
Instance* instance = nullptr;
for (const auto& entry : service_manager_->identity_to_instance_) {
- if (entry.first == remote_info.identity) {
+ if (entry.first == source_info.identity) {
instance = entry.second;
break;
}
}
DCHECK(instance);
- return instance->OnConnect(remote_info, registry);
+ instance->OnBindInterface(source_info, interface_name,
+ std::move(interface_pipe));
}
private:
@@ -853,14 +792,12 @@ void ServiceManager::NotifyServiceFailedToStart(const Identity& identity) {
bool ServiceManager::ConnectToExistingInstance(
std::unique_ptr<ConnectParams>* params) {
Instance* instance = GetExistingInstance((*params)->target());
- if (instance) {
- if ((*params)->HasInterfaceRequestInfo()) {
- instance->CallOnBindInterface(params);
- return true;
- }
- return instance->CallOnConnect(params);
- }
- return false;
+ if (!instance)
+ return false;
+
+ if ((*params)->HasInterfaceRequestInfo())
+ instance->CallOnBindInterface(params);
+ return true;
}
ServiceManager::Instance* ServiceManager::CreateInstance(
@@ -945,7 +882,8 @@ void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params,
// If name resolution failed, we drop the connection.
if (!result) {
LOG(ERROR) << "Failed to resolve service name: " << params->target().name();
- RunCallback(params.get(), mojom::ConnectResult::INVALID_ARGUMENT, "");
+ params->set_response_data(mojom::ConnectResult::INVALID_ARGUMENT,
+ Identity());
return;
}
@@ -1012,7 +950,8 @@ void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params,
LOG(ERROR)
<< "Error: The catalog was unable to read a manifest for service \""
<< result->name << "\".";
- RunCallback(params.get(), mojom::ConnectResult::ACCESS_DENIED, "");
+ params->set_response_data(mojom::ConnectResult::ACCESS_DENIED,
+ Identity());
return;
}
@@ -1050,19 +989,17 @@ void ServiceManager::OnGotResolvedName(std::unique_ptr<ConnectParams> params,
if (!instance->StartWithFilePath(package_path)) {
OnInstanceError(instance);
- RunCallback(params.get(), mojom::ConnectResult::INVALID_ARGUMENT, "");
+ params->set_response_data(mojom::ConnectResult::INVALID_ARGUMENT,
+ Identity());
return;
}
}
}
- // Now that the instance has a Service, we can connect to it.
- if (params->HasInterfaceRequestInfo()) {
+ params->set_response_data(mojom::ConnectResult::SUCCEEDED,
+ instance->identity());
+ if (params->HasInterfaceRequestInfo())
instance->CallOnBindInterface(&params);
- } else {
- bool connected = instance->CallOnConnect(&params);
- DCHECK(connected);
- }
}
base::WeakPtr<ServiceManager> ServiceManager::GetWeakPtr() {
diff --git a/chromium/services/service_manager/service_manager.h b/chromium/services/service_manager/service_manager.h
index 94c79e430e1..3596d8ef8f6 100644
--- a/chromium/services/service_manager/service_manager.h
+++ b/chromium/services/service_manager/service_manager.h
@@ -15,7 +15,6 @@
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "services/service_manager/connect_params.h"
#include "services/service_manager/public/cpp/identity.h"
-#include "services/service_manager/public/cpp/interface_factory.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"
@@ -189,8 +188,6 @@ class ServiceManager {
DISALLOW_COPY_AND_ASSIGN(ServiceManager);
};
-mojom::Connector::ConnectCallback EmptyConnectCallback();
-
} // namespace service_manager
#endif // SERVICES_SERVICE_MANAGER_SERVICE_MANAGER_H_
diff --git a/chromium/services/service_manager/standalone/context.cc b/chromium/services/service_manager/standalone/context.cc
index 5b38d52888e..998603612d1 100644
--- a/chromium/services/service_manager/standalone/context.cc
+++ b/chromium/services/service_manager/standalone/context.cc
@@ -156,13 +156,9 @@ void Context::RunCommandLineApplication() {
void Context::Run(const std::string& name) {
service_manager_->SetInstanceQuitCallback(base::Bind(&OnInstanceQuit, name));
- mojom::InterfaceProviderPtr remote_interfaces;
- mojom::InterfaceProviderPtr local_interfaces;
-
std::unique_ptr<ConnectParams> params(new ConnectParams);
params->set_source(CreateServiceManagerIdentity());
params->set_target(Identity(name, mojom::kRootUserID));
- params->set_remote_interfaces(mojo::MakeRequest(&remote_interfaces));
service_manager_->Connect(std::move(params));
}
diff --git a/chromium/services/shape_detection/BUILD.gn b/chromium/services/shape_detection/BUILD.gn
index e4d401d46b4..9a2ddbd6170 100644
--- a/chromium/services/shape_detection/BUILD.gn
+++ b/chromium/services/shape_detection/BUILD.gn
@@ -12,6 +12,7 @@ source_set("lib") {
"face_detection_provider_impl.h",
"shape_detection_service.cc",
"shape_detection_service.h",
+ "text_detection_impl.h",
]
if (is_mac) {
@@ -22,12 +23,15 @@ source_set("lib") {
"detection_utils_mac.mm",
"face_detection_impl_mac.h",
"face_detection_impl_mac.mm",
+ "text_detection_impl_mac.h",
+ "text_detection_impl_mac.mm",
]
libs = [ "QuartzCore.framework" ]
} else {
sources += [
"barcode_detection_impl.cc",
"face_detection_provider_impl.cc",
+ "text_detection_impl.cc",
]
}
@@ -57,6 +61,7 @@ source_set("tests") {
sources += [
"barcode_detection_impl_mac_unittest.mm",
"face_detection_impl_mac_unittest.mm",
+ "text_detection_impl_mac_unittest.mm",
]
libs = [
diff --git a/chromium/services/shape_detection/OWNERS b/chromium/services/shape_detection/OWNERS
new file mode 100644
index 00000000000..26e1bed754e
--- /dev/null
+++ b/chromium/services/shape_detection/OWNERS
@@ -0,0 +1,5 @@
+mcasas@chromium.org
+reillyg@chromium.org
+
+# COMPONENT: Blink>ImageCapture
+# TEAM: device-dev@chromium.org
diff --git a/chromium/services/shape_detection/manifest.json b/chromium/services/shape_detection/manifest.json
index b92fb5cbb25..542148e79f4 100644
--- a/chromium/services/shape_detection/manifest.json
+++ b/chromium/services/shape_detection/manifest.json
@@ -5,7 +5,8 @@
"service_manager:connector": {
"provides": {
"face_detection": [ "shape_detection::mojom::FaceDetectionProvider" ],
- "barcode_detection": [ "shape_detection::mojom::BarcodeDetection" ]
+ "barcode_detection": [ "shape_detection::mojom::BarcodeDetection" ],
+ "text_detection": [ "shape_detection::mojom::TextDetection" ]
},
"requires": {
"service_manager": [ "service_manager:all_users" ]
diff --git a/chromium/services/shape_detection/shape_detection_service.cc b/chromium/services/shape_detection/shape_detection_service.cc
index c2375168d4b..6891d4a672c 100644
--- a/chromium/services/shape_detection/shape_detection_service.cc
+++ b/chromium/services/shape_detection/shape_detection_service.cc
@@ -5,21 +5,13 @@
#include "services/shape_detection/shape_detection_service.h"
#include "base/macros.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
#include "services/shape_detection/barcode_detection_impl.h"
#include "services/shape_detection/face_detection_provider_impl.h"
+#include "services/shape_detection/text_detection_impl.h"
namespace shape_detection {
-namespace {
-
-void OnConnectionLost(std::unique_ptr<service_manager::ServiceContextRef> ref) {
- // No-op. This merely takes ownership of |ref| so it can be destroyed when
- // this function is invoked.
-}
-}
-
std::unique_ptr<service_manager::Service> ShapeDetectionService::Create() {
return base::MakeUnique<ShapeDetectionService>();
}
@@ -32,20 +24,17 @@ void ShapeDetectionService::OnStart() {
ref_factory_.reset(new service_manager::ServiceContextRefFactory(
base::Bind(&service_manager::ServiceContext::RequestQuit,
base::Unretained(context()))));
+ registry_.AddInterface(base::Bind(&BarcodeDetectionImpl::Create));
+ registry_.AddInterface(base::Bind(&FaceDetectionProviderImpl::Create));
+ registry_.AddInterface(base::Bind(&TextDetectionImpl::Create));
}
-bool ShapeDetectionService::OnConnect(
- const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- // Add a reference to the service and tie it to the lifetime of the
- // InterfaceRegistry's connection.
- std::unique_ptr<service_manager::ServiceContextRef> connection_ref =
- ref_factory_->CreateRef();
- registry->AddConnectionLostClosure(
- base::Bind(&OnConnectionLost, base::Passed(&connection_ref)));
- registry->AddInterface(base::Bind(&BarcodeDetectionImpl::Create));
- registry->AddInterface(base::Bind(&FaceDetectionProviderImpl::Create));
- return true;
+void ShapeDetectionService::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
} // namespace shape_detection
diff --git a/chromium/services/shape_detection/shape_detection_service.h b/chromium/services/shape_detection/shape_detection_service.h
index ab7945620d7..bf0f78c325e 100644
--- a/chromium/services/shape_detection/shape_detection_service.h
+++ b/chromium/services/shape_detection/shape_detection_service.h
@@ -9,6 +9,7 @@
#include "base/callback.h"
#include "base/macros.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"
@@ -23,11 +24,13 @@ class ShapeDetectionService : public service_manager::Service {
~ShapeDetectionService() override;
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
private:
std::unique_ptr<service_manager::ServiceContextRefFactory> ref_factory_;
+ service_manager::BinderRegistry registry_;
DISALLOW_COPY_AND_ASSIGN(ShapeDetectionService);
};
diff --git a/chromium/services/shape_detection/text_detection_impl.cc b/chromium/services/shape_detection/text_detection_impl.cc
new file mode 100644
index 00000000000..c5a3f091ba2
--- /dev/null
+++ b/chromium/services/shape_detection/text_detection_impl.cc
@@ -0,0 +1,14 @@
+// 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/shape_detection/text_detection_impl.h"
+
+namespace shape_detection {
+
+// static
+void TextDetectionImpl::Create(mojom::TextDetectionRequest request) {
+ DLOG(ERROR) << "Platform not supported for Text Detection Service.";
+}
+
+} // namespace shape_detection
diff --git a/chromium/services/shape_detection/text_detection_impl.h b/chromium/services/shape_detection/text_detection_impl.h
new file mode 100644
index 00000000000..617f6e8bc7f
--- /dev/null
+++ b/chromium/services/shape_detection/text_detection_impl.h
@@ -0,0 +1,24 @@
+// 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_SHAPE_DETECTION_TEXT_DETECTION_IMPL_H_
+#define SERVICES_SHAPE_DETECTION_TEXT_DETECTION_IMPL_H_
+
+#include "services/shape_detection/public/interfaces/textdetection.mojom.h"
+
+namespace shape_detection {
+
+class TextDetectionImpl {
+ public:
+ static void Create(mojom::TextDetectionRequest request);
+
+ private:
+ ~TextDetectionImpl() = default;
+
+ DISALLOW_COPY_AND_ASSIGN(TextDetectionImpl);
+};
+
+} // namespace shape_detection
+
+#endif // SERVICES_SHAPE_DETECTION_TEXT_DETECTION_IMPL_H_
diff --git a/chromium/services/shape_detection/text_detection_impl_mac.h b/chromium/services/shape_detection/text_detection_impl_mac.h
new file mode 100644
index 00000000000..d86be92799e
--- /dev/null
+++ b/chromium/services/shape_detection/text_detection_impl_mac.h
@@ -0,0 +1,33 @@
+// 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_SHAPE_DETECTION_TEXT_DETECTION_IMPL_MAC_H_
+#define SERVICES_SHAPE_DETECTION_TEXT_DETECTION_IMPL_MAC_H_
+
+#include "base/mac/scoped_nsobject.h"
+#include "services/shape_detection/public/interfaces/textdetection.mojom.h"
+
+@class CIDetector;
+
+namespace shape_detection {
+
+class TextDetectionImplMac : public mojom::TextDetection {
+ public:
+ TextDetectionImplMac();
+ ~TextDetectionImplMac() override;
+
+ void Detect(mojo::ScopedSharedBufferHandle frame_data,
+ uint32_t width,
+ uint32_t height,
+ const mojom::TextDetection::DetectCallback& callback) override;
+
+ private:
+ base::scoped_nsobject<CIDetector> detector_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextDetectionImplMac);
+};
+
+} // namespace shape_detection
+
+#endif // SERVICES_SHAPE_DETECTION_TEXT_DETECTION_IMPL_MAC_H_
diff --git a/chromium/services/shape_detection/text_detection_impl_mac.mm b/chromium/services/shape_detection/text_detection_impl_mac.mm
new file mode 100644
index 00000000000..3894770ada5
--- /dev/null
+++ b/chromium/services/shape_detection/text_detection_impl_mac.mm
@@ -0,0 +1,83 @@
+// 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/shape_detection/text_detection_impl_mac.h"
+
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "base/strings/sys_string_conversions.h"
+#include "media/capture/video/scoped_result_callback.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/shape_detection/detection_utils_mac.h"
+#include "services/shape_detection/text_detection_impl.h"
+
+namespace shape_detection {
+
+namespace {
+
+void RunCallbackWithResults(
+ const mojom::TextDetection::DetectCallback& callback,
+ std::vector<mojom::TextDetectionResultPtr> results) {
+ callback.Run(std::move(results));
+}
+
+void RunCallbackWithNoResults(
+ const mojom::TextDetection::DetectCallback& callback) {
+ callback.Run(std::vector<mojom::TextDetectionResultPtr>());
+}
+
+} // anonymous namespace
+
+// static
+void TextDetectionImpl::Create(mojom::TextDetectionRequest request) {
+ // Text detection needs at least MAC OS X 10.11.
+ if (!base::mac::IsAtLeastOS10_11())
+ return;
+ mojo::MakeStrongBinding(base::MakeUnique<TextDetectionImplMac>(),
+ std::move(request));
+}
+
+TextDetectionImplMac::TextDetectionImplMac() {
+ NSDictionary* const opts = @{CIDetectorAccuracy : CIDetectorAccuracyHigh};
+ detector_.reset([[CIDetector detectorOfType:CIDetectorTypeText
+ context:nil
+ options:opts] retain]);
+}
+
+TextDetectionImplMac::~TextDetectionImplMac() {}
+
+void TextDetectionImplMac::Detect(mojo::ScopedSharedBufferHandle frame_data,
+ uint32_t width,
+ uint32_t height,
+ const DetectCallback& callback) {
+ DCHECK(base::mac::IsAtLeastOS10_11());
+ media::ScopedResultCallback<DetectCallback> scoped_callback(
+ base::Bind(&RunCallbackWithResults, callback),
+ base::Bind(&RunCallbackWithNoResults));
+
+ base::scoped_nsobject<CIImage> ci_image =
+ CreateCIImageFromSharedMemory(std::move(frame_data), width, height);
+ if (!ci_image)
+ return;
+
+ NSArray* const features = [detector_ featuresInImage:ci_image];
+
+ std::vector<mojom::TextDetectionResultPtr> results;
+ for (CIRectangleFeature* const f in features) {
+ // CIRectangleFeature only has bounding box information.
+ auto result = mojom::TextDetectionResult::New();
+ // In the default Core Graphics coordinate space, the origin is located
+ // in the lower-left corner, and thus |ci_image| is flipped vertically.
+ // We need to adjust |y| coordinate of bounding box before sending it.
+ gfx::RectF boundingbox(f.bounds.origin.x,
+ height - f.bounds.origin.y - f.bounds.size.height,
+ f.bounds.size.width, f.bounds.size.height);
+ result->bounding_box = std::move(boundingbox);
+ results.push_back(std::move(result));
+ }
+ scoped_callback.Run(std::move(results));
+}
+
+} // namespace shape_detection
diff --git a/chromium/services/shape_detection/text_detection_impl_mac_unittest.mm b/chromium/services/shape_detection/text_detection_impl_mac_unittest.mm
new file mode 100644
index 00000000000..5333a5190b2
--- /dev/null
+++ b/chromium/services/shape_detection/text_detection_impl_mac_unittest.mm
@@ -0,0 +1,111 @@
+// 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/shape_detection/text_detection_impl_mac.h"
+
+#include "base/command_line.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/mac/scoped_nsobject.h"
+#include "base/mac/sdk_forward_declarations.h"
+#include "base/run_loop.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_switches.h"
+
+namespace shape_detection {
+
+ACTION_P(RunClosure, closure) {
+ closure.Run();
+}
+
+class TextDetectionImplMacTest : public ::testing::Test {
+ public:
+ ~TextDetectionImplMacTest() override = default;
+
+ void DetectCallback(std::vector<mojom::TextDetectionResultPtr> results) {
+ // CIDetectorTypeText doesn't return the decoded text, juts bounding boxes.
+ Detection(results.size());
+ }
+ MOCK_METHOD1(Detection, void(size_t));
+
+ TextDetectionImplMac impl_;
+ const base::MessageLoop message_loop_;
+};
+
+TEST_F(TextDetectionImplMacTest, CreateAndDestroy) {}
+
+// This test generates an image with a single text line and scans it back.
+TEST_F(TextDetectionImplMacTest, ScanOnce) {
+ // Text detection needs at least MAC OS X 10.11, and GPU infrastructure.
+ if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kUseGpuInTests) ||
+ !base::mac::IsAtLeastOS10_11()) {
+ return;
+ }
+
+ base::ScopedCFTypeRef<CGColorSpaceRef> rgb_colorspace(
+ CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB));
+
+ const int width = 200;
+ const int height = 50;
+ base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
+ nullptr, width, height, 8 /* bitsPerComponent */,
+ width * 4 /* rowBytes */, rgb_colorspace,
+ kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+
+ // Draw a white background.
+ CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0);
+ CGContextFillRect(context, CGRectMake(0.0, 0.0, width, height));
+
+ // Create a line of Helvetica 16 text, and draw it in the |context|.
+ base::scoped_nsobject<NSFont> helvetica(
+ [NSFont fontWithName:@"Helvetica" size:16]);
+ NSDictionary* attributes = [NSDictionary
+ dictionaryWithObjectsAndKeys:helvetica, kCTFontAttributeName, nil];
+
+ base::scoped_nsobject<NSAttributedString> info([[NSAttributedString alloc]
+ initWithString:@"https://www.chromium.org"
+ attributes:attributes]);
+
+ base::ScopedCFTypeRef<CTLineRef> line(
+ CTLineCreateWithAttributedString((CFAttributedStringRef)info.get()));
+
+ CGContextSetTextPosition(context, 10.0, height / 2.0);
+ CTLineDraw(line, context);
+
+ // Extract a CGImage and its raw pixels from |context|.
+ base::ScopedCFTypeRef<CGImageRef> cg_image(
+ CGBitmapContextCreateImage(context));
+ EXPECT_EQ(static_cast<size_t>(width), CGImageGetWidth(cg_image));
+ EXPECT_EQ(static_cast<size_t>(height), CGImageGetHeight(cg_image));
+
+ base::ScopedCFTypeRef<CFDataRef> raw_cg_image_data(
+ CGDataProviderCopyData(CGImageGetDataProvider(cg_image)));
+ EXPECT_TRUE(CFDataGetBytePtr(raw_cg_image_data));
+ const int num_bytes = width * height * 4;
+ EXPECT_EQ(num_bytes, CFDataGetLength(raw_cg_image_data));
+
+ // Generate a new ScopedSharedBufferHandle of the aproppriate size, map it and
+ // copy the generated text image pixels into it.
+ auto handle = mojo::SharedBufferHandle::Create(num_bytes);
+ ASSERT_TRUE(handle->is_valid());
+
+ mojo::ScopedSharedBufferMapping mapping = handle->Map(num_bytes);
+ ASSERT_TRUE(mapping);
+
+ memcpy(mapping.get(), CFDataGetBytePtr(raw_cg_image_data), num_bytes);
+
+ base::RunLoop run_loop;
+ base::Closure quit_closure = run_loop.QuitClosure();
+ // Send the image to Detect() and expect the response in callback.
+ EXPECT_CALL(*this, Detection(1)).WillOnce(RunClosure(quit_closure));
+ impl_.Detect(std::move(handle), width, height,
+ base::Bind(&TextDetectionImplMacTest::DetectCallback,
+ base::Unretained(this)));
+
+ run_loop.Run();
+}
+
+} // shape_detection namespace
diff --git a/chromium/services/tracing/public/cpp/provider.cc b/chromium/services/tracing/public/cpp/provider.cc
index 12e27bbbeec..c89aed26b03 100644
--- a/chromium/services/tracing/public/cpp/provider.cc
+++ b/chromium/services/tracing/public/cpp/provider.cc
@@ -17,7 +17,6 @@
#include "base/time/time.h"
#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_event.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/tracing/public/cpp/switches.h"
#include "services/tracing/public/interfaces/constants.mojom.h"
diff --git a/chromium/services/tracing/service.cc b/chromium/services/tracing/service.cc
index f2a6c3b3ad4..6eaf742e678 100644
--- a/chromium/services/tracing/service.cc
+++ b/chromium/services/tracing/service.cc
@@ -13,19 +13,23 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
+#include "mojo/public/cpp/system/wait.h"
+#include "services/service_manager/public/cpp/service_info.h"
namespace tracing {
-Service::Service() : collector_binding_(this), tracing_active_(false) {}
+Service::Service() : collector_binding_(this), tracing_active_(false) {
+ registry_.AddInterface<mojom::Factory>(this);
+ registry_.AddInterface<mojom::Collector>(this);
+ registry_.AddInterface<mojom::StartupPerformanceDataCollector>(this);
+}
Service::~Service() {}
-bool Service::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface<mojom::Factory>(this);
- registry->AddInterface<mojom::Collector>(this);
- registry->AddInterface<mojom::StartupPerformanceDataCollector>(this);
- return true;
+void Service::OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
bool Service::OnServiceManagerConnectionLost() {
@@ -94,7 +98,7 @@ void Service::StopAndFlush() {
// done, close the collector pipe. We don't know how long they will take. We
// want to read all data that any collector might send until all collectors or
// closed or an (arbitrary) deadline has passed. Since the bindings don't
- // support this directly we do our own MojoWaitMany over the handles and read
+ // support this directly we do our own WaitMany over the handles and read
// individual messages until all are closed or our absolute deadline has
// elapsed.
static const MojoDeadline kTimeToWaitMicros = 1000 * 1000;
@@ -105,7 +109,6 @@ void Service::StopAndFlush() {
if (now >= end) // Timed out?
break;
- MojoDeadline mojo_deadline = end - now;
std::vector<mojo::Handle> handles;
std::vector<MojoHandleSignals> signals;
for (const auto& it : recorder_impls_) {
@@ -114,14 +117,14 @@ void Service::StopAndFlush() {
MOJO_HANDLE_SIGNAL_PEER_CLOSED);
}
std::vector<MojoHandleSignalsState> signals_states(signals.size());
- const mojo::WaitManyResult wait_many_result =
- mojo::WaitMany(handles, signals, mojo_deadline, &signals_states);
- if (wait_many_result.result == MOJO_RESULT_DEADLINE_EXCEEDED) {
- // Timed out waiting, nothing more to read.
- LOG(WARNING) << "Timed out waiting for trace flush";
- break;
- }
- if (wait_many_result.IsIndexValid()) {
+ size_t result_index;
+
+ // TODO(rockot): Use a timed wait here to avoid hanging forever in the case
+ // of a misbehaving or unresponsive collector.
+ MojoResult rv =
+ mojo::WaitMany(handles.data(), signals.data(), handles.size(),
+ &result_index, signals_states.data());
+ if (rv == MOJO_RESULT_OK || rv == MOJO_RESULT_FAILED_PRECONDITION) {
// Iterate backwards so we can remove closed pipes from |recorder_impls_|
// without invalidating subsequent offsets.
for (size_t i = signals_states.size(); i != 0; --i) {
diff --git a/chromium/services/tracing/service.h b/chromium/services/tracing/service.h
index b45d54c8874..7260f0a76bc 100644
--- a/chromium/services/tracing/service.h
+++ b/chromium/services/tracing/service.h
@@ -14,6 +14,7 @@
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/tracing/data_sink.h"
@@ -36,8 +37,9 @@ class Service : public service_manager::Service,
private:
// service_manager::Service implementation.
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
bool OnServiceManagerConnectionLost() override;
// service_manager::InterfaceFactory<mojom::Factory>:
@@ -73,6 +75,7 @@ class Service : public service_manager::Service,
void AllDataCollected();
+ service_manager::BinderRegistry registry_;
mojo::BindingSet<mojom::Factory> bindings_;
std::unique_ptr<DataSink> sink_;
std::vector<std::unique_ptr<Recorder>> recorder_impls_;
diff --git a/chromium/services/ui/OWNERS b/chromium/services/ui/OWNERS
index e9190a40042..91d63fae26b 100644
--- a/chromium/services/ui/OWNERS
+++ b/chromium/services/ui/OWNERS
@@ -5,3 +5,5 @@ sky@chromium.org
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: Internals>MUS
diff --git a/chromium/services/ui/common/BUILD.gn b/chromium/services/ui/common/BUILD.gn
index 96ea1354ccd..803f8595afc 100644
--- a/chromium/services/ui/common/BUILD.gn
+++ b/chromium/services/ui/common/BUILD.gn
@@ -37,7 +37,7 @@ source_set("mus_common") {
}
# GPU related code used by the server-side components (e.g. window server
-# process, display compositor in the gpu process).
+# process, frame sink manager in the gpu process).
source_set("server_gpu") {
sources = [
"server_gpu_memory_buffer_manager.cc",
diff --git a/chromium/services/ui/common/accelerator_util.cc b/chromium/services/ui/common/accelerator_util.cc
index 11dca3f22cc..1c8c2efb908 100644
--- a/chromium/services/ui/common/accelerator_util.cc
+++ b/chromium/services/ui/common/accelerator_util.cc
@@ -24,18 +24,18 @@ mojom::EventMatcherPtr CreateKeyMatcher(ui::mojom::KeyboardCode code,
return matcher;
}
-std::vector<ui::mojom::AcceleratorPtr> CreateAcceleratorVector(
+std::vector<ui::mojom::WmAcceleratorPtr> CreateAcceleratorVector(
uint32_t id,
ui::mojom::EventMatcherPtr event_matcher) {
- std::vector<ui::mojom::AcceleratorPtr> accelerators;
+ std::vector<ui::mojom::WmAcceleratorPtr> accelerators;
accelerators.push_back(CreateAccelerator(id, std::move(event_matcher)));
return accelerators;
}
-ui::mojom::AcceleratorPtr CreateAccelerator(
+ui::mojom::WmAcceleratorPtr CreateAccelerator(
uint32_t id,
ui::mojom::EventMatcherPtr event_matcher) {
- ui::mojom::AcceleratorPtr accelerator_ptr = ui::mojom::Accelerator::New();
+ ui::mojom::WmAcceleratorPtr accelerator_ptr = ui::mojom::WmAccelerator::New();
accelerator_ptr->id = id;
accelerator_ptr->event_matcher = std::move(event_matcher);
return accelerator_ptr;
diff --git a/chromium/services/ui/common/accelerator_util.h b/chromium/services/ui/common/accelerator_util.h
index 2ce8695251c..06a306ca09a 100644
--- a/chromium/services/ui/common/accelerator_util.h
+++ b/chromium/services/ui/common/accelerator_util.h
@@ -18,12 +18,12 @@ mojom::EventMatcherPtr CreateKeyMatcher(ui::mojom::KeyboardCode code,
int flags);
// Construct accelerator vector from the provided |id| and |event_matcher|
-std::vector<ui::mojom::AcceleratorPtr> CreateAcceleratorVector(
+std::vector<ui::mojom::WmAcceleratorPtr> CreateAcceleratorVector(
uint32_t id,
ui::mojom::EventMatcherPtr event_matcher);
// Construct accelerator from the provided |id| and |event_matcher|
-ui::mojom::AcceleratorPtr CreateAccelerator(
+ui::mojom::WmAcceleratorPtr CreateAccelerator(
uint32_t id,
ui::mojom::EventMatcherPtr event_matcher);
diff --git a/chromium/services/ui/demo/OWNERS b/chromium/services/ui/demo/OWNERS
index 47351aafac9..d57048e5c65 100644
--- a/chromium/services/ui/demo/OWNERS
+++ b/chromium/services/ui/demo/OWNERS
@@ -1,2 +1,4 @@
kylechar@chromium.org
rjkroege@chromium.org
+
+# COMPONENT: Internals>MUS
diff --git a/chromium/services/ui/demo/mus_demo.cc b/chromium/services/ui/demo/mus_demo.cc
index 7afba5693af..a28ac9c5253 100644
--- a/chromium/services/ui/demo/mus_demo.cc
+++ b/chromium/services/ui/demo/mus_demo.cc
@@ -24,6 +24,14 @@ MusDemo::MusDemo() {}
MusDemo::~MusDemo() {
display::Screen::SetScreenInstance(nullptr);
+ // Destruction order is important here:
+ // 1) Windows must be destroyed before WindowTreeClient's destructor is
+ // called.
+ // 2) WindowTreeClient must be destroyed before Env and WMState.
+ window_tree_data_list_.clear();
+ window_tree_client_.reset();
+ env_.reset();
+ wm_state_.reset();
}
void MusDemo::AddPrimaryDisplay(const display::Display& display) {
@@ -74,11 +82,6 @@ void MusDemo::OnStart() {
env_->SetWindowTreeClient(window_tree_client_.get());
}
-bool MusDemo::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- return true;
-}
-
void MusDemo::OnEmbed(
std::unique_ptr<aura::WindowTreeHostMus> window_tree_host) {
NOTREACHED();
diff --git a/chromium/services/ui/demo/mus_demo.h b/chromium/services/ui/demo/mus_demo.h
index 251a505818c..251e90ab1b0 100644
--- a/chromium/services/ui/demo/mus_demo.h
+++ b/chromium/services/ui/demo/mus_demo.h
@@ -69,8 +69,6 @@ class MusDemo : public service_manager::Service,
// service_manager::Service:
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
// aura::WindowTreeClientDelegate:
void OnEmbed(
diff --git a/chromium/services/ui/demo/mus_demo_internal.cc b/chromium/services/ui/demo/mus_demo_internal.cc
index 6c2125692fa..4c79c7237f9 100644
--- a/chromium/services/ui/demo/mus_demo_internal.cc
+++ b/chromium/services/ui/demo/mus_demo_internal.cc
@@ -37,9 +37,8 @@ void MusDemoInternal::OnStartImpl() {
void MusDemoInternal::SetWindowManagerClient(
aura::WindowManagerClient* client) {}
-bool MusDemoInternal::OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) {
- return true;
-}
+void MusDemoInternal::OnWmSetBounds(aura::Window* window,
+ const gfx::Rect& bounds) {}
bool MusDemoInternal::OnWmSetProperty(
aura::Window* window,
@@ -48,6 +47,8 @@ bool MusDemoInternal::OnWmSetProperty(
return true;
}
+void MusDemoInternal::OnWmSetModalType(aura::Window* window, ModalType type) {}
+
void MusDemoInternal::OnWmSetCanFocus(aura::Window* window, bool can_focus) {}
aura::Window* MusDemoInternal::OnWmCreateTopLevelWindow(
@@ -63,6 +64,15 @@ void MusDemoInternal::OnWmClientJankinessChanged(
// Don't care
}
+void MusDemoInternal::OnWmBuildDragImage(const gfx::Point& screen_location,
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ ui::mojom::PointerKind source) {}
+
+void MusDemoInternal::OnWmMoveDragImage(const gfx::Point& screen_location) {}
+
+void MusDemoInternal::OnWmDestroyDragImage() {}
+
void MusDemoInternal::OnWmWillCreateDisplay(const display::Display& display) {
AddPrimaryDisplay(display);
}
@@ -81,8 +91,10 @@ void MusDemoInternal::OnWmDisplayRemoved(
void MusDemoInternal::OnWmDisplayModified(const display::Display& display) {}
-mojom::EventResult MusDemoInternal::OnAccelerator(uint32_t id,
- const Event& event) {
+mojom::EventResult MusDemoInternal::OnAccelerator(
+ uint32_t id,
+ const Event& event,
+ std::unordered_map<std::string, std::vector<uint8_t>>* properties) {
return mojom::EventResult::UNHANDLED;
}
diff --git a/chromium/services/ui/demo/mus_demo_internal.h b/chromium/services/ui/demo/mus_demo_internal.h
index ee93d5e3884..b145e891b77 100644
--- a/chromium/services/ui/demo/mus_demo_internal.h
+++ b/chromium/services/ui/demo/mus_demo_internal.h
@@ -32,23 +32,32 @@ class MusDemoInternal : public MusDemo, public aura::WindowManagerDelegate {
// aura::WindowManagerDelegate:
void SetWindowManagerClient(aura::WindowManagerClient* client) final;
- bool OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) final;
+ void OnWmSetBounds(aura::Window* window, const gfx::Rect& bounds) final;
bool OnWmSetProperty(aura::Window* window,
const std::string& name,
std::unique_ptr<std::vector<uint8_t>>* new_data) final;
+ void OnWmSetModalType(aura::Window* window, ModalType type) final;
void OnWmSetCanFocus(aura::Window* window, bool can_focus) final;
aura::Window* OnWmCreateTopLevelWindow(
ui::mojom::WindowType window_type,
std::map<std::string, std::vector<uint8_t>>* properties) final;
void OnWmClientJankinessChanged(const std::set<aura::Window*>& client_windows,
bool janky) final;
+ void OnWmBuildDragImage(const gfx::Point& screen_location,
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ ui::mojom::PointerKind source) final;
+ void OnWmMoveDragImage(const gfx::Point& screen_location) final;
+ void OnWmDestroyDragImage() final;
void OnWmWillCreateDisplay(const display::Display& display) final;
void OnWmNewDisplay(std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
const display::Display& display) final;
void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) final;
void OnWmDisplayModified(const display::Display& display) final;
- ui::mojom::EventResult OnAccelerator(uint32_t id,
- const ui::Event& event) final;
+ ui::mojom::EventResult OnAccelerator(
+ uint32_t id,
+ const ui::Event& event,
+ std::unordered_map<std::string, std::vector<uint8_t>>* properties) final;
void OnWmPerformMoveLoop(aura::Window* window,
ui::mojom::MoveLoopSource source,
const gfx::Point& cursor_location,
diff --git a/chromium/services/ui/demo/mus_demo_unittests.cc b/chromium/services/ui/demo/mus_demo_unittests.cc
index 9fdb8107a2c..e89c167fea1 100644
--- a/chromium/services/ui/demo/mus_demo_unittests.cc
+++ b/chromium/services/ui/demo/mus_demo_unittests.cc
@@ -40,7 +40,7 @@ class MusDemoTest : public service_manager::test::ServiceTest {
} // namespace
TEST_F(MusDemoTest, CheckMusDemoDraws) {
- connector()->Connect("mus_demo");
+ connector()->StartService("mus_demo");
::ui::mojom::WindowServerTestPtr test_interface;
connector()->BindInterface(ui::mojom::kServiceName, &test_interface);
diff --git a/chromium/services/ui/display/BUILD.gn b/chromium/services/ui/display/BUILD.gn
index 24c73bdc270..11a22557bd7 100644
--- a/chromium/services/ui/display/BUILD.gn
+++ b/chromium/services/ui/display/BUILD.gn
@@ -26,6 +26,8 @@ source_set("display") {
sources += [
"output_protection.cc",
"output_protection.h",
+ "screen_manager_forwarding.cc",
+ "screen_manager_forwarding.h",
"screen_manager_ozone_internal.cc",
"screen_manager_ozone_internal.h",
]
@@ -35,6 +37,7 @@ source_set("display") {
"//services/ui/public/interfaces/display",
"//skia",
"//ui/display/manager",
+ "//ui/display/mojo:interfaces",
"//ui/ozone",
]
} else {
diff --git a/chromium/services/ui/display/OWNERS b/chromium/services/ui/display/OWNERS
index 47351aafac9..d57048e5c65 100644
--- a/chromium/services/ui/display/OWNERS
+++ b/chromium/services/ui/display/OWNERS
@@ -1,2 +1,4 @@
kylechar@chromium.org
rjkroege@chromium.org
+
+# COMPONENT: Internals>MUS
diff --git a/chromium/services/ui/display/output_protection.h b/chromium/services/ui/display/output_protection.h
index 48185289df3..eafd2cb412b 100644
--- a/chromium/services/ui/display/output_protection.h
+++ b/chromium/services/ui/display/output_protection.h
@@ -8,7 +8,6 @@
#include <stdint.h>
#include "base/macros.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/ui/public/interfaces/display/output_protection.mojom.h"
diff --git a/chromium/services/ui/display/screen_manager.h b/chromium/services/ui/display/screen_manager.h
index ac7fe3ab898..9252194c689 100644
--- a/chromium/services/ui/display/screen_manager.h
+++ b/chromium/services/ui/display/screen_manager.h
@@ -11,7 +11,7 @@
#include "services/ui/display/screen_manager_delegate.h"
namespace service_manager {
-class InterfaceRegistry;
+class BinderRegistry;
}
namespace display {
@@ -28,7 +28,7 @@ class ScreenManager {
static ScreenManager* GetInstance();
// Registers Mojo interfaces provided.
- virtual void AddInterfaces(service_manager::InterfaceRegistry* registry) = 0;
+ virtual void AddInterfaces(service_manager::BinderRegistry* registry) = 0;
// Triggers initial display configuration to start. On device this will
// configuration the connected displays. Off device this will create one or
diff --git a/chromium/services/ui/display/screen_manager_delegate.h b/chromium/services/ui/display/screen_manager_delegate.h
index c6ed3873003..967dd478fcd 100644
--- a/chromium/services/ui/display/screen_manager_delegate.h
+++ b/chromium/services/ui/display/screen_manager_delegate.h
@@ -9,25 +9,24 @@
namespace display {
+class Display;
struct ViewportMetrics;
// The ScreenManagerDelegate will be informed of changes to the display or
// screen state by ScreenManager.
class ScreenManagerDelegate {
public:
- // Called when a display is added. |id| is the display id of the new display
- // and |metrics| contains display viewport information.
- virtual void OnDisplayAdded(int64_t id, const ViewportMetrics& metrics) = 0;
+ // Called when a display is added.
+ virtual void OnDisplayAdded(const display::Display& display,
+ const ViewportMetrics& metrics) = 0;
- // Called when a display is removed. |id| is the display id of the display
- // that was removed.
- virtual void OnDisplayRemoved(int64_t id) = 0;
-
- // Called when a display is modified. |id| is the display id of the modified
- // display and |metrics| contains updated display viewport information.
- virtual void OnDisplayModified(int64_t id,
+ // Called when a display is modified.
+ virtual void OnDisplayModified(const display::Display& display,
const ViewportMetrics& metrics) = 0;
+ // Called when a display is removed.
+ virtual void OnDisplayRemoved(int64_t display_id) = 0;
+
// Called when the primary display is changed.
virtual void OnPrimaryDisplayChanged(int64_t primary_display_id) = 0;
diff --git a/chromium/services/ui/display/screen_manager_forwarding.cc b/chromium/services/ui/display/screen_manager_forwarding.cc
new file mode 100644
index 00000000000..c3bfd521b9c
--- /dev/null
+++ b/chromium/services/ui/display/screen_manager_forwarding.cc
@@ -0,0 +1,200 @@
+// 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/ui/display/screen_manager_forwarding.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/display/types/display_snapshot_mojo.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/ozone/public/ozone_platform.h"
+
+namespace display {
+namespace {
+
+// Finds the display mode in |snapshot| that corresponds to |mode_to_find|.
+const DisplayMode* GetCorrespondingMode(const DisplaySnapshot& snapshot,
+ const DisplayMode* mode_to_find) {
+ if (!mode_to_find)
+ return nullptr;
+
+ for (auto& mode : snapshot.modes()) {
+ if (mode->size() == mode_to_find->size() &&
+ mode->is_interlaced() == mode_to_find->is_interlaced() &&
+ mode->refresh_rate() == mode_to_find->refresh_rate()) {
+ return mode.get();
+ }
+ }
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace
+
+// TODO(sky/kylechar): Change ScreenManager::Create() to make a
+// ScreenManagerForwarding in mus mode.
+
+ScreenManagerForwarding::ScreenManagerForwarding() : binding_(this) {}
+
+ScreenManagerForwarding::~ScreenManagerForwarding() {
+ if (native_display_delegate_)
+ native_display_delegate_->RemoveObserver(this);
+}
+
+void ScreenManagerForwarding::AddInterfaces(
+ service_manager::BinderRegistry* registry) {
+ registry->AddInterface<mojom::NativeDisplayDelegate>(this);
+}
+
+void ScreenManagerForwarding::Init(ScreenManagerDelegate* delegate) {
+ // Done in NativeDisplayDelegate::Initialize() instead.
+}
+
+void ScreenManagerForwarding::RequestCloseDisplay(int64_t display_id) {}
+
+void ScreenManagerForwarding::OnConfigurationChanged() {
+ if (observer_.is_bound())
+ observer_->OnConfigurationChanged();
+}
+
+void ScreenManagerForwarding::OnDisplaySnapshotsInvalidated() {
+ snapshot_map_.clear();
+}
+
+void ScreenManagerForwarding::Initialize(
+ mojom::NativeDisplayObserverPtr observer) {
+ DCHECK(!native_display_delegate_);
+ observer_ = std::move(observer);
+
+ native_display_delegate_ =
+ ui::OzonePlatform::GetInstance()->CreateNativeDisplayDelegate();
+ native_display_delegate_->AddObserver(this);
+ native_display_delegate_->Initialize();
+}
+
+void ScreenManagerForwarding::TakeDisplayControl(
+ const TakeDisplayControlCallback& callback) {
+ DCHECK(native_display_delegate_);
+ native_display_delegate_->TakeDisplayControl(callback);
+}
+
+void ScreenManagerForwarding::RelinquishDisplayControl(
+ const RelinquishDisplayControlCallback& callback) {
+ DCHECK(native_display_delegate_);
+ native_display_delegate_->RelinquishDisplayControl(callback);
+}
+
+void ScreenManagerForwarding::GetDisplays(const GetDisplaysCallback& callback) {
+ DCHECK(native_display_delegate_);
+ native_display_delegate_->GetDisplays(
+ base::Bind(&ScreenManagerForwarding::ForwardGetDisplays,
+ base::Unretained(this), callback));
+}
+
+void ScreenManagerForwarding::Configure(
+ int64_t display_id,
+ std::unique_ptr<display::DisplayMode> mode,
+ const gfx::Point& origin,
+ const ConfigureCallback& callback) {
+ DCHECK(native_display_delegate_);
+ DisplaySnapshot* snapshot = snapshot_map_[display_id];
+ if (!snapshot) {
+ callback.Run(false);
+ return;
+ }
+
+ // We need a pointer to the mode in |snapshot|, not the equivalent mode we
+ // received over Mojo.
+ const DisplayMode* snapshot_mode =
+ GetCorrespondingMode(*snapshot, mode.get());
+ native_display_delegate_->Configure(
+ *snapshot, snapshot_mode, origin,
+ base::Bind(&ScreenManagerForwarding::ForwardConfigure,
+ base::Unretained(this), snapshot, snapshot_mode, origin,
+ callback));
+}
+
+void ScreenManagerForwarding::GetHDCPState(
+ int64_t display_id,
+ const GetHDCPStateCallback& callback) {
+ DCHECK(native_display_delegate_);
+ const DisplaySnapshot* snapshot = snapshot_map_[display_id];
+ if (!snapshot) {
+ callback.Run(false, HDCP_STATE_UNDESIRED);
+ return;
+ }
+
+ native_display_delegate_->GetHDCPState(*snapshot, callback);
+}
+
+void ScreenManagerForwarding::SetHDCPState(
+ int64_t display_id,
+ display::HDCPState state,
+ const SetHDCPStateCallback& callback) {
+ DCHECK(native_display_delegate_);
+ const DisplaySnapshot* snapshot = snapshot_map_[display_id];
+ if (!snapshot) {
+ callback.Run(false);
+ return;
+ }
+
+ native_display_delegate_->SetHDCPState(*snapshot, state, callback);
+}
+
+void ScreenManagerForwarding::SetColorCorrection(
+ int64_t display_id,
+ const std::vector<display::GammaRampRGBEntry>& degamma_lut,
+ const std::vector<display::GammaRampRGBEntry>& gamma_lut,
+ const std::vector<float>& correction_matrix) {
+ DCHECK(native_display_delegate_);
+ const DisplaySnapshot* snapshot = snapshot_map_[display_id];
+ if (!snapshot)
+ return;
+
+ native_display_delegate_->SetColorCorrection(*snapshot, degamma_lut,
+ gamma_lut, correction_matrix);
+}
+
+void ScreenManagerForwarding::Create(
+ const service_manager::Identity& remote_identity,
+ mojom::NativeDisplayDelegateRequest request) {
+ DCHECK(!binding_.is_bound());
+ binding_.Bind(std::move(request));
+}
+
+void ScreenManagerForwarding::ForwardGetDisplays(
+ const mojom::NativeDisplayDelegate::GetDisplaysCallback& callback,
+ const std::vector<DisplaySnapshot*>& snapshots) {
+ snapshot_map_.clear();
+
+ // Convert the DisplaySnapshots to MojoDisplaySnapshots to allow sending
+ // over Mojo. Also caches the snapshots for lookup later.
+ std::vector<std::unique_ptr<DisplaySnapshotMojo>> mojo_snapshots;
+ for (auto* snapshot : snapshots) {
+ snapshot_map_[snapshot->display_id()] = snapshot;
+ mojo_snapshots.push_back(DisplaySnapshotMojo::CreateFrom(*snapshot));
+ }
+
+ callback.Run(std::move(mojo_snapshots));
+}
+
+void ScreenManagerForwarding::ForwardConfigure(
+ DisplaySnapshot* snapshot,
+ const DisplayMode* mode,
+ const gfx::Point& origin,
+ const mojom::NativeDisplayDelegate::ConfigureCallback& callback,
+ bool status) {
+ if (status) {
+ // Modify display snapshot similar to how ConfigureDisplaysTask would. Ozone
+ // DRM needs these to be changed and ConfigureDisplaysTasks can't do it.
+ snapshot->set_current_mode(mode);
+ snapshot->set_origin(origin);
+ }
+ callback.Run(status);
+}
+
+} // namespace display
diff --git a/chromium/services/ui/display/screen_manager_forwarding.h b/chromium/services/ui/display/screen_manager_forwarding.h
new file mode 100644
index 00000000000..d3a0f5bb467
--- /dev/null
+++ b/chromium/services/ui/display/screen_manager_forwarding.h
@@ -0,0 +1,96 @@
+// 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_UI_DISPLAY_SCREEN_MANAGER_FORWARDING_H_
+#define SERVICES_UI_DISPLAY_SCREEN_MANAGER_FORWARDING_H_
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "base/macros.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "services/service_manager/public/cpp/interface_factory.h"
+#include "services/ui/display/screen_manager.h"
+#include "ui/display/mojo/native_display_delegate.mojom.h"
+#include "ui/display/types/native_display_observer.h"
+
+namespace display {
+
+class NativeDisplayDelegate;
+
+// ScreenManager implementation that implements mojom::NativeDisplayDelegate.
+// This will own a real NativeDisplayDelegate and forwards calls to and
+// responses from it over Mojo.
+class ScreenManagerForwarding
+ : public ScreenManager,
+ public NativeDisplayObserver,
+ public mojom::NativeDisplayDelegate,
+ service_manager::InterfaceFactory<mojom::NativeDisplayDelegate> {
+ public:
+ ScreenManagerForwarding();
+ ~ScreenManagerForwarding() override;
+
+ // ScreenManager:
+ void AddInterfaces(service_manager::BinderRegistry* registry) override;
+ void Init(ScreenManagerDelegate* delegate) override;
+ void RequestCloseDisplay(int64_t display_id) override;
+
+ // NativeDisplayObserver:
+ void OnConfigurationChanged() override;
+ void OnDisplaySnapshotsInvalidated() override;
+
+ // mojom::NativeDisplayDelegate:
+ void Initialize(mojom::NativeDisplayObserverPtr observer) override;
+ void TakeDisplayControl(const TakeDisplayControlCallback& callback) override;
+ void RelinquishDisplayControl(
+ const RelinquishDisplayControlCallback& callback) override;
+ void GetDisplays(const GetDisplaysCallback& callback) override;
+ void Configure(int64_t display_id,
+ std::unique_ptr<display::DisplayMode> mode,
+ const gfx::Point& origin,
+ const ConfigureCallback& callback) override;
+ void GetHDCPState(int64_t display_id,
+ const GetHDCPStateCallback& callback) override;
+ void SetHDCPState(int64_t display_id,
+ display::HDCPState state,
+ const SetHDCPStateCallback& callback) override;
+ void SetColorCorrection(
+ int64_t display_id,
+ const std::vector<display::GammaRampRGBEntry>& degamma_lut,
+ const std::vector<display::GammaRampRGBEntry>& gamma_lut,
+ const std::vector<float>& correction_matrix) override;
+
+ // service_manager::InterfaceFactory<mojom::NativeDisplayDelegate>:
+ void Create(const service_manager::Identity& remote_identity,
+ mojom::NativeDisplayDelegateRequest request) override;
+
+ private:
+ // Forwards results from GetDisplays() back with |callback|.
+ void ForwardGetDisplays(
+ const mojom::NativeDisplayDelegate::GetDisplaysCallback& callback,
+ const std::vector<DisplaySnapshot*>& displays);
+
+ // Forwards results from call to Configure() back with |callback|.
+ void ForwardConfigure(
+ DisplaySnapshot* snapshot,
+ const DisplayMode* mode,
+ const gfx::Point& origin,
+ const mojom::NativeDisplayDelegate::ConfigureCallback& callback,
+ bool status);
+
+ mojo::Binding<mojom::NativeDisplayDelegate> binding_;
+ mojom::NativeDisplayObserverPtr observer_;
+
+ std::unique_ptr<display::NativeDisplayDelegate> native_display_delegate_;
+
+ // Cached pointers to snapshots owned by the |native_display_delegate_|.
+ std::unordered_map<int64_t, DisplaySnapshot*> snapshot_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenManagerForwarding);
+};
+
+} // namespace display
+
+#endif // SERVICES_UI_DISPLAY_SCREEN_MANAGER_FORWARDING_H_
diff --git a/chromium/services/ui/display/screen_manager_ozone_external.cc b/chromium/services/ui/display/screen_manager_ozone_external.cc
index ec27b7a4668..45a50277243 100644
--- a/chromium/services/ui/display/screen_manager_ozone_external.cc
+++ b/chromium/services/ui/display/screen_manager_ozone_external.cc
@@ -6,7 +6,7 @@
#include <memory>
-#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "ui/display/types/display_constants.h"
namespace display {
@@ -21,7 +21,7 @@ ScreenManagerOzoneExternal::ScreenManagerOzoneExternal() {}
ScreenManagerOzoneExternal::~ScreenManagerOzoneExternal() {}
void ScreenManagerOzoneExternal::AddInterfaces(
- service_manager::InterfaceRegistry* registry) {}
+ service_manager::BinderRegistry* registry) {}
void ScreenManagerOzoneExternal::Init(ScreenManagerDelegate* delegate) {}
diff --git a/chromium/services/ui/display/screen_manager_ozone_external.h b/chromium/services/ui/display/screen_manager_ozone_external.h
index bf1c92a755b..41fe466008f 100644
--- a/chromium/services/ui/display/screen_manager_ozone_external.h
+++ b/chromium/services/ui/display/screen_manager_ozone_external.h
@@ -23,7 +23,7 @@ class ScreenManagerOzoneExternal : public ScreenManager {
private:
// ScreenManager.
- void AddInterfaces(service_manager::InterfaceRegistry* registry) override;
+ void AddInterfaces(service_manager::BinderRegistry* registry) override;
void Init(ScreenManagerDelegate* delegate) override;
void RequestCloseDisplay(int64_t display_id) override;
diff --git a/chromium/services/ui/display/screen_manager_ozone_internal.cc b/chromium/services/ui/display/screen_manager_ozone_internal.cc
index d175cee4569..854ef3ae7bd 100644
--- a/chromium/services/ui/display/screen_manager_ozone_internal.cc
+++ b/chromium/services/ui/display/screen_manager_ozone_internal.cc
@@ -12,7 +12,7 @@
#include "base/threading/thread_task_runner_handle.h"
#include "chromeos/system/devicemode.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/ui/display/output_protection.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/display/manager/chromeos/display_change_observer.h"
@@ -33,26 +33,6 @@ namespace {
// Needed for DisplayConfigurator::ForceInitialConfigure.
const SkColor kChromeOsBootColor = SkColorSetRGB(0xfe, 0xfe, 0xfe);
-// Recursively swaps the displays in a DisplayLayout to change the primary
-// display but keep the same relative display layout.
-// TODO(kylechar): This is copied from WindowTreeHostManager. The concept of
-// getting the same relative display layout with a different primary display id
-// should become a function on DisplayLayout itself to avoid reimplementing it
-// here.
-void SwapRecursive(const std::map<int64_t, DisplayPlacement*>& id_to_placement,
- int64_t current_primary_id,
- int64_t display_id) {
- if (display_id == current_primary_id)
- return;
-
- DCHECK(id_to_placement.count(display_id));
- DisplayPlacement* placement = id_to_placement.at(display_id);
- DCHECK(placement);
- SwapRecursive(id_to_placement, current_primary_id,
- placement->parent_display_id);
- placement->Swap();
-}
-
} // namespace
// static
@@ -108,21 +88,8 @@ void ScreenManagerOzoneInternal::SetPrimaryDisplayId(int64_t display_id) {
// when the primary id is set after new displays are connected.
// Only update the layout if it is requested to swap primary display.
if (layout.primary_id != new_primary_display.id()) {
- std::unique_ptr<DisplayLayout> swapped_layout(layout.Copy());
-
- std::map<int64_t, DisplayPlacement*> id_to_placement;
- for (auto& placement : swapped_layout->placement_list)
- id_to_placement[placement.display_id] = &placement;
- SwapRecursive(id_to_placement, primary_display_id_,
- new_primary_display.id());
-
- std::sort(swapped_layout->placement_list.begin(),
- swapped_layout->placement_list.end(),
- [](const DisplayPlacement& d1, const DisplayPlacement& d2) {
- return d1.display_id < d2.display_id;
- });
-
- swapped_layout->primary_id = new_primary_display.id();
+ std::unique_ptr<display::DisplayLayout> swapped_layout = layout.Copy();
+ swapped_layout->SwapPrimaryDisplay(new_primary_display.id());
DisplayIdList list = display_manager_->GetCurrentDisplayIdList();
display_manager_->layout_store()->RegisterLayoutForDisplayIdList(
list, std::move(swapped_layout));
@@ -143,7 +110,7 @@ void ScreenManagerOzoneInternal::SetPrimaryDisplayId(int64_t display_id) {
}
void ScreenManagerOzoneInternal::AddInterfaces(
- service_manager::InterfaceRegistry* registry) {
+ service_manager::BinderRegistry* registry) {
registry->AddInterface<mojom::DisplayController>(this);
registry->AddInterface<mojom::OutputProtection>(this);
registry->AddInterface<mojom::TestDisplayController>(this);
@@ -308,7 +275,7 @@ void ScreenManagerOzoneInternal::OnDisplayAdded(const Display& display) {
DVLOG(1) << "OnDisplayAdded: " << display.ToString() << "\n "
<< metrics.ToString();
screen_->display_list().AddDisplay(display, DisplayList::Type::NOT_PRIMARY);
- delegate_->OnDisplayAdded(display.id(), metrics);
+ delegate_->OnDisplayAdded(display, metrics);
}
void ScreenManagerOzoneInternal::OnDisplayRemoved(const Display& display) {
@@ -327,7 +294,7 @@ void ScreenManagerOzoneInternal::OnDisplayMetricsChanged(
DVLOG(1) << "OnDisplayModified: " << display.ToString() << "\n "
<< metrics.ToString();
screen_->display_list().UpdateDisplay(display);
- delegate_->OnDisplayModified(display.id(), metrics);
+ delegate_->OnDisplayModified(display, metrics);
}
ViewportMetrics ScreenManagerOzoneInternal::GetViewportMetricsForDisplay(
@@ -336,11 +303,9 @@ ViewportMetrics ScreenManagerOzoneInternal::GetViewportMetricsForDisplay(
display_manager_->GetDisplayInfo(display.id());
ViewportMetrics metrics;
- metrics.bounds = display.bounds();
- metrics.work_area = display.work_area();
- metrics.pixel_size = managed_info.bounds_in_native().size();
- metrics.rotation = display.rotation();
- metrics.touch_support = display.touch_support();
+ // TODO(kylechar): The origin of |metrics.bounds_in_pixels| should be updated
+ // so that PlatformWindows appear next to one another for multiple displays.
+ metrics.bounds_in_pixels = managed_info.bounds_in_native();
metrics.device_scale_factor = display.device_scale_factor();
metrics.ui_scale_factor = managed_info.configured_ui_scale();
diff --git a/chromium/services/ui/display/screen_manager_ozone_internal.h b/chromium/services/ui/display/screen_manager_ozone_internal.h
index bb9abff09d0..61c99201bb7 100644
--- a/chromium/services/ui/display/screen_manager_ozone_internal.h
+++ b/chromium/services/ui/display/screen_manager_ozone_internal.h
@@ -11,7 +11,6 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/ui/display/screen_manager.h"
#include "services/ui/display/viewport_metrics.h"
@@ -50,7 +49,7 @@ class ScreenManagerOzoneInternal
void SetPrimaryDisplayId(int64_t display_id);
// ScreenManager:
- void AddInterfaces(service_manager::InterfaceRegistry* registry) override;
+ void AddInterfaces(service_manager::BinderRegistry* registry) override;
void Init(ScreenManagerDelegate* delegate) override;
void RequestCloseDisplay(int64_t display_id) override;
diff --git a/chromium/services/ui/display/screen_manager_ozone_internal_unittests.cc b/chromium/services/ui/display/screen_manager_ozone_internal_unittests.cc
index 7b93494342d..8b7a0100580 100644
--- a/chromium/services/ui/display/screen_manager_ozone_internal_unittests.cc
+++ b/chromium/services/ui/display/screen_manager_ozone_internal_unittests.cc
@@ -35,24 +35,25 @@ namespace {
// Holds info about the display state we want to test.
struct DisplayState {
- int64_t id;
+ Display display;
ViewportMetrics metrics;
};
// Matchers that operate on DisplayState.
MATCHER_P(DisplayIdIs, display_id, "") {
- *result_listener << "has id " << arg.id;
- return arg.id == display_id;
+ *result_listener << "has id " << arg.display.id();
+ return arg.display.id() == display_id;
}
MATCHER_P(DisplayPixelSizeIs, size_string, "") {
- *result_listener << "has size " << arg.metrics.pixel_size.ToString();
- return arg.metrics.pixel_size.ToString() == size_string;
+ *result_listener << "has size "
+ << arg.metrics.bounds_in_pixels.size().ToString();
+ return arg.metrics.bounds_in_pixels.size().ToString() == size_string;
}
MATCHER_P(DisplayBoundsIs, bounds_string, "") {
- *result_listener << "has size " << arg.metrics.bounds.ToString();
- return arg.metrics.bounds.ToString() == bounds_string;
+ *result_listener << "has size " << arg.display.bounds().ToString();
+ return arg.display.bounds().ToString() == bounds_string;
}
// Test delegate to track what functions calls the delegate receives.
@@ -84,18 +85,20 @@ class TestScreenManagerDelegate : public ScreenManagerDelegate {
changes_ += name + "(" + value + ")";
}
- void OnDisplayAdded(int64_t id, const ViewportMetrics& metrics) override {
- added_.push_back({id, metrics});
- AddChange("Added", base::Int64ToString(id));
+ void OnDisplayAdded(const display::Display& display,
+ const ViewportMetrics& metrics) override {
+ added_.push_back({display, metrics});
+ AddChange("Added", base::Int64ToString(display.id()));
}
void OnDisplayRemoved(int64_t id) override {
AddChange("Removed", base::Int64ToString(id));
}
- void OnDisplayModified(int64_t id, const ViewportMetrics& metrics) override {
- modified_.push_back({id, metrics});
- AddChange("Modified", base::Int64ToString(id));
+ void OnDisplayModified(const display::Display& display,
+ const ViewportMetrics& metrics) override {
+ modified_.push_back({display, metrics});
+ AddChange("Modified", base::Int64ToString(display.id()));
}
void OnPrimaryDisplayChanged(int64_t primary_display_id) override {
diff --git a/chromium/services/ui/display/screen_manager_stub_internal.cc b/chromium/services/ui/display/screen_manager_stub_internal.cc
index 4f4be7c8896..e513b004c80 100644
--- a/chromium/services/ui/display/screen_manager_stub_internal.cc
+++ b/chromium/services/ui/display/screen_manager_stub_internal.cc
@@ -10,30 +10,32 @@
#include "base/location.h"
#include "base/memory/ptr_util.h"
#include "base/threading/thread_task_runner_handle.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
-#include "ui/display/display.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
+#include "services/ui/display/viewport_metrics.h"
+#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
namespace display {
namespace {
-// Build a ViewportMetric for a 1024x768 display.
-ViewportMetrics DefaultViewportMetrics() {
- ViewportMetrics metrics;
+constexpr gfx::Size kDisplayPixelSize(1024, 768);
- metrics.device_scale_factor = 1.0f;
+// Build a 1024x768 pixel display.
+Display DefaultDisplay() {
+ float device_scale_factor = 1.f;
if (Display::HasForceDeviceScaleFactor())
- metrics.device_scale_factor = Display::GetForcedDeviceScaleFactor();
+ device_scale_factor = Display::GetForcedDeviceScaleFactor();
- metrics.pixel_size = gfx::Size(1024, 768);
- gfx::Size scaled_size = gfx::ScaleToRoundedSize(
- metrics.pixel_size, 1.0f / metrics.device_scale_factor);
+ gfx::Size scaled_size =
+ gfx::ConvertSizeToDIP(device_scale_factor, kDisplayPixelSize);
- metrics.bounds = gfx::Rect(scaled_size);
- metrics.work_area = gfx::Rect(scaled_size);
+ Display display(1);
+ display.set_bounds(gfx::Rect(scaled_size));
+ display.set_work_area(display.bounds());
+ display.set_device_scale_factor(device_scale_factor);
- return metrics;
+ return display;
}
} // namespace
@@ -49,16 +51,21 @@ ScreenManagerStubInternal::ScreenManagerStubInternal()
ScreenManagerStubInternal::~ScreenManagerStubInternal() {}
void ScreenManagerStubInternal::FixedSizeScreenConfiguration() {
- delegate_->OnDisplayAdded(display_id_, display_metrics_);
+ ViewportMetrics metrics;
+ metrics.bounds_in_pixels = gfx::Rect(kDisplayPixelSize);
+ metrics.device_scale_factor = display_.device_scale_factor();
+ metrics.ui_scale_factor = 1.f;
+
+ delegate_->OnDisplayAdded(display_, metrics);
}
void ScreenManagerStubInternal::AddInterfaces(
- service_manager::InterfaceRegistry* registry) {}
+ service_manager::BinderRegistry* registry) {}
void ScreenManagerStubInternal::Init(ScreenManagerDelegate* delegate) {
DCHECK(delegate);
delegate_ = delegate;
- display_metrics_ = DefaultViewportMetrics();
+ display_ = DefaultDisplay();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&ScreenManagerStubInternal::FixedSizeScreenConfiguration,
@@ -66,7 +73,7 @@ void ScreenManagerStubInternal::Init(ScreenManagerDelegate* delegate) {
}
void ScreenManagerStubInternal::RequestCloseDisplay(int64_t display_id) {
- if (display_id == display_id_) {
+ if (display_id == display_.id()) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(&ScreenManagerDelegate::OnDisplayRemoved,
base::Unretained(delegate_), display_id));
diff --git a/chromium/services/ui/display/screen_manager_stub_internal.h b/chromium/services/ui/display/screen_manager_stub_internal.h
index 9d278d7172e..bca5ab986ee 100644
--- a/chromium/services/ui/display/screen_manager_stub_internal.h
+++ b/chromium/services/ui/display/screen_manager_stub_internal.h
@@ -9,7 +9,7 @@
#include "base/memory/weak_ptr.h"
#include "services/ui/display/screen_manager.h"
-#include "services/ui/display/viewport_metrics.h"
+#include "ui/display/display.h"
namespace display {
@@ -25,13 +25,12 @@ class ScreenManagerStubInternal : public ScreenManager {
void FixedSizeScreenConfiguration();
// ScreenManager.
- void AddInterfaces(service_manager::InterfaceRegistry* registry) override;
+ void AddInterfaces(service_manager::BinderRegistry* registry) override;
void Init(ScreenManagerDelegate* delegate) override;
void RequestCloseDisplay(int64_t display_id) override;
// Sample display information.
- int64_t display_id_ = 1;
- ViewportMetrics display_metrics_;
+ Display display_;
ScreenManagerDelegate* delegate_ = nullptr;
diff --git a/chromium/services/ui/display/viewport_metrics.cc b/chromium/services/ui/display/viewport_metrics.cc
index 0cbacae06bb..cdf95482d4b 100644
--- a/chromium/services/ui/display/viewport_metrics.cc
+++ b/chromium/services/ui/display/viewport_metrics.cc
@@ -8,46 +8,11 @@
namespace display {
-namespace {
-
-std::string TouchSupportString(Display::TouchSupport touch_support) {
- switch (touch_support) {
- case Display::TOUCH_SUPPORT_UNKNOWN:
- return "unknown";
- case Display::TOUCH_SUPPORT_AVAILABLE:
- return "available";
- case Display::TOUCH_SUPPORT_UNAVAILABLE:
- return "unavailable";
- }
- NOTREACHED();
- return "Invalid TouchSupport";
-}
-
-std::string RotationString(Display::Rotation rotation) {
- switch (rotation) {
- case Display::ROTATE_0:
- return "0";
- case Display::ROTATE_90:
- return "90";
- case Display::ROTATE_180:
- return "180";
- case Display::ROTATE_270:
- return "270";
- }
- NOTREACHED();
- return "Invalid Rotation";
-}
-
-} // namespace
-
std::string ViewportMetrics::ToString() const {
return base::StringPrintf(
- "ViewportMetrics(bounds=%s, work_area=%s, pixel_size=%s, "
- "rotation=%s, touch_support=%s, "
- "device_scale_factor=%g, ui_scale_factor=%g)",
- bounds.ToString().c_str(), work_area.ToString().c_str(),
- pixel_size.ToString().c_str(), RotationString(rotation).c_str(),
- TouchSupportString(touch_support).c_str(), device_scale_factor,
+ "ViewportMetrics(bounds_in_pixels=%s, device_scale_factor=%g, "
+ "ui_scale_factor=%g)",
+ bounds_in_pixels.ToString().c_str(), device_scale_factor,
ui_scale_factor);
}
diff --git a/chromium/services/ui/display/viewport_metrics.h b/chromium/services/ui/display/viewport_metrics.h
index 063f9e6f072..631794fd59b 100644
--- a/chromium/services/ui/display/viewport_metrics.h
+++ b/chromium/services/ui/display/viewport_metrics.h
@@ -7,28 +7,20 @@
#include <string>
-#include "ui/display/display.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/size.h"
namespace display {
struct ViewportMetrics {
std::string ToString() const;
- gfx::Rect bounds; // DIP.
- gfx::Rect work_area; // DIP.
- gfx::Size pixel_size;
- Display::Rotation rotation = Display::ROTATE_0;
- Display::TouchSupport touch_support = Display::TOUCH_SUPPORT_UNKNOWN;
+ gfx::Rect bounds_in_pixels;
float device_scale_factor = 0.0f;
float ui_scale_factor = 0.0f;
};
inline bool operator==(const ViewportMetrics& lhs, const ViewportMetrics& rhs) {
- return lhs.bounds == rhs.bounds && lhs.work_area == rhs.work_area &&
- lhs.pixel_size == rhs.pixel_size && lhs.rotation == rhs.rotation &&
- lhs.touch_support == rhs.touch_support &&
+ return lhs.bounds_in_pixels == rhs.bounds_in_pixels &&
lhs.device_scale_factor == rhs.device_scale_factor &&
lhs.ui_scale_factor == rhs.ui_scale_factor;
}
diff --git a/chromium/services/ui/gpu/BUILD.gn b/chromium/services/ui/gpu/BUILD.gn
index c046f6f3cdc..c365a80363f 100644
--- a/chromium/services/ui/gpu/BUILD.gn
+++ b/chromium/services/ui/gpu/BUILD.gn
@@ -20,6 +20,7 @@ source_set("gpu") {
deps = [
"//cc",
+ "//components/viz/frame_sinks",
"//gpu/ipc:command_buffer",
"//gpu/ipc/common",
"//gpu/ipc/service",
@@ -51,12 +52,18 @@ test("mus_gpu_unittests") {
deps = [
":gpu",
"//base",
+ "//gpu",
"//ipc",
"//services/ui/common:run_all_service_tests",
+ "//services/ui/gpu/interfaces",
"//testing/gtest",
"//ui/gfx:memory_buffer",
"//ui/gfx/geometry",
]
+
+ sources = [
+ "gpu_service_unittest.cc",
+ ]
}
service_manifest("mus_gpu_unittests_app_manifest") {
diff --git a/chromium/services/ui/gpu/DEPS b/chromium/services/ui/gpu/DEPS
index 7c622586f4e..b6d0a2aa2ac 100644
--- a/chromium/services/ui/gpu/DEPS
+++ b/chromium/services/ui/gpu/DEPS
@@ -1,10 +1,11 @@
include_rules = [
+ "+components/viz",
"+gpu/command_buffer",
"+gpu/config",
"+gpu/ipc",
"+gpu/ipc/common",
"+gpu/ipc/service",
- "+media/gpu/ipc/service",
+ "+media/gpu",
"-services/ui/common",
]
diff --git a/chromium/services/ui/gpu/OWNERS b/chromium/services/ui/gpu/OWNERS
index afaf27099bd..0119364bab9 100644
--- a/chromium/services/ui/gpu/OWNERS
+++ b/chromium/services/ui/gpu/OWNERS
@@ -1,3 +1,6 @@
+file://gpu/OWNERS
fsamuel@chromium.org
rjkroege@chromium.org
sadrul@chromium.org
+
+# COMPONENT: Internals>GPU>Internals
diff --git a/chromium/services/ui/gpu/gpu_main.cc b/chromium/services/ui/gpu/gpu_main.cc
index bc04ac51508..ba01980a44b 100644
--- a/chromium/services/ui/gpu/gpu_main.cc
+++ b/chromium/services/ui/gpu/gpu_main.cc
@@ -7,12 +7,16 @@
#include "base/command_line.h"
#include "base/memory/ptr_util.h"
#include "base/message_loop/message_loop.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "components/viz/frame_sinks/mojo_frame_sink_manager.h"
+#include "gpu/command_buffer/common/activity_flags.h"
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "gpu/ipc/gpu_in_process_thread_service.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "services/ui/common/server_gpu_memory_buffer_manager.h"
#include "services/ui/gpu/gpu_service.h"
+#include "services/ui/surfaces/mus_display_provider.h"
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
@@ -47,6 +51,7 @@ GpuMain::GpuMain(mojom::GpuMainRequest request)
: gpu_thread_("GpuThread"),
io_thread_("GpuIOThread"),
compositor_thread_("DisplayCompositorThread"),
+ power_monitor_(base::MakeUnique<base::PowerMonitorDeviceSource>()),
binding_(this, std::move(request)) {
base::Thread::Options thread_options;
@@ -71,6 +76,7 @@ GpuMain::GpuMain(mojom::GpuMainRequest request)
thread_options.priority = base::ThreadPriority::DISPLAY;
#endif
CHECK(gpu_thread_.StartWithOptions(thread_options));
+ gpu_thread_task_runner_ = gpu_thread_.task_runner();
// TODO(sad): We do not need the IO thread once gpu has a separate process. It
// should be possible to use |main_task_runner_| for doing IO tasks.
@@ -85,11 +91,12 @@ GpuMain::GpuMain(mojom::GpuMainRequest request)
// Start the compositor thread.
compositor_thread_.Start();
+ compositor_thread_task_runner_ = compositor_thread_.task_runner();
}
GpuMain::~GpuMain() {
// Unretained() is OK here since the thread/task runner is owned by |this|.
- compositor_thread_.task_runner()->PostTask(
+ compositor_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuMain::TearDownOnCompositorThread, base::Unretained(this)));
@@ -98,7 +105,7 @@ GpuMain::~GpuMain() {
// thread to avoid deadlock.
compositor_thread_.Stop();
- gpu_thread_.task_runner()->PostTask(
+ gpu_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuMain::TearDownOnGpuThread, base::Unretained(this)));
gpu_thread_.Stop();
@@ -108,33 +115,36 @@ GpuMain::~GpuMain() {
void GpuMain::OnStart() {
// |this| will outlive the gpu thread and so it's safe to use
// base::Unretained here.
- gpu_thread_.task_runner()->PostTask(
+ gpu_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuMain::InitOnGpuThread, base::Unretained(this),
- io_thread_.task_runner(), compositor_thread_.task_runner()));
+ io_thread_.task_runner(), compositor_thread_task_runner_));
}
void GpuMain::CreateGpuService(mojom::GpuServiceRequest request,
mojom::GpuHostPtr gpu_host,
- const gpu::GpuPreferences& preferences) {
+ const gpu::GpuPreferences& preferences,
+ mojo::ScopedSharedBufferHandle activity_flags) {
// |this| will outlive the gpu thread and so it's safe to use
// base::Unretained here.
- gpu_thread_.task_runner()->PostTask(
+ gpu_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuMain::CreateGpuServiceOnGpuThread, base::Unretained(this),
base::Passed(std::move(request)),
- base::Passed(gpu_host.PassInterface()), preferences));
+ base::Passed(gpu_host.PassInterface()), preferences,
+ base::Passed(
+ gpu::GpuProcessActivityFlags(std::move(activity_flags)))));
}
-void GpuMain::CreateDisplayCompositor(
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtr client) {
+void GpuMain::CreateFrameSinkManager(
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtr client) {
if (!gpu_service_) {
- pending_display_compositor_request_ = std::move(request);
- pending_display_compositor_client_info_ = client.PassInterface();
+ pending_frame_sink_manager_request_ = std::move(request);
+ pending_frame_sink_manager_client_info_ = client.PassInterface();
return;
}
- CreateDisplayCompositorInternal(std::move(request), client.PassInterface());
+ CreateFrameSinkManagerInternal(std::move(request), client.PassInterface());
}
void GpuMain::InitOnGpuThread(
@@ -147,72 +157,67 @@ void GpuMain::InitOnGpuThread(
if (!success)
return;
- if (gpu::GetNativeGpuMemoryBufferType() != gfx::EMPTY_BUFFER) {
- gpu_memory_buffer_factory_ =
- gpu::GpuMemoryBufferFactory::CreateNativeType();
- }
-
gpu_service_ = base::MakeUnique<GpuService>(
- gpu_init_->gpu_info(), gpu_init_->TakeWatchdogThread(),
- gpu_memory_buffer_factory_.get(), io_runner,
+ gpu_init_->gpu_info(), gpu_init_->TakeWatchdogThread(), io_runner,
gpu_init_->gpu_feature_info());
}
-void GpuMain::CreateDisplayCompositorInternal(
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtrInfo client_info) {
+void GpuMain::CreateFrameSinkManagerInternal(
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtrInfo client_info) {
DCHECK(!gpu_command_service_);
gpu_command_service_ = new gpu::GpuInProcessThreadService(
- gpu_thread_.task_runner(), gpu_service_->sync_point_manager(),
+ gpu_thread_task_runner_, gpu_service_->sync_point_manager(),
gpu_service_->mailbox_manager(), gpu_service_->share_group());
- // |gpu_memory_buffer_factory_| is null in tests.
- gpu::ImageFactory* image_factory =
- gpu_memory_buffer_factory_ ? gpu_memory_buffer_factory_->AsImageFactory()
- : nullptr;
-
+ gpu::ImageFactory* image_factory = gpu_service_->gpu_image_factory();
mojom::GpuServicePtr gpu_service;
mojom::GpuServiceRequest gpu_service_request(&gpu_service);
- if (gpu_thread_.task_runner()->BelongsToCurrentThread()) {
- // If the DisplayCompositor creation was delayed because GpuService
- // had not been created yet, then this is called, in gpu thread, right after
+ if (gpu_thread_task_runner_->BelongsToCurrentThread()) {
+ // If the FrameSinkManager creation was delayed because GpuService had not
+ // been created yet, then this is called, in gpu thread, right after
// GpuService is created.
BindGpuInternalOnGpuThread(std::move(gpu_service_request));
} else {
- gpu_thread_.task_runner()->PostTask(
+ gpu_thread_task_runner_->PostTask(
FROM_HERE,
base::Bind(&GpuMain::BindGpuInternalOnGpuThread, base::Unretained(this),
base::Passed(std::move(gpu_service_request))));
}
- compositor_thread_.task_runner()->PostTask(
- FROM_HERE, base::Bind(&GpuMain::CreateDisplayCompositorOnCompositorThread,
+ compositor_thread_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuMain::CreateFrameSinkManagerOnCompositorThread,
base::Unretained(this), image_factory,
base::Passed(gpu_service.PassInterface()),
base::Passed(std::move(request)),
base::Passed(std::move(client_info))));
}
-void GpuMain::CreateDisplayCompositorOnCompositorThread(
+void GpuMain::CreateFrameSinkManagerOnCompositorThread(
gpu::ImageFactory* image_factory,
mojom::GpuServicePtrInfo gpu_service_info,
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtrInfo client_info) {
- DCHECK(!display_compositor_);
- cc::mojom::DisplayCompositorClientPtr client;
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtrInfo client_info) {
+ DCHECK(!frame_sink_manager_);
+ cc::mojom::FrameSinkManagerClientPtr client;
client.Bind(std::move(client_info));
gpu_internal_.Bind(std::move(gpu_service_info));
- display_compositor_ = base::MakeUnique<DisplayCompositor>(
- gpu_command_service_, base::MakeUnique<ServerGpuMemoryBufferManager>(
- gpu_internal_.get(), 1 /* client_id */),
- image_factory, std::move(request), std::move(client));
+ display_provider_ = base::MakeUnique<MusDisplayProvider>(
+ gpu_command_service_,
+ base::MakeUnique<ServerGpuMemoryBufferManager>(gpu_internal_.get(),
+ 1 /* client_id */),
+ image_factory);
+
+ frame_sink_manager_ = base::MakeUnique<viz::MojoFrameSinkManager>(
+ true, display_provider_.get(), std::move(request), std::move(client));
}
void GpuMain::TearDownOnCompositorThread() {
- display_compositor_.reset();
+ frame_sink_manager_.reset();
+ display_provider_.reset();
gpu_internal_.reset();
}
@@ -225,16 +230,19 @@ void GpuMain::TearDownOnGpuThread() {
void GpuMain::CreateGpuServiceOnGpuThread(
mojom::GpuServiceRequest request,
mojom::GpuHostPtrInfo gpu_host_info,
- const gpu::GpuPreferences& preferences) {
+ const gpu::GpuPreferences& preferences,
+ gpu::GpuProcessActivityFlags activity_flags) {
mojom::GpuHostPtr gpu_host;
gpu_host.Bind(std::move(gpu_host_info));
- gpu_service_->InitializeWithHost(std::move(gpu_host), preferences);
+ gpu_service_->UpdateGPUInfoFromPreferences(preferences);
+ gpu_service_->InitializeWithHost(std::move(gpu_host),
+ std::move(activity_flags));
gpu_service_->Bind(std::move(request));
- if (pending_display_compositor_request_.is_pending()) {
- CreateDisplayCompositorInternal(
- std::move(pending_display_compositor_request_),
- std::move(pending_display_compositor_client_info_));
+ if (pending_frame_sink_manager_request_.is_pending()) {
+ CreateFrameSinkManagerInternal(
+ std::move(pending_frame_sink_manager_request_),
+ std::move(pending_frame_sink_manager_client_info_));
}
}
diff --git a/chromium/services/ui/gpu/gpu_main.h b/chromium/services/ui/gpu/gpu_main.h
index a5c859d9460..005c6d526c3 100644
--- a/chromium/services/ui/gpu/gpu_main.h
+++ b/chromium/services/ui/gpu/gpu_main.h
@@ -5,18 +5,24 @@
#ifndef SERVICES_UI_GPU_GPU_MAIN_H_
#define SERVICES_UI_GPU_GPU_MAIN_H_
+#include "base/power_monitor/power_monitor.h"
#include "base/threading/thread.h"
#include "gpu/ipc/in_process_command_buffer.h"
#include "gpu/ipc/service/gpu_init.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "services/ui/gpu/interfaces/gpu_main.mojom.h"
#include "services/ui/gpu/interfaces/gpu_service.mojom.h"
-#include "services/ui/surfaces/display_compositor.h"
namespace gpu {
class GpuMemoryBufferFactory;
class ImageFactory;
}
+namespace viz {
+class DisplayProvider;
+class MojoFrameSinkManager;
+}
+
namespace ui {
class GpuService;
@@ -29,10 +35,11 @@ class GpuMain : public gpu::GpuSandboxHelper, public mojom::GpuMain {
// mojom::GpuMain implementation:
void CreateGpuService(mojom::GpuServiceRequest request,
mojom::GpuHostPtr gpu_host,
- const gpu::GpuPreferences& preferences) override;
- void CreateDisplayCompositor(
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtr client) override;
+ const gpu::GpuPreferences& preferences,
+ mojo::ScopedSharedBufferHandle activity_flags) override;
+ void CreateFrameSinkManager(
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtr client) override;
void OnStart();
@@ -43,17 +50,18 @@ class GpuMain : public gpu::GpuSandboxHelper, public mojom::GpuMain {
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
scoped_refptr<base::SingleThreadTaskRunner> compositor_runner);
- void CreateDisplayCompositorInternal(
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtrInfo client_info);
- void CreateDisplayCompositorOnCompositorThread(
+ void CreateFrameSinkManagerInternal(
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtrInfo client_info);
+ void CreateFrameSinkManagerOnCompositorThread(
gpu::ImageFactory* image_factory,
mojom::GpuServicePtrInfo gpu_service_info,
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtrInfo client_info);
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtrInfo client_info);
void CreateGpuServiceOnGpuThread(mojom::GpuServiceRequest request,
mojom::GpuHostPtrInfo gpu_host_info,
- const gpu::GpuPreferences& preferences);
+ const gpu::GpuPreferences& preferences,
+ gpu::GpuProcessActivityFlags activity_flags);
void BindGpuInternalOnGpuThread(mojom::GpuServiceRequest request);
void TearDownOnCompositorThread();
@@ -67,36 +75,41 @@ class GpuMain : public gpu::GpuSandboxHelper, public mojom::GpuMain {
std::unique_ptr<gpu::GpuInit> gpu_init_;
std::unique_ptr<GpuService> gpu_service_;
- // The message-pipe used by the DisplayCompositor to request gpu memory
+ // The message-pipe used by the FrameSinkManager to request gpu memory
// buffers.
mojom::GpuServicePtr gpu_internal_;
- // The InCommandCommandBuffer::Service used by the display compositor.
+ // The InCommandCommandBuffer::Service used by the frame sink manager.
scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_command_service_;
// If the gpu service is not yet ready then we stash pending MessagePipes in
// these member variables.
- cc::mojom::DisplayCompositorRequest pending_display_compositor_request_;
- cc::mojom::DisplayCompositorClientPtrInfo
- pending_display_compositor_client_info_;
+ cc::mojom::FrameSinkManagerRequest pending_frame_sink_manager_request_;
+ cc::mojom::FrameSinkManagerClientPtrInfo
+ pending_frame_sink_manager_client_info_;
- std::unique_ptr<DisplayCompositor> display_compositor_;
+ // Provides mojo interfaces for creating and managing FrameSinks.
+ std::unique_ptr<viz::MojoFrameSinkManager> frame_sink_manager_;
+ std::unique_ptr<viz::DisplayProvider> display_provider_;
std::unique_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
// The main thread for Gpu.
base::Thread gpu_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> gpu_thread_task_runner_;
// The thread that handles IO events for Gpu.
base::Thread io_thread_;
- // The display compositor gets its own thread in mus-gpu. The gpu service,
+ // The frame sink manager gets its own thread in mus-gpu. The gpu service,
// where GL commands are processed resides on its own thread. Various
- // components of the display compositor such as Display, ResourceProvider,
+ // components of the frame sink manager such as Display, ResourceProvider,
// and GLRenderer block on sync tokens from other command buffers. Thus,
// the gpu service must live on a separate thread.
base::Thread compositor_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_thread_task_runner_;
+ base::PowerMonitor power_monitor_;
mojo::Binding<mojom::GpuMain> binding_;
DISALLOW_COPY_AND_ASSIGN(GpuMain);
diff --git a/chromium/services/ui/gpu/gpu_service.cc b/chromium/services/ui/gpu/gpu_service.cc
index f5e5b1f179b..146e54890d4 100644
--- a/chromium/services/ui/gpu/gpu_service.cc
+++ b/chromium/services/ui/gpu/gpu_service.cc
@@ -6,7 +6,9 @@
#include "base/bind.h"
#include "base/debug/crash_logging.h"
+#include "base/lazy_instance.h"
#include "base/memory/shared_memory.h"
+#include "base/message_loop/message_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "cc/output/in_process_context_provider.h"
@@ -19,10 +21,12 @@
#include "gpu/ipc/common/gpu_memory_buffer_support.h"
#include "gpu/ipc/common/memory_stats.h"
#include "gpu/ipc/gpu_in_process_thread_service.h"
+#include "gpu/ipc/service/gpu_channel.h"
#include "gpu/ipc/service/gpu_channel_manager.h"
#include "gpu/ipc/service/gpu_memory_buffer_factory.h"
#include "gpu/ipc/service/gpu_watchdog_thread.h"
#include "ipc/ipc_channel_handle.h"
+#include "ipc/ipc_sync_channel.h"
#include "ipc/ipc_sync_message_filter.h"
#include "media/gpu/ipc/service/gpu_jpeg_decode_accelerator.h"
#include "media/gpu/ipc/service/gpu_video_decode_accelerator.h"
@@ -35,51 +39,128 @@
#include "ui/gl/init/gl_factory.h"
#include "url/gurl.h"
+#if defined(OS_ANDROID)
+#include "base/android/throw_uncaught_exception.h"
+#include "media/gpu/content_video_view_overlay_allocator.h"
+#endif
+
namespace ui {
+namespace {
+
+static base::LazyInstance<base::Callback<
+ void(int severity, size_t message_start, const std::string& message)>>::
+ Leaky g_log_callback = LAZY_INSTANCE_INITIALIZER;
+
+bool GpuLogMessageHandler(int severity,
+ const char* file,
+ int line,
+ size_t message_start,
+ const std::string& message) {
+ g_log_callback.Get().Run(severity, message_start, message);
+ return false;
+}
+
+// Returns a callback which does a PostTask to run |callback| on the |runner|
+// task runner.
+template <typename Param>
+const base::Callback<void(const Param&)> WrapCallback(
+ scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const base::Callback<void(const Param&)>& callback) {
+ return base::Bind(
+ [](scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const base::Callback<void(const Param&)>& callback,
+ const Param& param) {
+ runner->PostTask(FROM_HERE, base::Bind(callback, param));
+ },
+ runner, callback);
+}
+
+void DestroyBinding(mojo::BindingSet<mojom::GpuService>* binding,
+ base::WaitableEvent* wait) {
+ binding->CloseAllBindings();
+ wait->Signal();
+}
+
+} // namespace
+
GpuService::GpuService(const gpu::GPUInfo& gpu_info,
std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread,
- gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
const gpu::GpuFeatureInfo& gpu_feature_info)
- : io_runner_(std::move(io_runner)),
- shutdown_event_(base::WaitableEvent::ResetPolicy::MANUAL,
- base::WaitableEvent::InitialState::NOT_SIGNALED),
+ : main_runner_(base::ThreadTaskRunnerHandle::Get()),
+ io_runner_(std::move(io_runner)),
watchdog_thread_(std::move(watchdog_thread)),
- gpu_memory_buffer_factory_(gpu_memory_buffer_factory),
+ gpu_memory_buffer_factory_(
+ gpu::GpuMemoryBufferFactory::CreateNativeType()),
+ gpu_workarounds_(base::CommandLine::ForCurrentProcess()),
gpu_info_(gpu_info),
gpu_feature_info_(gpu_feature_info),
- sync_point_manager_(nullptr) {}
+ sync_point_manager_(nullptr),
+ bindings_(base::MakeUnique<mojo::BindingSet<mojom::GpuService>>()),
+ weak_ptr_factory_(this) {
+ DCHECK(!io_runner_->BelongsToCurrentThread());
+ weak_ptr_ = weak_ptr_factory_.GetWeakPtr();
+}
GpuService::~GpuService() {
- bindings_.CloseAllBindings();
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ bind_task_tracker_.TryCancelAll();
+ logging::SetLogMessageHandler(nullptr);
+ g_log_callback.Get() =
+ base::Callback<void(int, size_t, const std::string&)>();
+ base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ if (io_runner_->PostTask(
+ FROM_HERE, base::Bind(&DestroyBinding, bindings_.get(), &wait))) {
+ wait.Wait();
+ }
media_gpu_channel_manager_.reset();
gpu_channel_manager_.reset();
owned_sync_point_manager_.reset();
- // Signal this event before destroying the child process. That way all
- // background threads can cleanup.
- // For example, in the renderer the RenderThread instances will be able to
- // notice shutdown before the render process begins waiting for them to exit.
- shutdown_event_.Signal();
+ // Signal this event before destroying the child process. That way all
+ // background threads can cleanup. For example, in the renderer the
+ // RenderThread instances will be able to notice shutdown before the render
+ // process begins waiting for them to exit.
+ if (owned_shutdown_event_)
+ owned_shutdown_event_->Signal();
}
-void GpuService::InitializeWithHost(mojom::GpuHostPtr gpu_host,
- const gpu::GpuPreferences& preferences,
- gpu::SyncPointManager* sync_point_manager,
- base::WaitableEvent* shutdown_event) {
- DCHECK(CalledOnValidThread());
+void GpuService::UpdateGPUInfoFromPreferences(
+ const gpu::GpuPreferences& preferences) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
DCHECK(!gpu_host_);
- gpu_host_ = std::move(gpu_host);
gpu_preferences_ = preferences;
gpu_info_.video_decode_accelerator_capabilities =
- media::GpuVideoDecodeAccelerator::GetCapabilities(gpu_preferences_);
+ media::GpuVideoDecodeAccelerator::GetCapabilities(gpu_preferences_,
+ gpu_workarounds_);
gpu_info_.video_encode_accelerator_supported_profiles =
media::GpuVideoEncodeAccelerator::GetSupportedProfiles(gpu_preferences_);
gpu_info_.jpeg_decode_accelerator_supported =
media::GpuJpegDecodeAcceleratorFactoryProvider::
IsAcceleratedJpegDecodeSupported();
- gpu_host_->DidInitialize(gpu_info_);
+ // Record initialization only after collecting the GPU info because that can
+ // take a significant amount of time.
+ gpu_info_.initialization_time = base::Time::Now() - start_time_;
+}
+
+void GpuService::InitializeWithHost(mojom::GpuHostPtr gpu_host,
+ gpu::GpuProcessActivityFlags activity_flags,
+ gpu::SyncPointManager* sync_point_manager,
+ base::WaitableEvent* shutdown_event) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ gpu_host->DidInitialize(gpu_info_, gpu_feature_info_);
+ gpu_host_ =
+ mojom::ThreadSafeGpuHostPtr::Create(gpu_host.PassInterface(), io_runner_);
+ if (!in_host_process_) {
+ // The global callback is reset from the dtor. So Unretained() here is safe.
+ // Note that the callback can be called from any thread. Consequently, the
+ // callback cannot use a WeakPtr.
+ g_log_callback.Get() =
+ base::Bind(&GpuService::RecordLogMessage, base::Unretained(this));
+ logging::SetLogMessageHandler(GpuLogMessageHandler);
+ }
sync_point_manager_ = sync_point_manager;
if (!sync_point_manager_) {
@@ -87,21 +168,53 @@ void GpuService::InitializeWithHost(mojom::GpuHostPtr gpu_host,
sync_point_manager_ = owned_sync_point_manager_.get();
}
+ shutdown_event_ = shutdown_event;
+ if (!shutdown_event_) {
+ owned_shutdown_event_ = base::MakeUnique<base::WaitableEvent>(
+ base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ shutdown_event_ = owned_shutdown_event_.get();
+ }
+
// Defer creation of the render thread. This is to prevent it from handling
// IPC messages before the sandbox has been enabled and all other necessary
// initialization has succeeded.
gpu_channel_manager_.reset(new gpu::GpuChannelManager(
- gpu_preferences_, this, watchdog_thread_.get(),
- base::ThreadTaskRunnerHandle::Get().get(), io_runner_.get(),
- shutdown_event ? shutdown_event : &shutdown_event_, sync_point_manager_,
- gpu_memory_buffer_factory_, gpu_feature_info_));
+ gpu_preferences_, gpu_workarounds_, this, watchdog_thread_.get(),
+ base::ThreadTaskRunnerHandle::Get(), io_runner_, sync_point_manager_,
+ gpu_memory_buffer_factory_.get(), gpu_feature_info_,
+ std::move(activity_flags)));
media_gpu_channel_manager_.reset(
new media::MediaGpuChannelManager(gpu_channel_manager_.get()));
+ if (watchdog_thread())
+ watchdog_thread()->AddPowerObserver();
}
void GpuService::Bind(mojom::GpuServiceRequest request) {
- bindings_.AddBinding(this, std::move(request));
+ if (main_runner_->BelongsToCurrentThread()) {
+ bind_task_tracker_.PostTask(
+ io_runner_.get(), FROM_HERE,
+ base::Bind(&GpuService::Bind, base::Unretained(this),
+ base::Passed(std::move(request))));
+ return;
+ }
+ bindings_->AddBinding(this, std::move(request));
+}
+
+gpu::ImageFactory* GpuService::gpu_image_factory() {
+ return gpu_memory_buffer_factory_
+ ? gpu_memory_buffer_factory_->AsImageFactory()
+ : nullptr;
+}
+
+void GpuService::RecordLogMessage(int severity,
+ size_t message_start,
+ const std::string& str) {
+ // This can be run from any thread.
+ std::string header = str.substr(0, message_start);
+ std::string message = str.substr(message_start);
+ (*gpu_host_)->RecordLogMessage(severity, header, message);
}
void GpuService::CreateGpuMemoryBuffer(
@@ -112,7 +225,8 @@ void GpuService::CreateGpuMemoryBuffer(
int client_id,
gpu::SurfaceHandle surface_handle,
const CreateGpuMemoryBufferCallback& callback) {
- DCHECK(CalledOnValidThread());
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ // This needs to happen in the IO thread.
callback.Run(gpu_memory_buffer_factory_->CreateGpuMemoryBuffer(
id, size, format, usage, client_id, surface_handle));
}
@@ -120,55 +234,136 @@ void GpuService::CreateGpuMemoryBuffer(
void GpuService::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
int client_id,
const gpu::SyncToken& sync_token) {
- DCHECK(CalledOnValidThread());
- if (gpu_channel_manager_)
- gpu_channel_manager_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuService::DestroyGpuMemoryBuffer, weak_ptr_,
+ id, client_id, sync_token));
+ return;
+ }
+ gpu_channel_manager_->DestroyGpuMemoryBuffer(id, client_id, sync_token);
}
void GpuService::GetVideoMemoryUsageStats(
const GetVideoMemoryUsageStatsCallback& callback) {
- gpu::VideoMemoryUsageStats video_memory_usage_stats;
- if (gpu_channel_manager_) {
- gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
- &video_memory_usage_stats);
+ if (io_runner_->BelongsToCurrentThread()) {
+ auto wrap_callback = WrapCallback(io_runner_, callback);
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuService::GetVideoMemoryUsageStats, weak_ptr_,
+ wrap_callback));
+ return;
}
+ gpu::VideoMemoryUsageStats video_memory_usage_stats;
+ gpu_channel_manager_->gpu_memory_manager()->GetVideoMemoryUsageStats(
+ &video_memory_usage_stats);
callback.Run(video_memory_usage_stats);
}
+void GpuService::RequestCompleteGpuInfo(
+ const RequestCompleteGpuInfoCallback& callback) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ auto wrap_callback = WrapCallback(io_runner_, callback);
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuService::RequestCompleteGpuInfo, weak_ptr_,
+ wrap_callback));
+ return;
+ }
+ UpdateGpuInfoPlatform();
+ callback.Run(gpu_info_);
+#if defined(OS_WIN)
+ if (!in_host_process_) {
+ // The unsandboxed GPU process fulfilled its duty. Rest in peace.
+ base::MessageLoop::current()->QuitWhenIdle();
+ }
+#endif
+}
+
+#if defined(OS_MACOSX)
+void GpuService::UpdateGpuInfoPlatform() {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ // gpu::CollectContextGraphicsInfo() is already called during gpu process
+ // initialization (see GpuInit::InitializeAndStartSandbox()) on non-mac
+ // platforms, and during in-browser gpu thread initialization on all platforms
+ // (See InProcessGpuThread::Init()).
+ if (in_host_process_)
+ return;
+
+ DCHECK_EQ(gpu::kCollectInfoNone, gpu_info_.context_info_state);
+ gpu::CollectInfoResult result = gpu::CollectContextGraphicsInfo(&gpu_info_);
+ switch (result) {
+ case gpu::kCollectInfoFatalFailure:
+ LOG(ERROR) << "gpu::CollectGraphicsInfo failed (fatal).";
+ // TODO(piman): can we signal overall failure?
+ break;
+ case gpu::kCollectInfoNonFatalFailure:
+ DVLOG(1) << "gpu::CollectGraphicsInfo failed (non-fatal).";
+ break;
+ case gpu::kCollectInfoNone:
+ NOTREACHED();
+ break;
+ case gpu::kCollectInfoSuccess:
+ break;
+ }
+ gpu::SetKeysForCrashLogging(gpu_info_);
+}
+#elif defined(OS_WIN)
+void GpuService::UpdateGpuInfoPlatform() {
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ // GPU full info collection should only happen on un-sandboxed GPU process
+ // or single process/in-process gpu mode on Windows.
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ DCHECK(command_line->HasSwitch("disable-gpu-sandbox") || in_host_process_);
+
+ // This is slow, but it's the only thing the unsandboxed GPU process does,
+ // and GpuDataManager prevents us from sending multiple collecting requests,
+ // so it's OK to be blocking.
+ gpu::GetDxDiagnostics(&gpu_info_.dx_diagnostics);
+ gpu_info_.dx_diagnostics_info_state = gpu::kCollectInfoSuccess;
+}
+#else
+void GpuService::UpdateGpuInfoPlatform() {}
+#endif
+
void GpuService::DidCreateOffscreenContext(const GURL& active_url) {
- gpu_host_->DidCreateOffscreenContext(active_url);
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->DidCreateOffscreenContext(active_url);
}
void GpuService::DidDestroyChannel(int client_id) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
media_gpu_channel_manager_->RemoveChannel(client_id);
- gpu_host_->DidDestroyChannel(client_id);
+ (*gpu_host_)->DidDestroyChannel(client_id);
}
void GpuService::DidDestroyOffscreenContext(const GURL& active_url) {
- gpu_host_->DidDestroyOffscreenContext(active_url);
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->DidDestroyOffscreenContext(active_url);
}
void GpuService::DidLoseContext(bool offscreen,
gpu::error::ContextLostReason reason,
const GURL& active_url) {
- gpu_host_->DidLoseContext(offscreen, reason, active_url);
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->DidLoseContext(offscreen, reason, active_url);
}
void GpuService::StoreShaderToDisk(int client_id,
const std::string& key,
const std::string& shader) {
- gpu_host_->StoreShaderToDisk(client_id, key, shader);
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->StoreShaderToDisk(client_id, key, shader);
}
#if defined(OS_WIN)
void GpuService::SendAcceleratedSurfaceCreatedChildWindow(
gpu::SurfaceHandle parent_window,
gpu::SurfaceHandle child_window) {
- gpu_host_->SetChildSurface(parent_window, child_window);
+ DCHECK(main_runner_->BelongsToCurrentThread());
+ (*gpu_host_)->SetChildSurface(parent_window, child_window);
}
#endif
void GpuService::SetActiveURL(const GURL& url) {
+ DCHECK(main_runner_->BelongsToCurrentThread());
constexpr char kActiveURL[] = "url-chunk";
base::debug::SetCrashKeyValue(kActiveURL, url.possibly_invalid_spec());
}
@@ -178,23 +373,137 @@ void GpuService::EstablishGpuChannel(
uint64_t client_tracing_id,
bool is_gpu_host,
const EstablishGpuChannelCallback& callback) {
- DCHECK(CalledOnValidThread());
-
- if (!gpu_channel_manager_) {
- callback.Run(mojo::ScopedMessagePipeHandle());
+ if (io_runner_->BelongsToCurrentThread()) {
+ EstablishGpuChannelCallback wrap_callback = base::Bind(
+ [](scoped_refptr<base::SingleThreadTaskRunner> runner,
+ const EstablishGpuChannelCallback& cb,
+ mojo::ScopedMessagePipeHandle handle) {
+ runner->PostTask(FROM_HERE,
+ base::Bind(cb, base::Passed(std::move(handle))));
+ },
+ io_runner_, callback);
+ main_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&GpuService::EstablishGpuChannel, weak_ptr_, client_id,
+ client_tracing_id, is_gpu_host, wrap_callback));
return;
}
- const bool preempts = is_gpu_host;
- const bool allow_view_command_buffers = is_gpu_host;
- const bool allow_real_time_streams = is_gpu_host;
- mojo::ScopedMessagePipeHandle channel_handle;
- IPC::ChannelHandle handle = gpu_channel_manager_->EstablishChannel(
- client_id, client_tracing_id, preempts, allow_view_command_buffers,
- allow_real_time_streams);
- channel_handle.reset(handle.mojo_handle);
+ gpu::GpuChannel* gpu_channel = gpu_channel_manager_->EstablishChannel(
+ client_id, client_tracing_id, is_gpu_host);
+
+ mojo::MessagePipe pipe;
+ gpu_channel->Init(base::MakeUnique<gpu::SyncChannelFilteredSender>(
+ pipe.handle0.release(), gpu_channel, io_runner_, shutdown_event_));
+
media_gpu_channel_manager_->AddChannel(client_id);
- callback.Run(std::move(channel_handle));
+
+ callback.Run(std::move(pipe.handle1));
+}
+
+void GpuService::CloseChannel(int32_t client_id) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuService::CloseChannel, weak_ptr_, client_id));
+ return;
+ }
+ gpu_channel_manager_->RemoveChannel(client_id);
+}
+
+void GpuService::LoadedShader(const std::string& data) {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuService::LoadedShader, weak_ptr_, data));
+ return;
+ }
+ gpu_channel_manager_->PopulateShaderCache(data);
+}
+
+void GpuService::DestroyingVideoSurface(
+ int32_t surface_id,
+ const DestroyingVideoSurfaceCallback& callback) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+#if defined(OS_ANDROID)
+ main_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(
+ [](int32_t surface_id) {
+ media::ContentVideoViewOverlayAllocator::GetInstance()
+ ->OnSurfaceDestroyed(surface_id);
+ },
+ surface_id),
+ callback);
+#else
+ NOTREACHED() << "DestroyingVideoSurface() not supported on this platform.";
+#endif
+}
+
+void GpuService::WakeUpGpu() {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(FROM_HERE,
+ base::Bind(&GpuService::WakeUpGpu, weak_ptr_));
+ return;
+ }
+#if defined(OS_ANDROID)
+ gpu_channel_manager_->WakeUpGpu();
+#else
+ NOTREACHED() << "WakeUpGpu() not supported on this platform.";
+#endif
+}
+
+void GpuService::GpuSwitched() {
+ DVLOG(1) << "GPU: GPU has switched";
+ if (!in_host_process_)
+ ui::GpuSwitchingManager::GetInstance()->NotifyGpuSwitched();
+}
+
+void GpuService::DestroyAllChannels() {
+ if (io_runner_->BelongsToCurrentThread()) {
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind(&GpuService::DestroyAllChannels, weak_ptr_));
+ return;
+ }
+ DVLOG(1) << "GPU: Removing all contexts";
+ gpu_channel_manager_->DestroyAllChannels();
+}
+
+void GpuService::Crash() {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ DVLOG(1) << "GPU: Simulating GPU crash";
+ // Good bye, cruel world.
+ volatile int* it_s_the_end_of_the_world_as_we_know_it = NULL;
+ *it_s_the_end_of_the_world_as_we_know_it = 0xdead;
+}
+
+void GpuService::Hang() {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+
+ main_runner_->PostTask(FROM_HERE, base::Bind([] {
+ DVLOG(1) << "GPU: Simulating GPU hang";
+ for (;;) {
+ // Do not sleep here. The GPU watchdog timer tracks
+ // the amount of user time this thread is using and
+ // it doesn't use much while calling Sleep.
+ }
+ }));
+}
+
+void GpuService::ThrowJavaException() {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+#if defined(OS_ANDROID)
+ main_runner_->PostTask(
+ FROM_HERE, base::Bind([] { base::android::ThrowUncaughtException(); }));
+#else
+ NOTREACHED() << "Java exception not supported on this platform.";
+#endif
+}
+
+void GpuService::Stop(const StopCallback& callback) {
+ DCHECK(io_runner_->BelongsToCurrentThread());
+ main_runner_->PostTaskAndReply(FROM_HERE, base::Bind([] {
+ base::MessageLoop::current()->QuitWhenIdle();
+ }),
+ callback);
}
} // namespace ui
diff --git a/chromium/services/ui/gpu/gpu_service.h b/chromium/services/ui/gpu/gpu_service.h
index 7052cf42970..f07519bb663 100644
--- a/chromium/services/ui/gpu/gpu_service.h
+++ b/chromium/services/ui/gpu/gpu_service.h
@@ -7,10 +7,12 @@
#include "base/callback.h"
#include "base/synchronization/waitable_event.h"
+#include "base/task/cancelable_task_tracker.h"
#include "base/threading/non_thread_safe.h"
#include "base/threading/thread.h"
#include "build/build_config.h"
#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+#include "gpu/command_buffer/common/activity_flags.h"
#include "gpu/command_buffer/service/gpu_preferences.h"
#include "gpu/config/gpu_info.h"
#include "gpu/ipc/common/surface_handle.h"
@@ -42,19 +44,19 @@ class GpuMain;
// the window server) over the mojom APIs. This is responsible for setting up
// the connection to clients, allocating/free'ing gpu memory etc.
class GpuService : public gpu::GpuChannelManagerDelegate,
- public mojom::GpuService,
- public base::NonThreadSafe {
+ public mojom::GpuService {
public:
GpuService(const gpu::GPUInfo& gpu_info,
std::unique_ptr<gpu::GpuWatchdogThread> watchdog,
- gpu::GpuMemoryBufferFactory* memory_buffer_factory,
scoped_refptr<base::SingleThreadTaskRunner> io_runner,
const gpu::GpuFeatureInfo& gpu_feature_info);
~GpuService() override;
+ void UpdateGPUInfoFromPreferences(const gpu::GpuPreferences& preferences);
+
void InitializeWithHost(mojom::GpuHostPtr gpu_host,
- const gpu::GpuPreferences& preferences,
+ gpu::GpuProcessActivityFlags activity_flags,
gpu::SyncPointManager* sync_point_manager = nullptr,
base::WaitableEvent* shutdown_event = nullptr);
void Bind(mojom::GpuServiceRequest request);
@@ -67,15 +69,29 @@ class GpuService : public gpu::GpuChannelManagerDelegate,
return gpu_channel_manager_.get();
}
+ gpu::ImageFactory* gpu_image_factory();
+
gpu::GpuWatchdogThread* watchdog_thread() { return watchdog_thread_.get(); }
const gpu::GpuFeatureInfo& gpu_feature_info() const {
return gpu_feature_info_;
}
+ void set_in_host_process(bool in_host_process) {
+ in_host_process_ = in_host_process;
+ }
+
+ void set_start_time(base::Time start_time) { start_time_ = start_time; }
+
+ const gpu::GPUInfo& gpu_info() const { return gpu_info_; }
+
private:
friend class GpuMain;
+ void RecordLogMessage(int severity,
+ size_t message_start,
+ const std::string& message);
+
gpu::SyncPointManager* sync_point_manager() { return sync_point_manager_; }
gpu::gles2::MailboxManager* mailbox_manager() {
@@ -86,7 +102,7 @@ class GpuService : public gpu::GpuChannelManagerDelegate,
return gpu_channel_manager_->share_group();
}
- const gpu::GPUInfo& gpu_info() const { return gpu_info_; }
+ void UpdateGpuInfoPlatform();
// gpu::GpuChannelManagerDelegate:
void DidCreateOffscreenContext(const GURL& active_url) override;
@@ -111,6 +127,7 @@ class GpuService : public gpu::GpuChannelManagerDelegate,
uint64_t client_tracing_id,
bool is_gpu_host,
const EstablishGpuChannelCallback& callback) override;
+ void CloseChannel(int32_t client_id) override;
void CreateGpuMemoryBuffer(
gfx::GpuMemoryBufferId id,
const gfx::Size& size,
@@ -124,25 +141,38 @@ class GpuService : public gpu::GpuChannelManagerDelegate,
const gpu::SyncToken& sync_token) override;
void GetVideoMemoryUsageStats(
const GetVideoMemoryUsageStatsCallback& callback) override;
-
+ void RequestCompleteGpuInfo(
+ const RequestCompleteGpuInfoCallback& callback) override;
+ void LoadedShader(const std::string& data) override;
+ void DestroyingVideoSurface(
+ int32_t surface_id,
+ const DestroyingVideoSurfaceCallback& callback) override;
+ void WakeUpGpu() override;
+ void GpuSwitched() override;
+ void DestroyAllChannels() override;
+ void Crash() override;
+ void Hang() override;
+ void ThrowJavaException() override;
+ void Stop(const StopCallback& callback) override;
+
+ scoped_refptr<base::SingleThreadTaskRunner> main_runner_;
scoped_refptr<base::SingleThreadTaskRunner> io_runner_;
- // An event that will be signalled when we shutdown.
- base::WaitableEvent shutdown_event_;
-
std::unique_ptr<gpu::GpuWatchdogThread> watchdog_thread_;
- gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory_;
+ std::unique_ptr<gpu::GpuMemoryBufferFactory> gpu_memory_buffer_factory_;
gpu::GpuPreferences gpu_preferences_;
+ gpu::GpuDriverBugWorkarounds gpu_workarounds_;
+
// Information about the GPU, such as device and vendor ID.
gpu::GPUInfo gpu_info_;
// Information about general chrome feature support for the GPU.
gpu::GpuFeatureInfo gpu_feature_info_;
- mojom::GpuHostPtr gpu_host_;
+ scoped_refptr<mojom::ThreadSafeGpuHostPtr> gpu_host_;
std::unique_ptr<gpu::GpuChannelManager> gpu_channel_manager_;
std::unique_ptr<media::MediaGpuChannelManager> media_gpu_channel_manager_;
@@ -151,7 +181,21 @@ class GpuService : public gpu::GpuChannelManagerDelegate,
std::unique_ptr<gpu::SyncPointManager> owned_sync_point_manager_;
gpu::SyncPointManager* sync_point_manager_ = nullptr;
- mojo::BindingSet<mojom::GpuService> bindings_;
+ // An event that will be signalled when we shutdown. On some platforms it
+ // comes from external sources.
+ std::unique_ptr<base::WaitableEvent> owned_shutdown_event_;
+ base::WaitableEvent* shutdown_event_ = nullptr;
+
+ // Whether this is running in the same process as the gpu host.
+ bool in_host_process_ = false;
+ base::Time start_time_;
+
+ // Used to track the task to bind a GpuServiceRequest on the io thread.
+ base::CancelableTaskTracker bind_task_tracker_;
+ std::unique_ptr<mojo::BindingSet<mojom::GpuService>> bindings_;
+
+ base::WeakPtr<GpuService> weak_ptr_;
+ base::WeakPtrFactory<GpuService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GpuService);
};
diff --git a/chromium/services/ui/gpu/gpu_service_unittest.cc b/chromium/services/ui/gpu/gpu_service_unittest.cc
new file mode 100644
index 00000000000..f79e1acd195
--- /dev/null
+++ b/chromium/services/ui/gpu/gpu_service_unittest.cc
@@ -0,0 +1,100 @@
+// 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/ui/gpu/gpu_service.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/ipc/service/gpu_watchdog_thread.h"
+#include "services/ui/public/interfaces/gpu.mojom.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+namespace test {
+
+class GpuServiceTest : public testing::Test {
+ public:
+ GpuServiceTest()
+ : io_thread_("TestIOThread"),
+ wait_(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED) {}
+ ~GpuServiceTest() override {}
+
+ GpuService* gpu_service() { return gpu_service_.get(); }
+
+ void DestroyService() { gpu_service_ = nullptr; }
+
+ void BlockIOThread() {
+ wait_.Reset();
+ io_runner()->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Wait,
+ base::Unretained(&wait_)));
+ }
+
+ void UnblockIOThread() {
+ DCHECK(!wait_.IsSignaled());
+ wait_.Signal();
+ }
+
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner() {
+ return io_thread_.task_runner();
+ }
+
+ // testing::Test
+ void SetUp() override {
+ ASSERT_TRUE(io_thread_.Start());
+ gpu_service_ = base::MakeUnique<GpuService>(
+ gpu::GPUInfo(), nullptr /* watchdog_thread */, io_thread_.task_runner(),
+ gpu::GpuFeatureInfo());
+ }
+
+ void TearDown() override {
+ DestroyService();
+ base::RunLoop runloop;
+ runloop.RunUntilIdle();
+ io_thread_.Stop();
+ }
+
+ private:
+ base::MessageLoop message_loop_;
+ base::Thread io_thread_;
+ std::unique_ptr<GpuService> gpu_service_;
+ base::WaitableEvent wait_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuServiceTest);
+};
+
+// Tests that GpuService can be destroyed before Bind() succeeds on the IO
+// thread.
+TEST_F(GpuServiceTest, ServiceDestroyedBeforeBind) {
+ mojom::GpuServicePtr ptr;
+ mojom::GpuServiceRequest request(&ptr);
+
+ // Block the IO thread to make sure that the GpuService is destroyed before
+ // the binding happens on the IO thread.
+ BlockIOThread();
+ gpu_service()->Bind(std::move(request));
+ UnblockIOThread();
+ DestroyService();
+}
+
+// Tests ghat GpuService can be destroyed after Bind() succeeds on the IO
+// thread.
+TEST_F(GpuServiceTest, ServiceDestroyedAfterBind) {
+ mojom::GpuServicePtr ptr;
+ mojom::GpuServiceRequest request(&ptr);
+ gpu_service()->Bind(std::move(request));
+ base::WaitableEvent wait(base::WaitableEvent::ResetPolicy::MANUAL,
+ base::WaitableEvent::InitialState::NOT_SIGNALED);
+ io_runner()->PostTask(FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
+ base::Unretained(&wait)));
+ wait.Wait();
+ DestroyService();
+}
+
+} // namespace test
+} // namespace ui
diff --git a/chromium/services/ui/gpu/interfaces/gpu_host.mojom b/chromium/services/ui/gpu/interfaces/gpu_host.mojom
index 1d2b8fbb81b..b7d620032ee 100644
--- a/chromium/services/ui/gpu/interfaces/gpu_host.mojom
+++ b/chromium/services/ui/gpu/interfaces/gpu_host.mojom
@@ -4,6 +4,7 @@
module ui.mojom;
+import "gpu/ipc/common/gpu_feature_info.mojom";
import "gpu/ipc/common/gpu_info.mojom";
import "gpu/ipc/common/surface_handle.mojom";
import "services/ui/gpu/interfaces/context_lost_reason.mojom";
@@ -12,7 +13,10 @@ import "url/mojo/url.mojom";
// Communication channel from the gpu process to the gpu host. This interface
// should never have any sync function calls.
interface GpuHost {
- DidInitialize(gpu.mojom.GpuInfo gpu_info);
+ DidInitialize(gpu.mojom.GpuInfo gpu_info,
+ gpu.mojom.GpuFeatureInfo gpu_feature_info);
+ DidFailInitialize();
+
DidCreateOffscreenContext(url.mojom.Url url);
DidDestroyOffscreenContext(url.mojom.Url url);
@@ -24,4 +28,6 @@ interface GpuHost {
SetChildSurface(gpu.mojom.SurfaceHandle parent,
gpu.mojom.SurfaceHandle child);
StoreShaderToDisk(int32 client_id, string key, string shader);
+
+ RecordLogMessage(int32 severity, string header, string message);
};
diff --git a/chromium/services/ui/gpu/interfaces/gpu_main.mojom b/chromium/services/ui/gpu/interfaces/gpu_main.mojom
index 985b823b736..c34d1231c53 100644
--- a/chromium/services/ui/gpu/interfaces/gpu_main.mojom
+++ b/chromium/services/ui/gpu/interfaces/gpu_main.mojom
@@ -4,7 +4,7 @@
module ui.mojom;
-import "cc/ipc/display_compositor.mojom";
+import "cc/ipc/frame_sink_manager.mojom";
import "gpu/ipc/common/gpu_preferences.mojom";
import "services/ui/gpu/interfaces/gpu_host.mojom";
import "services/ui/gpu/interfaces/gpu_service.mojom";
@@ -12,11 +12,12 @@ import "services/ui/gpu/interfaces/gpu_service.mojom";
// This is the primordial interface used to (re)start the mus-gpu bundle
// of services.
interface GpuMain {
- CreateDisplayCompositor(
- cc.mojom.DisplayCompositor& display_compositor,
- cc.mojom.DisplayCompositorClient display_compositor_client);
+ CreateFrameSinkManager(
+ cc.mojom.FrameSinkManager& frame_sink_manager,
+ cc.mojom.FrameSinkManagerClient frame_sink_manager_client);
CreateGpuService(GpuService& gpu_service,
GpuHost gpu_host,
- gpu.mojom.GpuPreferences preferences);
+ gpu.mojom.GpuPreferences preferences,
+ handle<shared_buffer>? activity_flags);
};
diff --git a/chromium/services/ui/gpu/interfaces/gpu_service.mojom b/chromium/services/ui/gpu/interfaces/gpu_service.mojom
index 6f420bd62b4..c4bbea22702 100644
--- a/chromium/services/ui/gpu/interfaces/gpu_service.mojom
+++ b/chromium/services/ui/gpu/interfaces/gpu_service.mojom
@@ -4,7 +4,6 @@
module ui.mojom;
-import "cc/ipc/display_compositor.mojom";
import "gpu/ipc/common/gpu_info.mojom";
import "gpu/ipc/common/memory_stats.mojom";
import "gpu/ipc/common/surface_handle.mojom";
@@ -18,7 +17,11 @@ interface GpuService {
EstablishGpuChannel(int32 client_id,
uint64 client_tracing_id,
bool is_gpu_host)
- => (handle<message_pipe> channel_handle);
+ => (handle<message_pipe>? channel_handle);
+
+ // Tells the GPU process to close the channel identified by |client_id|.
+ // If no channel can be identified, do nothing.
+ CloseChannel(int32 client_id);
[Sync]
CreateGpuMemoryBuffer(gfx.mojom.GpuMemoryBufferId id,
@@ -34,4 +37,26 @@ interface GpuService {
gpu.mojom.SyncToken sync_token);
GetVideoMemoryUsageStats() => (gpu.mojom.VideoMemoryUsageStats stats);
+
+ RequestCompleteGpuInfo() => (gpu.mojom.GpuInfo gpu_info);
+
+ // Notify GPU that a shader was loaded from disk.
+ LoadedShader(string data);
+
+ // Tells GPU to release the surface because it's being destroyed.
+ DestroyingVideoSurface(int32 surface_id) => ();
+
+ // Tells GPU to wake up the GPU because we're about to draw.
+ WakeUpGpu();
+
+ // Tells GPU that host has seen a GPU switch. This can happen when the display
+ // is reconfigured, for example.
+ GpuSwitched();
+
+ DestroyAllChannels();
+
+ Crash();
+ Hang();
+ ThrowJavaException();
+ Stop() => ();
};
diff --git a/chromium/services/ui/ime/ime_server_impl.cc b/chromium/services/ui/ime/ime_server_impl.cc
index 19c89b5b492..7d26f0ed4a8 100644
--- a/chromium/services/ui/ime/ime_server_impl.cc
+++ b/chromium/services/ui/ime/ime_server_impl.cc
@@ -17,7 +17,7 @@ IMEServerImpl::~IMEServerImpl() {}
void IMEServerImpl::Init(service_manager::Connector* connector,
bool is_test_config) {
if (is_test_config)
- connector->Connect("test_ime_driver");
+ connector->StartService("test_ime_driver");
// For non test configs we assume a client registers with us.
}
diff --git a/chromium/services/ui/ime/ime_unittest.cc b/chromium/services/ui/ime/ime_unittest.cc
index 582521ffc0b..f33275a67fb 100644
--- a/chromium/services/ui/ime/ime_unittest.cc
+++ b/chromium/services/ui/ime/ime_unittest.cc
@@ -56,7 +56,7 @@ class IMEAppTest : public service_manager::test::ServiceTest {
void SetUp() override {
ServiceTest::SetUp();
// test_ime_driver will register itself as the current IMEDriver.
- connector()->Connect("test_ime_driver");
+ connector()->StartService("test_ime_driver");
connector()->BindInterface(ui::mojom::kServiceName, &ime_server_);
}
diff --git a/chromium/services/ui/ime/test_ime_driver/test_ime_application.cc b/chromium/services/ui/ime/test_ime_driver/test_ime_application.cc
index 6804ee4c281..b10851dd9c4 100644
--- a/chromium/services/ui/ime/test_ime_driver/test_ime_application.cc
+++ b/chromium/services/ui/ime/test_ime_driver/test_ime_application.cc
@@ -30,11 +30,5 @@ void TestIMEApplication::OnStart() {
ime_registrar->RegisterDriver(std::move(ime_driver_ptr));
}
-bool TestIMEApplication::OnConnect(
- const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- return true;
-}
-
} // namespace test
} // namespace ui
diff --git a/chromium/services/ui/ime/test_ime_driver/test_ime_application.h b/chromium/services/ui/ime/test_ime_driver/test_ime_application.h
index a194f6d2d63..ecab0081dcb 100644
--- a/chromium/services/ui/ime/test_ime_driver/test_ime_application.h
+++ b/chromium/services/ui/ime/test_ime_driver/test_ime_application.h
@@ -19,8 +19,6 @@ class TestIMEApplication : public service_manager::Service {
private:
// service_manager::Service:
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
DISALLOW_COPY_AND_ASSIGN(TestIMEApplication);
};
diff --git a/chromium/services/ui/input_devices/input_device_server.cc b/chromium/services/ui/input_devices/input_device_server.cc
index d254cba9df1..3983137bd46 100644
--- a/chromium/services/ui/input_devices/input_device_server.cc
+++ b/chromium/services/ui/input_devices/input_device_server.cc
@@ -7,7 +7,7 @@
#include <utility>
#include <vector>
-#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "ui/events/devices/input_device.h"
#include "ui/events/devices/touchscreen_device.h"
@@ -34,7 +34,7 @@ bool InputDeviceServer::IsRegisteredAsObserver() const {
}
void InputDeviceServer::AddInterface(
- service_manager::InterfaceRegistry* registry) {
+ service_manager::BinderRegistry* registry) {
DCHECK(IsRegisteredAsObserver());
registry->AddInterface<mojom::InputDeviceServer>(this);
}
diff --git a/chromium/services/ui/input_devices/input_device_server.h b/chromium/services/ui/input_devices/input_device_server.h
index a84651deafa..1e7d91cdf6a 100644
--- a/chromium/services/ui/input_devices/input_device_server.h
+++ b/chromium/services/ui/input_devices/input_device_server.h
@@ -8,14 +8,13 @@
#include "base/macros.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_ptr_set.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/ui/public/interfaces/input_devices/input_device_server.mojom.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/input_device_event_observer.h"
namespace service_manager {
-class InterfaceRegistry;
+class BinderRegistry;
}
namespace ui {
@@ -39,7 +38,7 @@ class InputDeviceServer
// connect. You should have already called RegisterAsObserver() to get local
// input-device event updates and checked it was successful by calling
// IsRegisteredAsObserver().
- void AddInterface(service_manager::InterfaceRegistry* registry);
+ void AddInterface(service_manager::BinderRegistry* registry);
// mojom::InputDeviceServer:
void AddObserver(mojom::InputDeviceObserverMojoPtr observer) override;
diff --git a/chromium/services/ui/manifest.json b/chromium/services/ui/manifest.json
index d49775f2fcd..ea834902095 100644
--- a/chromium/services/ui/manifest.json
+++ b/chromium/services/ui/manifest.json
@@ -11,7 +11,6 @@
"app": [
"discardable_memory::mojom::DiscardableSharedMemoryManager",
"ui::mojom::Clipboard",
- "ui::mojom::DisplayCompositor",
"ui::mojom::DisplayManager",
"ui::mojom::Gpu",
"ui::mojom::IMEServer",
@@ -49,9 +48,9 @@
"window_manager": [
"discardable_memory::mojom::DiscardableSharedMemoryManager",
"display::mojom::DisplayController",
+ "display::mojom::NativeDisplayDelegate",
"ui::mojom::AccessibilityManager",
"ui::mojom::Clipboard",
- "ui::mojom::DisplayCompositor",
"ui::mojom::DisplayManager",
"ui::mojom::Gpu",
"ui::mojom::IMEServer",
diff --git a/chromium/services/ui/public/cpp/BUILD.gn b/chromium/services/ui/public/cpp/BUILD.gn
index 0d050272952..9875d3dbe6a 100644
--- a/chromium/services/ui/public/cpp/BUILD.gn
+++ b/chromium/services/ui/public/cpp/BUILD.gn
@@ -8,9 +8,9 @@ import("//build/config/ui.gni")
# implementation (and private haders) are in 'internal'.
source_set("cpp") {
sources = [
+ "client_compositor_frame_sink.h",
"property_type_converters.h",
"raster_thread_helper.h",
- "window_compositor_frame_sink.h",
]
public_deps = [
@@ -54,9 +54,10 @@ source_set("internal") {
]
sources = [
+ "client_compositor_frame_sink.cc",
+ "client_compositor_frame_sink.h",
"property_type_converters.cc",
"raster_thread_helper.cc",
- "window_compositor_frame_sink.cc",
]
deps = [
diff --git a/chromium/services/ui/public/cpp/OWNERS b/chromium/services/ui/public/cpp/OWNERS
index f6e789abbdc..560bfc3da0e 100644
--- a/chromium/services/ui/public/cpp/OWNERS
+++ b/chromium/services/ui/public/cpp/OWNERS
@@ -1,3 +1,3 @@
per-file *_type_converter*.*=set noparent
per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
-per-file window_compositor_frame_sink*.*=fsamuel@chromium.org
+per-file *compositor_frame_sink*.*=fsamuel@chromium.org
diff --git a/chromium/services/ui/public/cpp/bitmap/BUILD.gn b/chromium/services/ui/public/cpp/bitmap/BUILD.gn
new file mode 100644
index 00000000000..2562f2079f6
--- /dev/null
+++ b/chromium/services/ui/public/cpp/bitmap/BUILD.gn
@@ -0,0 +1,20 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/ui.gni")
+
+source_set("bitmap") {
+ sources = [
+ "child_shared_bitmap_manager.cc",
+ "child_shared_bitmap_manager.h",
+ ]
+
+ deps = [
+ "//base",
+ "//cc",
+ "//cc/ipc:interfaces",
+ "//mojo/public/cpp/bindings",
+ "//ui/gfx",
+ ]
+}
diff --git a/chromium/services/ui/public/cpp/bitmap/child_shared_bitmap_manager.cc b/chromium/services/ui/public/cpp/bitmap/child_shared_bitmap_manager.cc
new file mode 100644
index 00000000000..92fc4300b18
--- /dev/null
+++ b/chromium/services/ui/public/cpp/bitmap/child_shared_bitmap_manager.cc
@@ -0,0 +1,165 @@
+// Copyright (c) 2013 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/public/cpp/bitmap/child_shared_bitmap_manager.h"
+
+#include <stddef.h>
+
+#include <utility>
+
+#include "base/debug/alias.h"
+#include "base/memory/ptr_util.h"
+#include "base/process/memory.h"
+#include "base/process/process_metrics.h"
+#include "base/trace_event/trace_event.h"
+#include "build/build_config.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace ui {
+
+namespace {
+
+class ChildSharedBitmap : public cc::SharedBitmap {
+ public:
+ ChildSharedBitmap(
+ const scoped_refptr<cc::mojom::ThreadSafeSharedBitmapManagerAssociatedPtr>
+ shared_bitmap_manager_ptr,
+ base::SharedMemory* shared_memory,
+ const cc::SharedBitmapId& id)
+ : cc::SharedBitmap(static_cast<uint8_t*>(shared_memory->memory()), id),
+ shared_bitmap_manager_ptr_(shared_bitmap_manager_ptr) {}
+
+ ChildSharedBitmap(
+ const scoped_refptr<cc::mojom::ThreadSafeSharedBitmapManagerAssociatedPtr>
+ shared_bitmap_manager_ptr,
+ std::unique_ptr<base::SharedMemory> shared_memory_holder,
+ const cc::SharedBitmapId& id)
+ : ChildSharedBitmap(shared_bitmap_manager_ptr,
+ shared_memory_holder.get(),
+ id) {
+ shared_memory_holder_ = std::move(shared_memory_holder);
+ }
+
+ ~ChildSharedBitmap() override {
+ (*shared_bitmap_manager_ptr_)->DidDeleteSharedBitmap(id());
+ }
+
+ private:
+ scoped_refptr<cc::mojom::ThreadSafeSharedBitmapManagerAssociatedPtr>
+ shared_bitmap_manager_ptr_;
+ std::unique_ptr<base::SharedMemory> shared_memory_holder_;
+};
+
+// Collect extra information for debugging bitmap creation failures.
+void CollectMemoryUsageAndDie(const gfx::Size& size, size_t alloc_size) {
+#if defined(OS_WIN)
+ int width = size.width();
+ int height = size.height();
+ DWORD last_error = GetLastError();
+
+ std::unique_ptr<base::ProcessMetrics> metrics(
+ base::ProcessMetrics::CreateProcessMetrics(
+ base::GetCurrentProcessHandle()));
+
+ size_t private_bytes = 0;
+ size_t shared_bytes = 0;
+ metrics->GetMemoryBytes(&private_bytes, &shared_bytes);
+
+ base::debug::Alias(&width);
+ base::debug::Alias(&height);
+ base::debug::Alias(&last_error);
+ base::debug::Alias(&private_bytes);
+ base::debug::Alias(&shared_bytes);
+#endif
+ base::TerminateBecauseOutOfMemory(alloc_size);
+}
+
+// Allocates a block of shared memory of the given size. Returns nullptr on
+// failure.
+std::unique_ptr<base::SharedMemory> AllocateSharedMemory(size_t buf_size) {
+ mojo::ScopedSharedBufferHandle mojo_buf =
+ mojo::SharedBufferHandle::Create(buf_size);
+ if (!mojo_buf->is_valid()) {
+ LOG(WARNING) << "Browser failed to allocate shared memory";
+ return nullptr;
+ }
+
+ base::SharedMemoryHandle shared_buf;
+ if (mojo::UnwrapSharedMemoryHandle(std::move(mojo_buf), &shared_buf, nullptr,
+ nullptr) != MOJO_RESULT_OK) {
+ LOG(WARNING) << "Browser failed to allocate shared memory";
+ return nullptr;
+ }
+
+ return base::MakeUnique<base::SharedMemory>(shared_buf, false);
+}
+
+} // namespace
+
+ChildSharedBitmapManager::ChildSharedBitmapManager(
+ const scoped_refptr<cc::mojom::ThreadSafeSharedBitmapManagerAssociatedPtr>&
+ shared_bitmap_manager_ptr)
+ : shared_bitmap_manager_ptr_(shared_bitmap_manager_ptr) {}
+
+ChildSharedBitmapManager::~ChildSharedBitmapManager() {}
+
+std::unique_ptr<cc::SharedBitmap>
+ChildSharedBitmapManager::AllocateSharedBitmap(const gfx::Size& size) {
+ TRACE_EVENT2("renderer", "ChildSharedBitmapManager::AllocateSharedBitmap",
+ "width", size.width(), "height", size.height());
+ size_t memory_size;
+ if (!cc::SharedBitmap::SizeInBytes(size, &memory_size))
+ return nullptr;
+ cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+ std::unique_ptr<base::SharedMemory> memory =
+ AllocateSharedMemory(memory_size);
+ if (!memory || !memory->Map(memory_size))
+ CollectMemoryUsageAndDie(size, memory_size);
+
+ NotifyAllocatedSharedBitmap(memory.get(), id);
+
+ // Close the associated FD to save resources, the previously mapped memory
+ // remains available.
+ memory->Close();
+
+ return base::MakeUnique<ChildSharedBitmap>(shared_bitmap_manager_ptr_,
+ std::move(memory), id);
+}
+
+std::unique_ptr<cc::SharedBitmap>
+ChildSharedBitmapManager::GetSharedBitmapFromId(const gfx::Size&,
+ const cc::SharedBitmapId&) {
+ NOTREACHED();
+ return nullptr;
+}
+
+std::unique_ptr<cc::SharedBitmap>
+ChildSharedBitmapManager::GetBitmapForSharedMemory(base::SharedMemory* mem) {
+ cc::SharedBitmapId id = cc::SharedBitmap::GenerateId();
+ NotifyAllocatedSharedBitmap(mem, cc::SharedBitmap::GenerateId());
+ return base::MakeUnique<ChildSharedBitmap>(shared_bitmap_manager_ptr_,
+ std::move(mem), id);
+}
+
+// Notifies the browser process that a shared bitmap with the given ID was
+// allocated. Caller keeps ownership of |memory|.
+void ChildSharedBitmapManager::NotifyAllocatedSharedBitmap(
+ base::SharedMemory* memory,
+ const cc::SharedBitmapId& id) {
+ base::SharedMemoryHandle handle_to_send =
+ base::SharedMemory::DuplicateHandle(memory->handle());
+ if (!base::SharedMemory::IsHandleValid(handle_to_send)) {
+ LOG(ERROR) << "Failed to duplicate shared memory handle for bitmap.";
+ return;
+ }
+
+ mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
+ handle_to_send, memory->mapped_size(), true /* read_only */);
+
+ (*shared_bitmap_manager_ptr_)
+ ->DidAllocateSharedBitmap(std::move(buffer_handle), id);
+}
+
+} // namespace ui
diff --git a/chromium/services/ui/public/cpp/bitmap/child_shared_bitmap_manager.h b/chromium/services/ui/public/cpp/bitmap/child_shared_bitmap_manager.h
new file mode 100644
index 00000000000..7e8eb3a9058
--- /dev/null
+++ b/chromium/services/ui/public/cpp/bitmap/child_shared_bitmap_manager.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2013 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_PUBLIC_CPP_BITMAP_CHILD_CHILD_SHARED_BITMAP_MANAGER_H_
+#define SERVICES_UI_PUBLIC_CPP_BITMAP_CHILD_CHILD_SHARED_BITMAP_MANAGER_H_
+
+#include <stdint.h>
+
+#include <memory>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "cc/ipc/shared_bitmap_manager.mojom.h"
+#include "cc/resources/shared_bitmap_manager.h"
+#include "mojo/public/cpp/bindings/thread_safe_interface_ptr.h"
+
+namespace ui {
+
+class ChildSharedBitmapManager : public cc::SharedBitmapManager {
+ public:
+ explicit ChildSharedBitmapManager(
+ const scoped_refptr<
+ cc::mojom::ThreadSafeSharedBitmapManagerAssociatedPtr>&
+ shared_bitmap_manager_ptr);
+ ~ChildSharedBitmapManager() override;
+
+ // cc::SharedBitmapManager implementation.
+ std::unique_ptr<cc::SharedBitmap> AllocateSharedBitmap(
+ const gfx::Size& size) override;
+ std::unique_ptr<cc::SharedBitmap> GetSharedBitmapFromId(
+ const gfx::Size&,
+ const cc::SharedBitmapId&) override;
+
+ std::unique_ptr<cc::SharedBitmap> GetBitmapForSharedMemory(
+ base::SharedMemory* mem);
+
+ private:
+ void NotifyAllocatedSharedBitmap(base::SharedMemory* memory,
+ const cc::SharedBitmapId& id);
+
+ scoped_refptr<cc::mojom::ThreadSafeSharedBitmapManagerAssociatedPtr>
+ shared_bitmap_manager_ptr_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildSharedBitmapManager);
+};
+
+} // namespace ui
+
+#endif // SERVICES_UI_PUBLIC_CPP_BITMAP_CHILD_CHILD_SHARED_BITMAP_MANAGER_H_
diff --git a/chromium/services/ui/public/cpp/window_compositor_frame_sink.cc b/chromium/services/ui/public/cpp/client_compositor_frame_sink.cc
index 01944e98ea2..8a132ae2dd8 100644
--- a/chromium/services/ui/public/cpp/window_compositor_frame_sink.cc
+++ b/chromium/services/ui/public/cpp/client_compositor_frame_sink.cc
@@ -2,21 +2,24 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "services/ui/public/cpp/window_compositor_frame_sink.h"
+#include "services/ui/public/cpp/client_compositor_frame_sink.h"
#include "base/bind.h"
+#include "base/command_line.h"
#include "base/memory/ptr_util.h"
+#include "cc/base/switches.h"
+#include "cc/output/begin_frame_args.h"
#include "cc/output/compositor_frame.h"
#include "cc/output/compositor_frame_sink_client.h"
namespace ui {
// static
-std::unique_ptr<WindowCompositorFrameSink> WindowCompositorFrameSink::Create(
+std::unique_ptr<ClientCompositorFrameSink> ClientCompositorFrameSink::Create(
const cc::FrameSinkId& frame_sink_id,
scoped_refptr<cc::ContextProvider> context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- std::unique_ptr<WindowCompositorFrameSinkBinding>*
+ std::unique_ptr<ClientCompositorFrameSinkBinding>*
compositor_frame_sink_binding) {
cc::mojom::MojoCompositorFrameSinkPtr compositor_frame_sink;
cc::mojom::MojoCompositorFrameSinkClientPtr compositor_frame_sink_client;
@@ -24,18 +27,18 @@ std::unique_ptr<WindowCompositorFrameSink> WindowCompositorFrameSink::Create(
compositor_frame_sink_client_request =
MakeRequest(&compositor_frame_sink_client);
- compositor_frame_sink_binding->reset(new WindowCompositorFrameSinkBinding(
+ compositor_frame_sink_binding->reset(new ClientCompositorFrameSinkBinding(
MakeRequest(&compositor_frame_sink),
compositor_frame_sink_client.PassInterface()));
- return base::WrapUnique(new WindowCompositorFrameSink(
+ return base::WrapUnique(new ClientCompositorFrameSink(
frame_sink_id, std::move(context_provider), gpu_memory_buffer_manager,
compositor_frame_sink.PassInterface(),
std::move(compositor_frame_sink_client_request)));
}
-WindowCompositorFrameSink::~WindowCompositorFrameSink() {}
+ClientCompositorFrameSink::~ClientCompositorFrameSink() {}
-bool WindowCompositorFrameSink::BindToClient(
+bool ClientCompositorFrameSink::BindToClient(
cc::CompositorFrameSinkClient* client) {
if (!cc::CompositorFrameSink::BindToClient(client))
return false;
@@ -53,7 +56,7 @@ bool WindowCompositorFrameSink::BindToClient(
return true;
}
-void WindowCompositorFrameSink::DetachFromClient() {
+void ClientCompositorFrameSink::DetachFromClient() {
client_->SetBeginFrameSource(nullptr);
begin_frame_source_.reset();
client_binding_.reset();
@@ -61,26 +64,37 @@ void WindowCompositorFrameSink::DetachFromClient() {
cc::CompositorFrameSink::DetachFromClient();
}
-void WindowCompositorFrameSink::SubmitCompositorFrame(
+void ClientCompositorFrameSink::SetLocalSurfaceId(
+ const cc::LocalSurfaceId& local_surface_id) {
+ DCHECK(local_surface_id.is_valid());
+ DCHECK(enable_surface_synchronization_);
+ local_surface_id_ = local_surface_id;
+}
+
+void ClientCompositorFrameSink::SubmitCompositorFrame(
cc::CompositorFrame frame) {
DCHECK(thread_checker_);
DCHECK(thread_checker_->CalledOnValidThread());
if (!compositor_frame_sink_)
return;
+ DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber,
+ frame.metadata.begin_frame_ack.sequence_number);
+
gfx::Size frame_size = last_submitted_frame_size_;
if (!frame.render_pass_list.empty())
frame_size = frame.render_pass_list.back()->output_rect.size();
- if (!local_surface_id_.is_valid() || frame_size != last_submitted_frame_size_)
+ if (!enable_surface_synchronization_ &&
+ (!local_surface_id_.is_valid() ||
+ frame_size != last_submitted_frame_size_)) {
local_surface_id_ = id_allocator_.GenerateId();
-
+ }
compositor_frame_sink_->SubmitCompositorFrame(local_surface_id_,
std::move(frame));
-
last_submitted_frame_size_ = frame_size;
}
-WindowCompositorFrameSink::WindowCompositorFrameSink(
+ClientCompositorFrameSink::ClientCompositorFrameSink(
const cc::FrameSinkId& frame_sink_id,
scoped_refptr<cc::ContextProvider> context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
@@ -92,22 +106,28 @@ WindowCompositorFrameSink::WindowCompositorFrameSink(
nullptr),
compositor_frame_sink_info_(std::move(compositor_frame_sink_info)),
client_request_(std::move(client_request)),
- frame_sink_id_(frame_sink_id) {}
+ frame_sink_id_(frame_sink_id) {
+ enable_surface_synchronization_ =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ cc::switches::kEnableSurfaceSynchronization);
+}
-void WindowCompositorFrameSink::DidReceiveCompositorFrameAck() {
+void ClientCompositorFrameSink::DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) {
DCHECK(thread_checker_);
DCHECK(thread_checker_->CalledOnValidThread());
if (!client_)
return;
+ client_->ReclaimResources(resources);
client_->DidReceiveCompositorFrameAck();
}
-void WindowCompositorFrameSink::OnBeginFrame(
+void ClientCompositorFrameSink::OnBeginFrame(
const cc::BeginFrameArgs& begin_frame_args) {
begin_frame_source_->OnBeginFrame(begin_frame_args);
}
-void WindowCompositorFrameSink::ReclaimResources(
+void ClientCompositorFrameSink::ReclaimResources(
const cc::ReturnedResourceArray& resources) {
DCHECK(thread_checker_);
DCHECK(thread_checker_->CalledOnValidThread());
@@ -116,23 +136,19 @@ void WindowCompositorFrameSink::ReclaimResources(
client_->ReclaimResources(resources);
}
-void WindowCompositorFrameSink::WillDrawSurface(
- const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {
- // TODO(fsamuel, staraz): Implement this.
-}
-
-void WindowCompositorFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
+void ClientCompositorFrameSink::OnNeedsBeginFrames(bool needs_begin_frames) {
compositor_frame_sink_->SetNeedsBeginFrame(needs_begin_frames);
}
-void WindowCompositorFrameSink::OnDidFinishFrame(const cc::BeginFrameAck& ack) {
- // TODO(eseckler): Pass on the ack to compositor_frame_sink_.
+void ClientCompositorFrameSink::OnDidFinishFrame(const cc::BeginFrameAck& ack) {
+ // If there was damage, the submitted CompositorFrame includes the ack.
+ if (!ack.has_damage)
+ compositor_frame_sink_->BeginFrameDidNotSwap(ack);
}
-WindowCompositorFrameSinkBinding::~WindowCompositorFrameSinkBinding() {}
+ClientCompositorFrameSinkBinding::~ClientCompositorFrameSinkBinding() {}
-WindowCompositorFrameSinkBinding::WindowCompositorFrameSinkBinding(
+ClientCompositorFrameSinkBinding::ClientCompositorFrameSinkBinding(
cc::mojom::MojoCompositorFrameSinkRequest compositor_frame_sink_request,
cc::mojom::MojoCompositorFrameSinkClientPtrInfo
compositor_frame_sink_client)
@@ -140,12 +156,12 @@ WindowCompositorFrameSinkBinding::WindowCompositorFrameSinkBinding(
compositor_frame_sink_client_(std::move(compositor_frame_sink_client)) {}
cc::mojom::MojoCompositorFrameSinkRequest
-WindowCompositorFrameSinkBinding::TakeFrameSinkRequest() {
+ClientCompositorFrameSinkBinding::TakeFrameSinkRequest() {
return std::move(compositor_frame_sink_request_);
}
cc::mojom::MojoCompositorFrameSinkClientPtrInfo
-WindowCompositorFrameSinkBinding::TakeFrameSinkClient() {
+ClientCompositorFrameSinkBinding::TakeFrameSinkClient() {
return std::move(compositor_frame_sink_client_);
}
diff --git a/chromium/services/ui/public/cpp/window_compositor_frame_sink.h b/chromium/services/ui/public/cpp/client_compositor_frame_sink.h
index ce1225714d1..af5f13a09c3 100644
--- a/chromium/services/ui/public/cpp/window_compositor_frame_sink.h
+++ b/chromium/services/ui/public/cpp/client_compositor_frame_sink.h
@@ -16,30 +16,31 @@
namespace ui {
-class WindowCompositorFrameSinkBinding;
+class ClientCompositorFrameSinkBinding;
-class WindowCompositorFrameSink
+class ClientCompositorFrameSink
: public cc::CompositorFrameSink,
public cc::mojom::MojoCompositorFrameSinkClient,
public cc::ExternalBeginFrameSourceClient {
public:
// static
- static std::unique_ptr<WindowCompositorFrameSink> Create(
+ static std::unique_ptr<ClientCompositorFrameSink> Create(
const cc::FrameSinkId& frame_sink_id,
scoped_refptr<cc::ContextProvider> context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
- std::unique_ptr<WindowCompositorFrameSinkBinding>*
+ std::unique_ptr<ClientCompositorFrameSinkBinding>*
compositor_frame_sink_binding);
- ~WindowCompositorFrameSink() override;
+ ~ClientCompositorFrameSink() override;
// cc::CompositorFrameSink implementation.
bool BindToClient(cc::CompositorFrameSinkClient* client) override;
void DetachFromClient() override;
+ void SetLocalSurfaceId(const cc::LocalSurfaceId& local_surface_id) override;
void SubmitCompositorFrame(cc::CompositorFrame frame) override;
private:
- WindowCompositorFrameSink(
+ ClientCompositorFrameSink(
const cc::FrameSinkId& frame_sink_id,
scoped_refptr<cc::ContextProvider> context_provider,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
@@ -47,11 +48,10 @@ class WindowCompositorFrameSink
cc::mojom::MojoCompositorFrameSinkClientRequest client_request);
// cc::mojom::MojoCompositorFrameSinkClient implementation:
- void DidReceiveCompositorFrameAck() override;
+ void DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) override;
void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override;
void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
- void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) override;
// cc::ExternalBeginFrameSourceClient implementation.
void OnNeedsBeginFrames(bool needs_begin_frames) override;
@@ -68,27 +68,28 @@ class WindowCompositorFrameSink
client_binding_;
std::unique_ptr<base::ThreadChecker> thread_checker_;
const cc::FrameSinkId frame_sink_id_;
+ bool enable_surface_synchronization_ = false;
- DISALLOW_COPY_AND_ASSIGN(WindowCompositorFrameSink);
+ DISALLOW_COPY_AND_ASSIGN(ClientCompositorFrameSink);
};
-// A WindowCompositorFrameSinkBinding is a bundle of mojo interfaces that is
-// created by WindowCompositorFrameSink::Create and is used by or implemented by
+// A ClientCompositorFrameSinkBinding is a bundle of mojo interfaces that is
+// created by ClientCompositorFrameSink::Create and is used by or implemented by
// Mus when a window is attached to a frame-sink..
-// WindowCompositorFrameSinkBinding has no standalone functionality. Its purpose
+// ClientCompositorFrameSinkBinding has no standalone functionality. Its purpose
// is to allow safely creating and attaching a CompositorFrameSink on one
// thread and using it on another.
-class WindowCompositorFrameSinkBinding {
+class ClientCompositorFrameSinkBinding {
public:
- ~WindowCompositorFrameSinkBinding();
+ ~ClientCompositorFrameSinkBinding();
cc::mojom::MojoCompositorFrameSinkRequest TakeFrameSinkRequest();
cc::mojom::MojoCompositorFrameSinkClientPtrInfo TakeFrameSinkClient();
private:
- friend class WindowCompositorFrameSink;
+ friend class ClientCompositorFrameSink;
- WindowCompositorFrameSinkBinding(
+ ClientCompositorFrameSinkBinding(
cc::mojom::MojoCompositorFrameSinkRequest compositor_frame_sink_request,
cc::mojom::MojoCompositorFrameSinkClientPtrInfo
compositor_frame_sink_client);
@@ -96,7 +97,7 @@ class WindowCompositorFrameSinkBinding {
cc::mojom::MojoCompositorFrameSinkRequest compositor_frame_sink_request_;
cc::mojom::MojoCompositorFrameSinkClientPtrInfo compositor_frame_sink_client_;
- DISALLOW_COPY_AND_ASSIGN(WindowCompositorFrameSinkBinding);
+ DISALLOW_COPY_AND_ASSIGN(ClientCompositorFrameSinkBinding);
};
} // namespace ui
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 12034d266b7..13238158de2 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
@@ -380,7 +380,8 @@ class GrContext* ContextProviderCommandBuffer::GrContext() {
if (gr_context_)
return gr_context_->get();
- gr_context_.reset(new skia_bindings::GrContextForGLES2Interface(ContextGL()));
+ gr_context_.reset(new skia_bindings::GrContextForGLES2Interface(
+ ContextGL(), ContextCapabilities()));
cache_controller_->SetGrContext(gr_context_->get());
// If GlContext is already lost, also abandon the new GrContext.
diff --git a/chromium/services/ui/public/cpp/gpu/gpu.cc b/chromium/services/ui/public/cpp/gpu/gpu.cc
index 45ba2595fcd..e0073d5d174 100644
--- a/chromium/services/ui/public/cpp/gpu/gpu.cc
+++ b/chromium/services/ui/public/cpp/gpu/gpu.cc
@@ -18,21 +18,18 @@
namespace ui {
Gpu::Gpu(service_manager::Connector* connector,
- service_manager::InterfaceProvider* provider,
+ const std::string& service_name,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: main_task_runner_(base::ThreadTaskRunnerHandle::Get()),
io_task_runner_(std::move(task_runner)),
connector_(connector),
- interface_provider_(provider),
+ service_name_(service_name),
shutdown_event_(base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {
DCHECK(main_task_runner_);
- DCHECK(connector_ || interface_provider_);
+ DCHECK(connector_);
mojom::GpuPtr gpu_ptr;
- if (connector_)
- connector_->BindInterface(ui::mojom::kServiceName, &gpu_ptr);
- else
- interface_provider_->GetInterface(&gpu_ptr);
+ connector_->BindInterface(service_name_, &gpu_ptr);
gpu_memory_buffer_manager_ =
base::MakeUnique<ClientGpuMemoryBufferManager>(std::move(gpu_ptr));
if (!io_task_runner_) {
@@ -54,14 +51,10 @@ Gpu::~Gpu() {
// static
std::unique_ptr<Gpu> Gpu::Create(
service_manager::Connector* connector,
+ const std::string& service_name,
scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- return base::WrapUnique(new Gpu(connector, nullptr, std::move(task_runner)));
-}
-
-std::unique_ptr<Gpu> Gpu::Create(
- service_manager::InterfaceProvider* provider,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
- return base::WrapUnique(new Gpu(nullptr, provider, std::move(task_runner)));
+ return base::WrapUnique(
+ new Gpu(connector, service_name, std::move(task_runner)));
}
scoped_refptr<cc::ContextProvider> Gpu::CreateContextProvider(
@@ -98,10 +91,7 @@ void Gpu::EstablishGpuChannel(
if (gpu_)
return;
- if (connector_)
- connector_->BindInterface(ui::mojom::kServiceName, &gpu_);
- else
- interface_provider_->GetInterface(&gpu_);
+ connector_->BindInterface(service_name_, &gpu_);
gpu_->EstablishGpuChannel(
base::Bind(&Gpu::OnEstablishedGpuChannel, base::Unretained(this)));
}
@@ -114,10 +104,7 @@ scoped_refptr<gpu::GpuChannelHost> Gpu::EstablishGpuChannelSync() {
int client_id = 0;
mojo::ScopedMessagePipeHandle channel_handle;
gpu::GPUInfo gpu_info;
- if (connector_)
- connector_->BindInterface(ui::mojom::kServiceName, &gpu_);
- else
- interface_provider_->GetInterface(&gpu_);
+ connector_->BindInterface(service_name_, &gpu_);
mojo::SyncCallRestrictions::ScopedAllowSyncCall allow_sync_call;
if (!gpu_->EstablishGpuChannel(&client_id, &channel_handle, &gpu_info)) {
diff --git a/chromium/services/ui/public/cpp/gpu/gpu.h b/chromium/services/ui/public/cpp/gpu/gpu.h
index f99250a65d4..2ca485288ed 100644
--- a/chromium/services/ui/public/cpp/gpu/gpu.h
+++ b/chromium/services/ui/public/cpp/gpu/gpu.h
@@ -20,7 +20,6 @@
namespace service_manager {
class Connector;
-class InterfaceProvider;
}
namespace ui {
@@ -39,9 +38,7 @@ class Gpu : public gpu::GpuChannelHostFactory,
// created and used.
static std::unique_ptr<Gpu> Create(
service_manager::Connector* connector,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner = nullptr);
- static std::unique_ptr<Gpu> Create(
- service_manager::InterfaceProvider*,
+ const std::string& service_name,
scoped_refptr<base::SingleThreadTaskRunner> task_runner = nullptr);
scoped_refptr<cc::ContextProvider> CreateContextProvider(
@@ -57,7 +54,7 @@ class Gpu : public gpu::GpuChannelHostFactory,
friend struct base::DefaultSingletonTraits<Gpu>;
Gpu(service_manager::Connector* connector,
- service_manager::InterfaceProvider* provider,
+ const std::string& service_name,
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
scoped_refptr<gpu::GpuChannelHost> GetGpuChannel();
@@ -74,7 +71,7 @@ class Gpu : public gpu::GpuChannelHostFactory,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
service_manager::Connector* connector_;
- service_manager::InterfaceProvider* interface_provider_;
+ const std::string service_name_;
base::WaitableEvent shutdown_event_;
std::unique_ptr<base::Thread> io_thread_;
std::unique_ptr<ClientGpuMemoryBufferManager> gpu_memory_buffer_manager_;
diff --git a/chromium/services/ui/public/interfaces/BUILD.gn b/chromium/services/ui/public/interfaces/BUILD.gn
index 6a3756828b8..3d9403ed396 100644
--- a/chromium/services/ui/public/interfaces/BUILD.gn
+++ b/chromium/services/ui/public/interfaces/BUILD.gn
@@ -9,7 +9,6 @@ mojom("interfaces") {
sources = [
"accessibility_manager.mojom",
"clipboard.mojom",
- "cursor.mojom",
"display_manager.mojom",
"event_matcher.mojom",
"gpu.mojom",
@@ -34,8 +33,11 @@ mojom("interfaces") {
":constants",
"//cc/ipc:interfaces",
"//gpu/ipc/common:interfaces",
+ "//services/ui/public/interfaces/cursor",
"//services/ui/public/interfaces/display",
"//services/ui/public/interfaces/ime",
+ "//skia/public/interfaces",
+ "//ui/base/mojo:mojo_bindings",
"//ui/display/mojo:interfaces",
"//ui/events/mojo:interfaces",
"//ui/gfx/geometry/mojo",
@@ -54,6 +56,7 @@ test("ui_struct_traits_unittests") {
testonly = true
sources = [
+ "cursor/cursor_struct_traits_unittest.cc",
"ime/ime_struct_traits_unittest.cc",
]
@@ -61,7 +64,9 @@ test("ui_struct_traits_unittests") {
"//base",
"//base/test:test_support",
"//mojo/edk/test:run_all_unittests",
+ "//services/ui/public/interfaces/cursor",
"//services/ui/public/interfaces/ime:test_interfaces",
+ "//skia/public/interfaces",
"//testing/gtest",
"//ui/display/types",
"//ui/gfx:test_support",
diff --git a/chromium/services/ui/public/interfaces/cursor/BUILD.gn b/chromium/services/ui/public/interfaces/cursor/BUILD.gn
new file mode 100644
index 00000000000..962f1f67b3d
--- /dev/null
+++ b/chromium/services/ui/public/interfaces/cursor/BUILD.gn
@@ -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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("cursor") {
+ sources = [
+ "cursor.mojom",
+ ]
+
+ public_deps = [
+ "//mojo/common:common_custom_types",
+ "//skia/public/interfaces",
+ "//skia/public/interfaces:mojo",
+ "//ui/gfx/geometry/mojo",
+ ]
+}
diff --git a/chromium/services/ui/public/interfaces/cursor/DEPS b/chromium/services/ui/public/interfaces/cursor/DEPS
new file mode 100644
index 00000000000..605004893e4
--- /dev/null
+++ b/chromium/services/ui/public/interfaces/cursor/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+skia/public/interfaces"
+]
diff --git a/chromium/services/ui/public/interfaces/cursor/OWNERS b/chromium/services/ui/public/interfaces/cursor/OWNERS
new file mode 100644
index 00000000000..e75daf744a0
--- /dev/null
+++ b/chromium/services/ui/public/interfaces/cursor/OWNERS
@@ -0,0 +1,8 @@
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+per-file *.typemap=set noparent
+per-file *.typemap=file://ipc/SECURITY_OWNERS
diff --git a/chromium/services/ui/public/interfaces/cursor.mojom b/chromium/services/ui/public/interfaces/cursor/cursor.mojom
index 863c96cde5f..08a88021df7 100644
--- a/chromium/services/ui/public/interfaces/cursor.mojom
+++ b/chromium/services/ui/public/interfaces/cursor/cursor.mojom
@@ -4,9 +4,13 @@
module ui.mojom;
+import "mojo/common/time.mojom";
+import "skia/public/interfaces/bitmap_array.mojom";
+import "ui/gfx/geometry/mojo/geometry.mojom";
+
// Standard Cursor numbers. These are the same as Chrome's ui::Cursor and
// blink's WebCursorInfo.
-enum Cursor {
+enum CursorType {
// NULL is kept for compatibility with chrome declarations. In chrome code, it
// is treated exactly like POINTER, the default pointer.
CURSOR_NULL = 0,
@@ -55,3 +59,21 @@ enum Cursor {
GRABBING,
CUSTOM
};
+
+// A description of a cursor.
+struct CursorData {
+ // The type of cursor. If CUSTOM, the rest of the fields are relevant.
+ CursorType cursor_type;
+
+ // The delay between cursor frames.
+ mojo.common.mojom.TimeDelta frame_delay;
+
+ // The hotspot in pixels in the source cursor frames.
+ gfx.mojom.Point hotspot_in_pixels;
+
+ // The frames of the cursor.
+ skia.mojom.BitmapArray cursor_frames;
+
+ // This is the image scale of this cursor.
+ float scale_factor;
+};
diff --git a/chromium/services/ui/public/interfaces/cursor/cursor.typemap b/chromium/services/ui/public/interfaces/cursor/cursor.typemap
new file mode 100644
index 00000000000..e82b51d3a60
--- /dev/null
+++ b/chromium/services/ui/public/interfaces/cursor/cursor.typemap
@@ -0,0 +1,19 @@
+# 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.
+
+mojom = "//services/ui/public/interfaces/cursor/cursor.mojom"
+public_headers = [ "//ui/base/cursor/cursor_data.h" ]
+traits_headers =
+ [ "//services/ui/public/interfaces/cursor/cursor_struct_traits.h" ]
+sources = [
+ "//services/ui/public/interfaces/cursor/cursor_struct_traits.cc",
+]
+public_deps = [
+ "//ui/base",
+]
+deps = [
+ "//ui/gfx/geometry",
+]
+
+type_mappings = [ "ui.mojom.CursorData=ui::CursorData[copyable_pass_by_value]" ]
diff --git a/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits.cc b/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits.cc
new file mode 100644
index 00000000000..609ab837dec
--- /dev/null
+++ b/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits.cc
@@ -0,0 +1,64 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "services/ui/public/interfaces/cursor/cursor_struct_traits.h"
+
+#include "base/time/time.h"
+#include "mojo/common/common_custom_types_struct_traits.h"
+#include "skia/public/interfaces/bitmap_array_struct_traits.h"
+#include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+
+namespace mojo {
+
+// static
+const base::TimeDelta&
+StructTraits<ui::mojom::CursorDataDataView, ui::CursorData>::frame_delay(
+ const ui::CursorData& c) {
+ return c.frame_delay();
+}
+
+// static
+const gfx::Point&
+StructTraits<ui::mojom::CursorDataDataView, ui::CursorData>::hotspot_in_pixels(
+ const ui::CursorData& c) {
+ return c.hotspot_in_pixels();
+}
+
+// static
+const std::vector<SkBitmap>&
+StructTraits<ui::mojom::CursorDataDataView, ui::CursorData>::cursor_frames(
+ const ui::CursorData& c) {
+ return c.cursor_frames();
+}
+
+// static
+bool StructTraits<ui::mojom::CursorDataDataView, ui::CursorData>::Read(
+ ui::mojom::CursorDataDataView data,
+ ui::CursorData* out) {
+ ui::mojom::CursorType type = data.cursor_type();
+ if (type != ui::mojom::CursorType::CUSTOM) {
+ *out = ui::CursorData(static_cast<int>(type));
+ return true;
+ }
+
+ gfx::Point hotspot_in_pixels;
+ std::vector<SkBitmap> cursor_frames;
+ float scale_factor = data.scale_factor();
+ base::TimeDelta frame_delay;
+
+ if (!data.ReadHotspotInPixels(&hotspot_in_pixels) ||
+ !data.ReadCursorFrames(&cursor_frames) ||
+ !data.ReadFrameDelay(&frame_delay)) {
+ return false;
+ }
+
+ *out = ui::CursorData(hotspot_in_pixels, cursor_frames, scale_factor,
+ frame_delay);
+ return true;
+}
+
+} // namespace mojo
diff --git a/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits.h b/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits.h
new file mode 100644
index 00000000000..a626051553b
--- /dev/null
+++ b/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits.h
@@ -0,0 +1,29 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_UI_PUBLIC_INTERFACES_CURSOR_CURSOR_STRUCT_TRAITS_H_
+#define SERVICES_UI_PUBLIC_INTERFACES_CURSOR_CURSOR_STRUCT_TRAITS_H_
+
+#include "services/ui/public/interfaces/cursor/cursor.mojom-shared.h"
+#include "ui/base/cursor/cursor_data.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<ui::mojom::CursorDataDataView, ui::CursorData> {
+ static ui::mojom::CursorType cursor_type(const ui::CursorData& c) {
+ return ui::mojom::CursorType(c.cursor_type());
+ }
+ static const base::TimeDelta& frame_delay(const ui::CursorData& c);
+ static const gfx::Point& hotspot_in_pixels(const ui::CursorData& c);
+ static const std::vector<SkBitmap>& cursor_frames(const ui::CursorData& c);
+ static float scale_factor(const ui::CursorData& c) {
+ return c.scale_factor();
+ }
+ static bool Read(ui::mojom::CursorDataDataView data, ui::CursorData* out);
+};
+
+} // namespace mojo
+
+#endif // SERVICES_UI_PUBLIC_INTERFACES_CURSOR_CURSOR_STRUCT_TRAITS_H_
diff --git a/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits_unittest.cc b/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits_unittest.cc
new file mode 100644
index 00000000000..179c6ca5d81
--- /dev/null
+++ b/chromium/services/ui/public/interfaces/cursor/cursor_struct_traits_unittest.cc
@@ -0,0 +1,106 @@
+// 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/ui/public/interfaces/cursor/cursor_struct_traits.h"
+
+#include "base/message_loop/message_loop.h"
+#include "mojo/common/common_custom_types_struct_traits.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
+#include "skia/public/interfaces/bitmap_array_struct_traits.h"
+#include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/cursor/cursor_data.h"
+#include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
+
+namespace ui {
+
+namespace {
+
+class CursorStructTraitsTest : public testing::Test {
+ public:
+ CursorStructTraitsTest() {}
+
+ protected:
+ bool EchoCursorData(const ui::CursorData& in, ui::CursorData* out) {
+ return mojom::CursorData::Deserialize(mojom::CursorData::Serialize(&in),
+ out);
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(CursorStructTraitsTest);
+};
+
+std::vector<SkBitmap> CreateTestCursorFrames(const gfx::Size& size,
+ unsigned int count) {
+ std::vector<SkBitmap> frames(count);
+ for (size_t i = 0; i < count; ++i) {
+ SkBitmap& bitmap = frames[i];
+ bitmap.allocN32Pixels(size.width(), size.height());
+ bitmap.eraseColor(SK_ColorRED);
+ }
+ return frames;
+}
+
+} // namespace
+
+// Tests numeric cursor ids.
+TEST_F(CursorStructTraitsTest, TestBuiltIn) {
+ for (int i = 0; i < 43; ++i) {
+ ui::CursorData input(i);
+
+ ui::CursorData output;
+ ASSERT_TRUE(EchoCursorData(input, &output));
+ EXPECT_TRUE(output.IsType(i));
+ }
+}
+
+// Test that we copy cursor bitmaps and metadata across the wire.
+TEST_F(CursorStructTraitsTest, TestBitmapCursor) {
+ const base::TimeDelta kFrameDelay = base::TimeDelta::FromMilliseconds(15);
+ const gfx::Point kHotspot = gfx::Point(5, 2);
+ const float kScale = 2.0f;
+
+ ui::CursorData input(kHotspot, CreateTestCursorFrames(gfx::Size(10, 10), 3),
+ kScale, kFrameDelay);
+
+ ui::CursorData output;
+ ASSERT_TRUE(EchoCursorData(input, &output));
+
+ EXPECT_EQ(kCursorCustom, output.cursor_type());
+ EXPECT_EQ(kScale, output.scale_factor());
+ EXPECT_EQ(kFrameDelay, output.frame_delay());
+ EXPECT_EQ(kHotspot, output.hotspot_in_pixels());
+
+ // Even if the pixel data is logically the same, expect that it has different
+ // generation ids.
+ EXPECT_FALSE(output.IsSameAs(input));
+
+ // Make a copy of output. It should be the same as output.
+ ui::CursorData copy = output;
+ EXPECT_TRUE(copy.IsSameAs(output));
+
+ // But make sure that the pixel data actually is equivalent.
+ ASSERT_EQ(input.cursor_frames().size(), output.cursor_frames().size());
+ for (size_t f = 0; f < input.cursor_frames().size(); ++f) {
+ ASSERT_EQ(input.cursor_frames()[f].width(),
+ output.cursor_frames()[f].width());
+ ASSERT_EQ(input.cursor_frames()[f].height(),
+ output.cursor_frames()[f].height());
+
+ input.cursor_frames()[f].lockPixels();
+ output.cursor_frames()[f].lockPixels();
+ for (int x = 0; x < input.cursor_frames()[f].width(); ++x) {
+ for (int y = 0; y < input.cursor_frames()[f].height(); ++y) {
+ EXPECT_EQ(input.cursor_frames()[f].getColor(x, y),
+ output.cursor_frames()[f].getColor(x, y));
+ }
+ }
+
+ output.cursor_frames()[f].unlockPixels();
+ input.cursor_frames()[f].unlockPixels();
+ }
+}
+
+} // namespace ui
diff --git a/chromium/services/ui/public/interfaces/cursor/typemaps.gni b/chromium/services/ui/public/interfaces/cursor/typemaps.gni
new file mode 100644
index 00000000000..c2ecaca6885
--- /dev/null
+++ b/chromium/services/ui/public/interfaces/cursor/typemaps.gni
@@ -0,0 +1,5 @@
+# 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.
+
+typemaps = [ "//services/ui/public/interfaces/cursor/cursor.typemap" ]
diff --git a/chromium/services/ui/public/interfaces/window_manager.mojom b/chromium/services/ui/public/interfaces/window_manager.mojom
index 1215261eeb3..aa340ba650b 100644
--- a/chromium/services/ui/public/interfaces/window_manager.mojom
+++ b/chromium/services/ui/public/interfaces/window_manager.mojom
@@ -4,12 +4,17 @@
module ui.mojom;
-import "services/ui/public/interfaces/cursor.mojom";
+import "cc/ipc/frame_sink_id.mojom";
+import "cc/ipc/local_surface_id.mojom";
+import "services/ui/public/interfaces/cursor/cursor.mojom";
import "services/ui/public/interfaces/event_matcher.mojom";
import "services/ui/public/interfaces/window_manager_constants.mojom";
import "services/ui/public/interfaces/window_tree_constants.mojom";
+import "skia/public/interfaces/bitmap.mojom";
+import "ui/base/mojo/ui_base_types.mojom";
import "ui/display/mojo/display.mojom";
import "ui/events/mojo/event.mojom";
+import "ui/events/mojo/event_constants.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
// WindowManager is used when a WindowTreeClient attempts to modify
@@ -144,19 +149,18 @@ interface WindowManager {
// End long lived properties. ------------------------------------------------
- // Shadow style for the window. Type: mojom::ShadowStyle.
- // TODO(sky): this is currently unused, either wire up or nuke:
- // http://crbug.com/671714.
- const string kShadowStyle_Property = "prop:shadow-style";
-
// Called immediately when the WindowManager is obtained.
OnConnect(uint16 client_id);
// Called when a new display is added. |root| gives the root window specific
- // to this WindowManager for |display|.
+ // to this WindowManager for |display|. |frame_sink_id| uniquely identifies
+ // the window manager in the frame sink manager. |local_surface_id| identifies
+ // the ID to use to submit CompositorFrames.
WmNewDisplayAdded(display.mojom.Display display,
WindowData root,
- bool parent_drawn);
+ bool parent_drawn,
+ cc.mojom.FrameSinkId frame_sink_id,
+ cc.mojom.LocalSurfaceId? local_surface_id);
// Called when a display is removed. The root of the specified display is
// still valid. It is expected the client calls DeleteWindow() shortly after
@@ -175,6 +179,7 @@ interface WindowManager {
string name,
array<uint8>? value);
+ WmSetModalType(uint32 window_id, ModalType type);
WmSetCanFocus(uint32 window_id, bool can_focus);
// Asks the WindowManager to create a new window.
@@ -190,6 +195,23 @@ interface WindowManager {
// can update the UI for the janky windows.
WmClientJankinessChanged(uint16 client_id, bool janky);
+ // Asks the WindowManager to create a drag representation window: a window
+ // which contains a single image representation.
+ //
+ // TODO(erg): SkBitmap is the wrong data type for the drag image; we should
+ // be passing ImageSkias once http://crbug.com/655874 is implemented.
+ WmBuildDragImage(gfx.mojom.Point screen_location,
+ skia.mojom.Bitmap? drag_image,
+ gfx.mojom.Vector2d drag_image_offset,
+ PointerKind source);
+
+ // Moves the drag representation image to |screen_location|. The window server
+ // queues further drags locally until they receive the callback.
+ WmMoveDragImage(gfx.mojom.Point screen_location) => ();
+
+ // Called when the drag image is no longer needed.
+ WmDestroyDragImage();
+
// Asks the WindowManager to interactively move the window. This will return
// whether this completed successfully or not through the client's
// OnWmMoveLoopCompleted().
@@ -217,7 +239,7 @@ interface WindowManager {
OnAccelerator(uint32 ack_id, uint32 accelerator_id, ui.mojom.Event event);
};
-struct Accelerator {
+struct WmAccelerator {
uint32 id;
EventMatcher event_matcher;
};
@@ -245,12 +267,22 @@ interface WindowManagerClient {
// See WindowTree for details on event dispatch.
// This ignores any accelerators already defined with the same id or matcher.
// Returns true if all accelerators were added successfully.
- AddAccelerators(array<Accelerator> accelerators) => (bool success);
+ AddAccelerators(array<WmAccelerator> accelerators) => (bool success);
RemoveAccelerator(uint32 id);
+ // Sets the root of a particular display. This is only applicable when the
+ // WindowTree was created with a value of false for
+ // |automatically_create_display_roots| (see
+ // WindowManagerWindowTreeFactory::CreateWindowTree() for details).
+ SetDisplayRoot(int64 display_id, uint32 window_id) => (bool success);
+
// The window manager has completed a request with the specific change id.
WmResponse(uint32 change_id, bool response);
+ // The window manager has completed a SetBounds request with the specified
+ // change id
+ WmSetBoundsResponse(uint32 change_id);
+
// Calls WindowTreeClient::RequestClose() on the embedded app at the
// specified window.
WmRequestClose(uint32 window_id);
@@ -260,13 +292,17 @@ interface WindowManagerClient {
WmSetFrameDecorationValues(FrameDecorationValues values);
// Sets the cursor that the non-client areas of the window should use.
- WmSetNonClientCursor(uint32 window_id, Cursor cursor_id);
+ WmSetNonClientCursor(uint32 window_id, CursorType cursor_id);
// Response from WmCreateTopLevelWindow() informing the client of the id for
// the new window.
OnWmCreatedTopLevelWindow(uint32 change_id, uint32 window_id);
// See description in WindowManager::OnAccelerator(). |ack_id| is the value
- // that was passed to OnAccelerator().
- OnAcceleratorAck(uint32 ack_id, EventResult event_result);
+ // that was passed to OnAccelerator(). If the accelerator is a pre-target
+ // handler and |event_result| is UNHANDLED, then |properties| is added to
+ // the KeyEvent that is dispatched to the client with the focused window.
+ OnAcceleratorAck(uint32 ack_id,
+ EventResult event_result,
+ map<string, array<uint8>> properties);
};
diff --git a/chromium/services/ui/public/interfaces/window_manager_constants.mojom b/chromium/services/ui/public/interfaces/window_manager_constants.mojom
index f2a2b12c853..7863f767227 100644
--- a/chromium/services/ui/public/interfaces/window_manager_constants.mojom
+++ b/chromium/services/ui/public/interfaces/window_manager_constants.mojom
@@ -22,7 +22,6 @@ enum ShowState {
MAXIMIZED,
INACTIVE,
FULLSCREEN,
- DOCKED,
};
const int32 kResizeBehaviorNone = 0;
diff --git a/chromium/services/ui/public/interfaces/window_manager_window_tree_factory.mojom b/chromium/services/ui/public/interfaces/window_manager_window_tree_factory.mojom
index 152b3263a78..04ad1f3c4f9 100644
--- a/chromium/services/ui/public/interfaces/window_manager_window_tree_factory.mojom
+++ b/chromium/services/ui/public/interfaces/window_manager_window_tree_factory.mojom
@@ -7,10 +7,17 @@ module ui.mojom;
import "services/ui/public/interfaces/window_manager_constants.mojom";
import "services/ui/public/interfaces/window_tree.mojom";
-// Interface used by the WindowManager to obtain a WindowTree. The
-// WindowManager is informed of the roots (one per display) by way of
-// WmNewDisplayAdded(). See it for details.
+// Interface used by the WindowManager to obtain a WindowTree. Server may be
+// configured in two distinct modes by way of the
+// |automatically_create_display_roots| parameter:
+// . If true, then mus creates windows for displays as displays are added and
+// calls WmNewDisplayAdded() (see it for more details).
+// . If false, the client is responsible for creating and setting windows for
+// displays (via SetDisplayRoot()). In this mode it is assumed the client is
+// detecting displays via another mechanism.
interface WindowManagerWindowTreeFactory {
// NOTE: it is expected this is called only once.
- CreateWindowTree(WindowTree& tree_request, WindowTreeClient client);
+ CreateWindowTree(WindowTree& tree_request,
+ WindowTreeClient client,
+ bool automatically_create_display_roots);
};
diff --git a/chromium/services/ui/public/interfaces/window_server_test.mojom b/chromium/services/ui/public/interfaces/window_server_test.mojom
index 2a8028f055e..899faf23086 100644
--- a/chromium/services/ui/public/interfaces/window_server_test.mojom
+++ b/chromium/services/ui/public/interfaces/window_server_test.mojom
@@ -4,6 +4,14 @@
module ui.mojom;
+import "ui/events/mojo/event.mojom";
+
interface WindowServerTest {
EnsureClientHasDrawnWindow(string client_name) => (bool success);
+
+ // Takes an event and dispatches it as if it came from the native platform.
+ // Returns false on bad |display_id| or |event|; returns true if it reaches
+ // the event dispatch phase.
+ DispatchEvent(int64 display_id, ui.mojom.Event event)
+ => (bool result);
};
diff --git a/chromium/services/ui/public/interfaces/window_tree.mojom b/chromium/services/ui/public/interfaces/window_tree.mojom
index ab53d13c0f7..b8c4fabc041 100644
--- a/chromium/services/ui/public/interfaces/window_tree.mojom
+++ b/chromium/services/ui/public/interfaces/window_tree.mojom
@@ -4,15 +4,21 @@
module ui.mojom;
+import "cc/ipc/frame_sink_id.mojom";
+import "cc/ipc/local_surface_id.mojom";
+import "cc/ipc/surface_id.mojom";
import "cc/ipc/surface_info.mojom";
import "cc/ipc/mojo_compositor_frame_sink.mojom";
-import "services/ui/public/interfaces/cursor.mojom";
+import "services/ui/public/interfaces/cursor/cursor.mojom";
import "services/ui/public/interfaces/event_matcher.mojom";
import "services/ui/public/interfaces/mus_constants.mojom";
import "services/ui/public/interfaces/window_manager.mojom";
import "services/ui/public/interfaces/window_manager_constants.mojom";
import "services/ui/public/interfaces/window_tree_constants.mojom";
+import "skia/public/interfaces/bitmap.mojom";
+import "ui/base/mojo/ui_base_types.mojom";
import "ui/events/mojo/event.mojom";
+import "ui/events/mojo/event_constants.mojom";
import "ui/gfx/geometry/mojo/geometry.mojom";
import "ui/platform_window/mojo/text_input_state.mojom";
@@ -100,8 +106,10 @@ interface WindowTree {
// Stops the pointer watcher for all events.
StopPointerWatcher();
- // Sets the specified bounds of the specified window.
- SetWindowBounds(uint32 change_id, uint32 window_id, gfx.mojom.Rect bounds);
+ // 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,
+ cc.mojom.LocalSurfaceId? local_surface_id);
// 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
@@ -176,13 +184,11 @@ interface WindowTree {
// This does not change transient window's position in the window hierarchy.
RemoveTransientWindowFromParent(uint32 change_id, uint32 transient_window_id);
- // Sets |window_id| to be modal. If the window has a transient parent, then
- // the window is modal to the transient parent. Otherwise, the window is modal
- // to the system. This releases capture if necessary.
+ // 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).
- SetModal(uint32 change_id, uint32 window_id);
+ SetModalType(uint32 change_id, uint32 window_id, ModalType type);
// Reorders a window in its parent, relative to |relative_window_id| according
// to |direction|. Only the connection that created the window's parent can
@@ -240,7 +246,7 @@ interface WindowTree {
// Sets the cursor when the pointer is inside |window_id| to a system standard
// cursor provided by the window manager.
- SetPredefinedCursor(uint32 change_id, uint32 window_id, Cursor cursor_id);
+ SetPredefinedCursor(uint32 change_id, uint32 window_id, CursorType cursor_id);
// TODO(erg): Additional cursor methods. Image based cursors, visibility,
// and cursor locking.
@@ -290,13 +296,23 @@ interface WindowTree {
CancelWindowMove(uint32 window_id);
// Called by the client to start a drag operation. |source_window_id| is the
- // source window, |drag_data| is the entire set of mime to raw data
- // mapping. We send this during the start of the drag because most views
+ // source window, |screen_location| is what the source thinks their location
+ // of the pointer which started the drag is, |drag_data| is the entire set of
+ // mime to raw data mapping. |drag_image| and |drag_image_offset| describe
+ // an image to hold behind the cursor which represents the data on the
+ // clipboard. We send this during the start of the drag because most views
// clients will try to read all this data on first entry.
+ //
+ // 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,
+ gfx.mojom.Point screen_location,
map<string, array<uint8>> drag_data,
- uint32 drag_operation);
+ skia.mojom.Bitmap? drag_image,
+ gfx.mojom.Vector2d drag_image_offset,
+ uint32 drag_operation,
+ PointerKind source);
// Called by the client to cancel any in progress drag drop operation. This
// will result in a change completed for the underlying change.
@@ -313,13 +329,17 @@ interface WindowTreeClient {
// the window manager service, unless the connection is to the root connection
// in which case it will be null. |parent_drawn| is true if roots parent is
// drawn, see OnParentDrawnStateChanged() for details. |display_id| identifies
- // the display this root window is on.
+ // the display this root window is on. |frame_sink_id| uniquely identifies the
+ // client in the frame sink manager. If the embedded window has a size,
+ // |local_surface_id| identifies the ID to use to submit CompositorFrames.
OnEmbed(uint16 connection_id,
WindowData root,
WindowTree? tree,
int64 display_id,
uint32 focused_window,
- bool parent_drawn);
+ bool parent_drawn,
+ cc.mojom.FrameSinkId frame_sink_id,
+ cc.mojom.LocalSurfaceId? local_surface_id);
// Invoked when the application embedded at |window| is disconnected. In other
// words the embedded app closes the connection to the server. This is called
@@ -335,19 +355,30 @@ interface WindowTreeClient {
// change.
OnCaptureChanged(uint32 new_capture, uint32 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, cc.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
// OnDrawnStateChanged() for details. |display_id| identifies the display this
- // window is on.
+ // window is on. |frame_sink_id| uniquely identifies the client in the display
+ // compositor. If the top level window has a size, |local_surface_id|
+ // identifies the ID to use to submit CompositorFrames.
OnTopLevelCreated(uint32 change_id,
WindowData data,
int64 display_id,
- bool parent_drawn);
+ bool parent_drawn,
+ cc.mojom.FrameSinkId frame_sink_id,
+ cc.mojom.LocalSurfaceId? local_surface_id);
- // Invoked when a window's bounds have changed.
+ // Invoked when a window's bounds have changed. Only the client embedded in
+ // |window| gets a non_empty |local_surface_id|.
OnWindowBoundsChanged(uint32 window,
gfx.mojom.Rect old_bounds,
- gfx.mojom.Rect new_bounds);
+ gfx.mojom.Rect new_bounds,
+ cc.mojom.LocalSurfaceId? local_surface_id);
OnClientAreaChanged(uint32 window_id,
gfx.mojom.Insets new_client_area,
@@ -436,7 +467,7 @@ interface WindowTreeClient {
// initiate the change.
OnWindowFocused(uint32 focused_window_id);
- OnWindowPredefinedCursorChanged(uint32 window_id, Cursor cursor_id);
+ OnWindowPredefinedCursorChanged(uint32 window_id, CursorType cursor_id);
// Invoked when a client window submits a new surface ID. The surface ID and
// associated information is propagated to the parent connection. The parent
diff --git a/chromium/services/ui/service.cc b/chromium/services/ui/service.cc
index 34f4803d498..b7ff96918dc 100644
--- a/chromium/services/ui/service.cc
+++ b/chromium/services/ui/service.cc
@@ -18,7 +18,6 @@
#include "services/catalog/public/cpp/resource_loader.h"
#include "services/catalog/public/interfaces/constants.mojom.h"
#include "services/service_manager/public/c/main.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/interface_registry.h"
#include "services/service_manager/public/cpp/service_context.h"
@@ -58,7 +57,6 @@
#include "ui/ozone/public/ozone_platform.h"
#endif
-using service_manager::Connection;
using mojo::InterfaceRequest;
using ui::mojom::WindowServerTest;
using ui::mojom::WindowTreeHostFactory;
@@ -96,6 +94,10 @@ Service::~Service() {
// WindowServer (or more correctly its Displays) may have state that needs to
// be destroyed before GpuState as well.
window_server_.reset();
+
+#if defined(USE_OZONE)
+ OzonePlatform::Shutdown();
+#endif
}
void Service::InitializeResources(service_manager::Connector* connector) {
@@ -170,11 +172,11 @@ void Service::OnStart() {
// TODO(kylechar): We might not always want a US keyboard layout.
ui::KeyboardLayoutEngineManager::GetKeyboardLayoutEngine()
->SetCurrentLayoutByName("us");
- client_native_pixmap_factory_ = ui::ClientNativePixmapFactory::Create();
- ui::ClientNativePixmapFactory::SetInstance(
+ client_native_pixmap_factory_ = ui::CreateClientNativePixmapFactoryOzone();
+ gfx::ClientNativePixmapFactory::SetInstance(
client_native_pixmap_factory_.get());
- DCHECK(ui::ClientNativePixmapFactory::GetInstance());
+ DCHECK(gfx::ClientNativePixmapFactory::GetInstance());
#endif
// TODO(rjkroege): Enter sandbox here before we start threads in GpuState
@@ -195,39 +197,41 @@ void Service::OnStart() {
discardable_shared_memory_manager_ =
base::MakeUnique<discardable_memory::DiscardableSharedMemoryManager>();
-}
-bool Service::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface<mojom::AccessibilityManager>(this);
- registry->AddInterface<mojom::Clipboard>(this);
- registry->AddInterface<mojom::DisplayManager>(this);
- registry->AddInterface<mojom::Gpu>(this);
- registry->AddInterface<mojom::IMERegistrar>(this);
- registry->AddInterface<mojom::IMEServer>(this);
- registry->AddInterface<mojom::UserAccessManager>(this);
- registry->AddInterface<mojom::UserActivityMonitor>(this);
- registry->AddInterface<WindowTreeHostFactory>(this);
- registry->AddInterface<mojom::WindowManagerWindowTreeFactory>(this);
- registry->AddInterface<mojom::WindowTreeFactory>(this);
- registry
- ->AddInterface<discardable_memory::mojom::DiscardableSharedMemoryManager>(
+ registry_.AddInterface<mojom::AccessibilityManager>(this);
+ registry_.AddInterface<mojom::Clipboard>(this);
+ registry_.AddInterface<mojom::DisplayManager>(this);
+ registry_.AddInterface<mojom::Gpu>(this);
+ registry_.AddInterface<mojom::IMERegistrar>(this);
+ registry_.AddInterface<mojom::IMEServer>(this);
+ registry_.AddInterface<mojom::UserAccessManager>(this);
+ registry_.AddInterface<mojom::UserActivityMonitor>(this);
+ registry_.AddInterface<WindowTreeHostFactory>(this);
+ registry_.AddInterface<mojom::WindowManagerWindowTreeFactory>(this);
+ registry_.AddInterface<mojom::WindowTreeFactory>(this);
+ registry_
+ .AddInterface<discardable_memory::mojom::DiscardableSharedMemoryManager>(
this);
if (test_config_)
- registry->AddInterface<WindowServerTest>(this);
+ registry_.AddInterface<WindowServerTest>(this);
// On non-Linux platforms there will be no DeviceDataManager instance and no
// purpose in adding the Mojo interface to connect to.
if (input_device_server_.IsRegisteredAsObserver())
- input_device_server_.AddInterface(registry);
+ input_device_server_.AddInterface(&registry_);
- screen_manager_->AddInterfaces(registry);
+ screen_manager_->AddInterfaces(&registry_);
#if defined(USE_OZONE)
- ui::OzonePlatform::GetInstance()->AddInterfaces(registry);
+ ui::OzonePlatform::GetInstance()->AddInterfaces(&registry_);
#endif
+}
- return true;
+void Service::OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
void Service::StartDisplayInit() {
diff --git a/chromium/services/ui/service.h b/chromium/services/ui/service.h
index 7bd35c21232..92e5f607828 100644
--- a/chromium/services/ui/service.h
+++ b/chromium/services/ui/service.h
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "components/discardable_memory/public/interfaces/discardable_shared_memory_manager.mojom.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_runner.h"
@@ -32,12 +33,11 @@
#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.mojom.h"
-#include "services/ui/ws/platform_display_init_params.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.h"
+#include "ui/ozone/public/client_native_pixmap_factory_ozone.h"
#endif
namespace discardable_memory {
@@ -102,8 +102,9 @@ class Service
// service_manager::Service:
void OnStart() override;
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// WindowServerDelegate:
void StartDisplayInit() override;
@@ -177,16 +178,16 @@ class Service
UserIdToUserState user_id_to_user_state_;
// Provides input-device information via Mojo IPC. Registers Mojo interfaces
- // and must outlive service_manager::InterfaceRegistry.
+ // and must outlive |registry_|.
InputDeviceServer input_device_server_;
bool test_config_;
#if defined(USE_OZONE)
- std::unique_ptr<ui::ClientNativePixmapFactory> client_native_pixmap_factory_;
+ std::unique_ptr<gfx::ClientNativePixmapFactory> client_native_pixmap_factory_;
#endif
// Manages display hardware and handles display management. May register Mojo
- // interfaces and must outlive service_manager::InterfaceRegistry.
+ // interfaces and must outlive |registry_|.
std::unique_ptr<display::ScreenManager> screen_manager_;
IMERegistrarImpl ime_registrar_;
@@ -195,6 +196,8 @@ class Service
std::unique_ptr<discardable_memory::DiscardableSharedMemoryManager>
discardable_shared_memory_manager_;
+ service_manager::BinderRegistry registry_;
+
DISALLOW_COPY_AND_ASSIGN(Service);
};
diff --git a/chromium/services/ui/surfaces/BUILD.gn b/chromium/services/ui/surfaces/BUILD.gn
index ebaafcb439e..b63bba35746 100644
--- a/chromium/services/ui/surfaces/BUILD.gn
+++ b/chromium/services/ui/surfaces/BUILD.gn
@@ -6,10 +6,10 @@ import("//build/config/ui.gni")
source_set("surfaces") {
sources = [
- "display_compositor.cc",
- "display_compositor.h",
"display_output_surface.cc",
"display_output_surface.h",
+ "mus_display_provider.cc",
+ "mus_display_provider.h",
]
deps = [
@@ -18,6 +18,7 @@ source_set("surfaces") {
"//cc/ipc:interfaces",
"//cc/surfaces",
"//components/display_compositor",
+ "//components/viz/frame_sinks",
"//gpu/command_buffer/client",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/ipc:command_buffer",
@@ -26,6 +27,10 @@ source_set("surfaces") {
"//ui/gfx/geometry/mojo",
]
+ public_deps = [
+ "//ipc",
+ ]
+
if (use_ozone) {
sources += [
"display_output_surface_ozone.cc",
diff --git a/chromium/services/ui/surfaces/DEPS b/chromium/services/ui/surfaces/DEPS
index 257582d5988..1c1bbc83c06 100644
--- a/chromium/services/ui/surfaces/DEPS
+++ b/chromium/services/ui/surfaces/DEPS
@@ -1,7 +1,7 @@
include_rules = [
"+cc",
"+components/display_compositor",
- "+components/gpu",
+ "+components/viz/frame_sinks",
"+gpu",
"+services/service_manager",
"+mojo/common",
diff --git a/chromium/services/ui/surfaces/OWNERS b/chromium/services/ui/surfaces/OWNERS
index 1f1af6bcc54..2edcdb6fff7 100644
--- a/chromium/services/ui/surfaces/OWNERS
+++ b/chromium/services/ui/surfaces/OWNERS
@@ -1,2 +1,4 @@
fsamuel@chromium.org
rjkroege@chromium.org
+
+# COMPONENT: Internals>Compositing
diff --git a/chromium/services/ui/surfaces/display_compositor.cc b/chromium/services/ui/surfaces/display_compositor.cc
deleted file mode 100644
index 4809c17ecd2..00000000000
--- a/chromium/services/ui/surfaces/display_compositor.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-// 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/ui/surfaces/display_compositor.h"
-
-#include <utility>
-
-#include "base/command_line.h"
-#include "base/memory/ptr_util.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "cc/base/switches.h"
-#include "cc/output/in_process_context_provider.h"
-#include "cc/output/texture_mailbox_deleter.h"
-#include "cc/surfaces/display.h"
-#include "cc/surfaces/display_scheduler.h"
-#include "cc/surfaces/surface.h"
-#include "components/display_compositor/gpu_compositor_frame_sink.h"
-#include "components/display_compositor/gpu_root_compositor_frame_sink.h"
-#include "gpu/command_buffer/client/shared_memory_limits.h"
-#include "gpu/ipc/gpu_in_process_thread_service.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-#include "services/ui/surfaces/display_output_surface.h"
-
-#if defined(USE_OZONE)
-#include "gpu/command_buffer/client/gles2_interface.h"
-#include "services/ui/surfaces/display_output_surface_ozone.h"
-#endif
-
-namespace ui {
-
-DisplayCompositor::DisplayCompositor(
- scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
- std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
- gpu::ImageFactory* image_factory,
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtr client)
- : manager_(cc::SurfaceManager::LifetimeType::REFERENCES),
- gpu_service_(std::move(gpu_service)),
- gpu_memory_buffer_manager_(std::move(gpu_memory_buffer_manager)),
- image_factory_(image_factory),
- task_runner_(base::ThreadTaskRunnerHandle::Get()),
- client_(std::move(client)),
- binding_(this, std::move(request)) {
- manager_.AddObserver(this);
-}
-
-DisplayCompositor::~DisplayCompositor() {
- DCHECK(thread_checker_.CalledOnValidThread());
- manager_.RemoveObserver(this);
-}
-
-void DisplayCompositor::CreateRootCompositorFrameSink(
- const cc::FrameSinkId& frame_sink_id,
- gpu::SurfaceHandle surface_handle,
- cc::mojom::MojoCompositorFrameSinkAssociatedRequest request,
- cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request,
- cc::mojom::MojoCompositorFrameSinkClientPtr client,
- cc::mojom::DisplayPrivateAssociatedRequest display_private_request) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_NE(surface_handle, gpu::kNullSurfaceHandle);
- DCHECK_EQ(0u, compositor_frame_sinks_.count(frame_sink_id));
-
- std::unique_ptr<cc::SyntheticBeginFrameSource> begin_frame_source(
- new cc::DelayBasedBeginFrameSource(
- base::MakeUnique<cc::DelayBasedTimeSource>(task_runner_.get())));
- std::unique_ptr<cc::Display> display =
- CreateDisplay(frame_sink_id, surface_handle, begin_frame_source.get());
-
- compositor_frame_sinks_[frame_sink_id] =
- base::MakeUnique<display_compositor::GpuRootCompositorFrameSink>(
- this, &manager_, frame_sink_id, std::move(display),
- std::move(begin_frame_source), std::move(request),
- std::move(private_request), std::move(client),
- std::move(display_private_request));
-}
-
-void DisplayCompositor::CreateCompositorFrameSink(
- const cc::FrameSinkId& frame_sink_id,
- cc::mojom::MojoCompositorFrameSinkRequest request,
- cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request,
- cc::mojom::MojoCompositorFrameSinkClientPtr client) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_EQ(0u, compositor_frame_sinks_.count(frame_sink_id));
-
- compositor_frame_sinks_[frame_sink_id] =
- base::MakeUnique<display_compositor::GpuCompositorFrameSink>(
- this, &manager_, frame_sink_id, std::move(request),
- std::move(private_request), std::move(client));
-}
-
-void DisplayCompositor::RegisterFrameSinkHierarchy(
- const cc::FrameSinkId& parent_frame_sink_id,
- const cc::FrameSinkId& child_frame_sink_id) {
- manager_.RegisterFrameSinkHierarchy(parent_frame_sink_id,
- child_frame_sink_id);
-}
-
-void DisplayCompositor::UnregisterFrameSinkHierarchy(
- const cc::FrameSinkId& parent_frame_sink_id,
- const cc::FrameSinkId& child_frame_sink_id) {
- manager_.UnregisterFrameSinkHierarchy(parent_frame_sink_id,
- child_frame_sink_id);
-}
-
-void DisplayCompositor::DropTemporaryReference(
- const cc::SurfaceId& surface_id) {
- manager_.DropTemporaryReference(surface_id);
-}
-
-std::unique_ptr<cc::Display> DisplayCompositor::CreateDisplay(
- const cc::FrameSinkId& frame_sink_id,
- gpu::SurfaceHandle surface_handle,
- cc::SyntheticBeginFrameSource* begin_frame_source) {
- scoped_refptr<cc::InProcessContextProvider> context_provider =
- new cc::InProcessContextProvider(
- gpu_service_, surface_handle, gpu_memory_buffer_manager_.get(),
- image_factory_, gpu::SharedMemoryLimits(),
- nullptr /* shared_context */);
-
- // TODO(rjkroege): If there is something better to do than CHECK, add it.
- CHECK(context_provider->BindToCurrentThread());
-
- std::unique_ptr<cc::OutputSurface> display_output_surface;
- if (context_provider->ContextCapabilities().surfaceless) {
-#if defined(USE_OZONE)
- display_output_surface = base::MakeUnique<DisplayOutputSurfaceOzone>(
- std::move(context_provider), surface_handle,
- begin_frame_source, gpu_memory_buffer_manager_.get(),
- GL_TEXTURE_2D, GL_RGB);
-#else
- NOTREACHED();
-#endif
- } else {
- display_output_surface = base::MakeUnique<DisplayOutputSurface>(
- std::move(context_provider), begin_frame_source);
- }
-
- int max_frames_pending =
- display_output_surface->capabilities().max_frames_pending;
- DCHECK_GT(max_frames_pending, 0);
-
- std::unique_ptr<cc::DisplayScheduler> scheduler(
- new cc::DisplayScheduler(task_runner_.get(), max_frames_pending));
-
- cc::RendererSettings settings;
- settings.show_overdraw_feedback =
- base::CommandLine::ForCurrentProcess()->HasSwitch(
- cc::switches::kShowOverdrawFeedback);
-
- return base::MakeUnique<cc::Display>(
- nullptr /* bitmap_manager */, gpu_memory_buffer_manager_.get(), settings,
- frame_sink_id, begin_frame_source, std::move(display_output_surface),
- std::move(scheduler),
- base::MakeUnique<cc::TextureMailboxDeleter>(task_runner_.get()));
-}
-
-void DisplayCompositor::DestroyCompositorFrameSink(cc::FrameSinkId sink_id) {
- compositor_frame_sinks_.erase(sink_id);
-}
-
-void DisplayCompositor::OnSurfaceCreated(const cc::SurfaceInfo& surface_info) {
- DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_GT(surface_info.device_scale_factor(), 0.0f);
-
- // TODO(kylechar): |client_| will try to find an owner for the temporary
- // reference to the new surface. With surface synchronization this might not
- // be necessary, because a surface reference might already exist and no
- // temporary reference was created. It could be useful to let |client_| know
- // if it should find an owner.
- if (client_)
- client_->OnSurfaceCreated(surface_info);
-}
-
-void DisplayCompositor::OnSurfaceDamaged(const cc::SurfaceId& surface_id,
- bool* changed) {}
-
-void DisplayCompositor::OnClientConnectionLost(
- const cc::FrameSinkId& frame_sink_id,
- bool destroy_compositor_frame_sink) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (destroy_compositor_frame_sink)
- DestroyCompositorFrameSink(frame_sink_id);
- // TODO(fsamuel): Tell the display compositor host that the client connection
- // has been lost so that it can drop its private connection and allow a new
- // client instance to create a new CompositorFrameSink.
-}
-
-void DisplayCompositor::OnPrivateConnectionLost(
- const cc::FrameSinkId& frame_sink_id,
- bool destroy_compositor_frame_sink) {
- DCHECK(thread_checker_.CalledOnValidThread());
- if (destroy_compositor_frame_sink)
- DestroyCompositorFrameSink(frame_sink_id);
-}
-
-} // namespace ui
diff --git a/chromium/services/ui/surfaces/display_compositor.h b/chromium/services/ui/surfaces/display_compositor.h
deleted file mode 100644
index 260c1f4fcae..00000000000
--- a/chromium/services/ui/surfaces/display_compositor.h
+++ /dev/null
@@ -1,137 +0,0 @@
-// 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_UI_SURFACES_DISPLAY_COMPOSITOR_H_
-#define SERVICES_UI_SURFACES_DISPLAY_COMPOSITOR_H_
-
-#include <stdint.h>
-
-#include <memory>
-#include <unordered_map>
-#include <vector>
-
-#include "base/macros.h"
-#include "base/threading/thread_checker.h"
-#include "cc/ipc/display_compositor.mojom.h"
-#include "cc/surfaces/frame_sink_id.h"
-#include "cc/surfaces/local_surface_id.h"
-#include "cc/surfaces/surface_id.h"
-#include "cc/surfaces/surface_manager.h"
-#include "cc/surfaces/surface_observer.h"
-#include "components/display_compositor/gpu_compositor_frame_sink_delegate.h"
-#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
-#include "gpu/ipc/common/surface_handle.h"
-#include "gpu/ipc/in_process_command_buffer.h"
-#include "ipc/ipc_channel_handle.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace gpu {
-class GpuMemoryBufferManager;
-class ImageFactory;
-}
-
-namespace cc {
-class Display;
-class SyntheticBeginFrameSource;
-}
-
-namespace display_compositor {
-class GpuCompositorFrameSink;
-}
-
-namespace ui {
-
-// The DisplayCompositor object is an object global to the Window Server app
-// that holds the SurfaceServer and allocates new Surfaces namespaces.
-// This object lives on the main thread of the Window Server.
-// TODO(rjkroege, fsamuel): This object will need to change to support multiple
-// displays.
-class DisplayCompositor
- : public cc::SurfaceObserver,
- public display_compositor::GpuCompositorFrameSinkDelegate,
- public cc::mojom::DisplayCompositor {
- public:
- DisplayCompositor(
- scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
- std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
- gpu::ImageFactory* image_factory,
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtr client);
- ~DisplayCompositor() override;
-
- cc::SurfaceManager* manager() { return &manager_; }
-
- // cc::mojom::DisplayCompositor implementation:
- void CreateRootCompositorFrameSink(
- const cc::FrameSinkId& frame_sink_id,
- gpu::SurfaceHandle surface_handle,
- cc::mojom::MojoCompositorFrameSinkAssociatedRequest request,
- cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request,
- cc::mojom::MojoCompositorFrameSinkClientPtr client,
- cc::mojom::DisplayPrivateAssociatedRequest display_private_request)
- override;
- void CreateCompositorFrameSink(
- const cc::FrameSinkId& frame_sink_id,
- cc::mojom::MojoCompositorFrameSinkRequest request,
- cc::mojom::MojoCompositorFrameSinkPrivateRequest private_request,
- cc::mojom::MojoCompositorFrameSinkClientPtr client) override;
- void RegisterFrameSinkHierarchy(
- const cc::FrameSinkId& parent_frame_sink_id,
- const cc::FrameSinkId& child_frame_sink_id) override;
- void UnregisterFrameSinkHierarchy(
- const cc::FrameSinkId& parent_frame_sink_id,
- const cc::FrameSinkId& child_frame_sink_id) override;
- void DropTemporaryReference(const cc::SurfaceId& surface_id) override;
-
- private:
- std::unique_ptr<cc::Display> CreateDisplay(
- const cc::FrameSinkId& frame_sink_id,
- gpu::SurfaceHandle surface_handle,
- cc::SyntheticBeginFrameSource* begin_frame_source);
-
- // It is necessary to pass |frame_sink_id| by value because the id
- // is owned by the GpuCompositorFrameSink in the map. When the sink is
- // removed from the map, |frame_sink_id| would also be destroyed if it were a
- // reference. But the map can continue to iterate and try to use it. Passing
- // by value avoids this.
- void DestroyCompositorFrameSink(cc::FrameSinkId frame_sink_id);
-
- // cc::SurfaceObserver implementation.
- void OnSurfaceCreated(const cc::SurfaceInfo& surface_info) override;
- void OnSurfaceDamaged(const cc::SurfaceId& surface_id,
- bool* changed) override;
-
- // display_compositor::GpuCompositorFrameSinkDelegate implementation.
- void OnClientConnectionLost(const cc::FrameSinkId& frame_sink_id,
- bool destroy_compositor_frame_sink) override;
- void OnPrivateConnectionLost(const cc::FrameSinkId& frame_sink_id,
- bool destroy_compositor_frame_sink) override;
-
- // SurfaceManager should be the first object constructed and the last object
- // destroyed in order to ensure that all other objects that depend on it have
- // access to a valid pointer for the entirety of their liftimes.
- cc::SurfaceManager manager_;
-
- scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service_;
- std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
- gpu::ImageFactory* image_factory_;
-
- std::unordered_map<cc::FrameSinkId,
- std::unique_ptr<cc::mojom::MojoCompositorFrameSink>,
- cc::FrameSinkIdHash>
- compositor_frame_sinks_;
-
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
- base::ThreadChecker thread_checker_;
-
- cc::mojom::DisplayCompositorClientPtr client_;
- mojo::Binding<cc::mojom::DisplayCompositor> binding_;
-
- DISALLOW_COPY_AND_ASSIGN(DisplayCompositor);
-};
-
-} // namespace ui
-
-#endif // SERVICES_UI_SURFACES_DISPLAY_COMPOSITOR_H_
diff --git a/chromium/services/ui/surfaces/mus_display_provider.cc b/chromium/services/ui/surfaces/mus_display_provider.cc
new file mode 100644
index 00000000000..30be7d10fa0
--- /dev/null
+++ b/chromium/services/ui/surfaces/mus_display_provider.cc
@@ -0,0 +1,94 @@
+// 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/ui/surfaces/mus_display_provider.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "cc/base/switches.h"
+#include "cc/output/in_process_context_provider.h"
+#include "cc/output/texture_mailbox_deleter.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/display_scheduler.h"
+#include "gpu/command_buffer/client/shared_memory_limits.h"
+#include "gpu/command_buffer/service/image_factory.h"
+#include "services/ui/surfaces/display_output_surface.h"
+
+#if defined(USE_OZONE)
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "services/ui/surfaces/display_output_surface_ozone.h"
+#endif
+
+namespace ui {
+
+MusDisplayProvider::MusDisplayProvider(
+ scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
+ std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
+ gpu::ImageFactory* image_factory)
+ : gpu_service_(std::move(gpu_service)),
+ gpu_memory_buffer_manager_(std::move(gpu_memory_buffer_manager)),
+ image_factory_(image_factory),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+
+MusDisplayProvider::~MusDisplayProvider() {}
+
+std::unique_ptr<cc::Display> MusDisplayProvider::CreateDisplay(
+ const cc::FrameSinkId& frame_sink_id,
+ gpu::SurfaceHandle surface_handle,
+ std::unique_ptr<cc::BeginFrameSource>* begin_frame_source) {
+ auto synthetic_begin_frame_source =
+ base::MakeUnique<cc::DelayBasedBeginFrameSource>(
+ base::MakeUnique<cc::DelayBasedTimeSource>(task_runner_.get()));
+
+ scoped_refptr<cc::InProcessContextProvider> context_provider =
+ new cc::InProcessContextProvider(
+ gpu_service_, surface_handle, gpu_memory_buffer_manager_.get(),
+ image_factory_, gpu::SharedMemoryLimits(),
+ nullptr /* shared_context */);
+
+ // TODO(rjkroege): If there is something better to do than CHECK, add it.
+ CHECK(context_provider->BindToCurrentThread());
+
+ std::unique_ptr<cc::OutputSurface> display_output_surface;
+ if (context_provider->ContextCapabilities().surfaceless) {
+#if defined(USE_OZONE)
+ display_output_surface = base::MakeUnique<DisplayOutputSurfaceOzone>(
+ std::move(context_provider), surface_handle,
+ synthetic_begin_frame_source.get(), gpu_memory_buffer_manager_.get(),
+ GL_TEXTURE_2D, GL_RGB);
+#else
+ NOTREACHED();
+#endif
+ } else {
+ display_output_surface = base::MakeUnique<DisplayOutputSurface>(
+ std::move(context_provider), synthetic_begin_frame_source.get());
+ }
+
+ int max_frames_pending =
+ display_output_surface->capabilities().max_frames_pending;
+ DCHECK_GT(max_frames_pending, 0);
+
+ auto scheduler = base::MakeUnique<cc::DisplayScheduler>(task_runner_.get(),
+ max_frames_pending);
+
+ cc::RendererSettings settings;
+ settings.show_overdraw_feedback =
+ base::CommandLine::ForCurrentProcess()->HasSwitch(
+ cc::switches::kShowOverdrawFeedback);
+
+ // The ownership of the BeginFrameSource is transfered to the caller.
+ *begin_frame_source = std::move(synthetic_begin_frame_source);
+
+ return base::MakeUnique<cc::Display>(
+ nullptr /* bitmap_manager */, gpu_memory_buffer_manager_.get(), settings,
+ frame_sink_id, begin_frame_source->get(),
+ std::move(display_output_surface), std::move(scheduler),
+ base::MakeUnique<cc::TextureMailboxDeleter>(task_runner_.get()));
+}
+
+} // namespace ui
diff --git a/chromium/services/ui/surfaces/mus_display_provider.h b/chromium/services/ui/surfaces/mus_display_provider.h
new file mode 100644
index 00000000000..f5438832036
--- /dev/null
+++ b/chromium/services/ui/surfaces/mus_display_provider.h
@@ -0,0 +1,52 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef SERVICES_UI_SURFACES_MUS_DISPLAY_PROVIDER_H_
+#define SERVICES_UI_SURFACES_MUS_DISPLAY_PROVIDER_H_
+
+#include <memory>
+
+#include "base/compiler_specific.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "cc/surfaces/frame_sink_id.h"
+#include "components/viz/frame_sinks/display_provider.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+#include "gpu/ipc/common/surface_handle.h"
+#include "gpu/ipc/in_process_command_buffer.h"
+
+namespace gpu {
+class ImageFactory;
+}
+
+namespace ui {
+
+// Mus implementation of DisplayProvider. This will be created in mus-gpu.
+class MusDisplayProvider : public NON_EXPORTED_BASE(viz::DisplayProvider) {
+ public:
+ MusDisplayProvider(
+ scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service,
+ std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager,
+ gpu::ImageFactory* image_factory);
+ ~MusDisplayProvider() override;
+
+ // display_compositor::DisplayProvider:
+ std::unique_ptr<cc::Display> CreateDisplay(
+ const cc::FrameSinkId& frame_sink_id,
+ gpu::SurfaceHandle surface_handle,
+ std::unique_ptr<cc::BeginFrameSource>* begin_frame_source) override;
+
+ private:
+ scoped_refptr<gpu::InProcessCommandBuffer::Service> gpu_service_;
+ std::unique_ptr<gpu::GpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ gpu::ImageFactory* image_factory_;
+
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(MusDisplayProvider);
+};
+
+} // namespace ui
+
+#endif // SERVICES_UI_SURFACES_MUS_DISPLAY_PROVIDER_H_
diff --git a/chromium/services/ui/test_wm/test_wm.cc b/chromium/services/ui/test_wm/test_wm.cc
index a0c75dbe180..3fb4269a930 100644
--- a/chromium/services/ui/test_wm/test_wm.cc
+++ b/chromium/services/ui/test_wm/test_wm.cc
@@ -63,11 +63,9 @@ class TestWM : public service_manager::Service,
aura_env_->SetWindowTreeClient(window_tree_client_.get());
window_tree_client_->ConnectAsWindowManager();
}
-
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override {
- return false;
- }
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {}
// aura::WindowTreeClientDelegate:
void OnEmbed(
@@ -98,8 +96,8 @@ class TestWM : public service_manager::Service,
void SetWindowManagerClient(aura::WindowManagerClient* client) override {
window_manager_client_ = client;
}
- bool OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) override {
- return true;
+ void OnWmSetBounds(aura::Window* window, const gfx::Rect& bounds) override {
+ window->SetBounds(bounds);
}
bool OnWmSetProperty(
aura::Window* window,
@@ -107,6 +105,7 @@ class TestWM : public service_manager::Service,
std::unique_ptr<std::vector<uint8_t>>* new_data) override {
return true;
}
+ void OnWmSetModalType(aura::Window* window, ui::ModalType type) override {}
void OnWmSetCanFocus(aura::Window* window, bool can_focus) override {}
aura::Window* OnWmCreateTopLevelWindow(
ui::mojom::WindowType window_type,
@@ -122,6 +121,12 @@ class TestWM : public service_manager::Service,
bool janky) override {
// Don't care.
}
+ void OnWmBuildDragImage(const gfx::Point& screen_location,
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ ui::mojom::PointerKind source) override {}
+ void OnWmMoveDragImage(const gfx::Point& screen_location) override {}
+ void OnWmDestroyDragImage() override {}
void OnWmWillCreateDisplay(const display::Display& display) override {
// This class only deals with one display.
DCHECK_EQ(0u, screen_->display_list().displays().size());
diff --git a/chromium/services/ui/ws/BUILD.gn b/chromium/services/ui/ws/BUILD.gn
index 7408a083aa3..90db269448f 100644
--- a/chromium/services/ui/ws/BUILD.gn
+++ b/chromium/services/ui/ws/BUILD.gn
@@ -9,6 +9,10 @@ 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")
+# In external window mode, top-level windows are native platform windows i.e.
+# not children of a Chrome OS window manager's root window.
+is_external_mode = use_ozone && !is_chromeos
+
static_library("lib") {
sources = [
"accelerator.cc",
@@ -25,6 +29,8 @@ static_library("lib") {
"display.h",
"display_binding.cc",
"display_binding.h",
+ "display_client_compositor_frame_sink.cc",
+ "display_client_compositor_frame_sink.h",
"display_manager.cc",
"display_manager.h",
"drag_controller.cc",
@@ -43,6 +49,8 @@ static_library("lib") {
"focus_controller_observer.h",
"frame_generator.cc",
"frame_generator.h",
+ "gpu_client.cc",
+ "gpu_client.h",
"gpu_host.cc",
"gpu_host.h",
"gpu_host_delegate.h",
@@ -56,8 +64,6 @@ static_library("lib") {
"platform_display_default.h",
"platform_display_delegate.h",
"platform_display_factory.h",
- "platform_display_init_params.cc",
- "platform_display_init_params.h",
"server_window.cc",
"server_window.h",
"server_window_compositor_frame_sink_manager.cc",
@@ -147,6 +153,18 @@ static_library("lib") {
if (use_ozone) {
public_deps += [ "//ui/ozone:ozone" ]
}
+ if (is_chromeos) {
+ public_deps += [ "//ui/chromeos/events" ]
+ }
+
+ # ui service should not depend on below components.
+ assert_no_deps = [
+ "//ash",
+ "//content/public/browser",
+ "//content/public/common",
+ "//ui/aura",
+ "//ui/views",
+ ]
}
static_library("test_interface") {
@@ -171,10 +189,18 @@ static_library("test_support") {
"test_change_tracker.h",
"window_server_service_test_base.cc",
"window_server_service_test_base.h",
- "window_server_test_base.cc",
- "window_server_test_base.h",
]
+ if (!is_external_mode) {
+ # WindowServerTestBase assumes an initial display (and root) is provided
+ # at startup, which is not the case on platforms running external window
+ # mode.
+ sources += [
+ "window_server_test_base.cc",
+ "window_server_test_base.h",
+ ]
+ }
+
deps = [
"//base",
"//base/test:test_config",
@@ -213,6 +239,8 @@ service_test("mus_ws_unittests") {
"event_dispatcher_unittest.cc",
"event_matcher_unittest.cc",
"focus_controller_unittest.cc",
+ "frame_generator_unittest.cc",
+ "gpu_host_unittest.cc",
"server_window_drawn_tracker_unittest.cc",
"test_server_window_delegate.cc",
"test_server_window_delegate.h",
@@ -223,12 +251,23 @@ service_test("mus_ws_unittests") {
"user_display_manager_unittest.cc",
"window_coordinate_conversions_unittest.cc",
"window_finder_unittest.cc",
- "window_manager_client_unittest.cc",
"window_manager_state_unittest.cc",
"window_tree_client_unittest.cc",
"window_tree_unittest.cc",
]
+ if (!is_external_mode) {
+ # A window manager client is not needed on platforms running external
+ # window mode, since the host system is always the window manager.
+ sources += [ "window_manager_client_unittest.cc" ]
+ }
+
+ # TODO(jamescook): Run this test on non-ozone platforms. This will require
+ # initializing all the platform-specific windowing support.
+ if (use_ozone) {
+ sources += [ "platform_display_default_unittest.cc" ]
+ }
+
catalog = ":mus_ws_unittests_catalog"
deps = [
@@ -238,6 +277,7 @@ service_test("mus_ws_unittests") {
"//base/test:test_config",
"//base/test:test_support",
"//cc:cc",
+ "//cc:test_support",
"//gpu/ipc/client",
"//mojo/public/cpp/bindings:bindings",
"//services/service_manager/public/cpp:service_test_support",
@@ -245,6 +285,7 @@ service_test("mus_ws_unittests") {
"//services/service_manager/public/interfaces",
"//services/ui/common:mus_common",
"//services/ui/common:task_runner_test_base",
+ "//services/ui/gpu:gpu",
"//services/ui/public/cpp",
"//services/ui/public/interfaces",
"//testing/gtest",
diff --git a/chromium/services/ui/ws/DEPS b/chromium/services/ui/ws/DEPS
index f771ac877ca..9145166001c 100644
--- a/chromium/services/ui/ws/DEPS
+++ b/chromium/services/ui/ws/DEPS
@@ -11,4 +11,7 @@ specific_include_rules = {
"gpu_host.h": [
"+services/ui/gpu/gpu_main.h",
],
+ "gpu_host_unittest.cc": [
+ "+services/ui/gpu"
+ ],
}
diff --git a/chromium/services/ui/ws/OWNERS b/chromium/services/ui/ws/OWNERS
index 02f5fed1053..b720a393c19 100644
--- a/chromium/services/ui/ws/OWNERS
+++ b/chromium/services/ui/ws/OWNERS
@@ -2,3 +2,4 @@ per-file *gpu*=fsamuel@chromium.org
per-file *gpu*=sadrul@chromium.org
per-file *compositor_frame*=fsamuel@chromium.org
per-file *compositor_frame*=rjkroege@chromium.org
+per-file *frame_generator*=fsamuel@chromium.org \ No newline at end of file
diff --git a/chromium/services/ui/ws/cursor_unittest.cc b/chromium/services/ui/ws/cursor_unittest.cc
index 732eb51894e..678723a734b 100644
--- a/chromium/services/ui/ws/cursor_unittest.cc
+++ b/chromium/services/ui/ws/cursor_unittest.cc
@@ -42,7 +42,7 @@ class CursorTest : public testing::Test {
TestWindowServerDelegate* window_server_delegate() {
return ws_test_helper_.window_server_delegate();
}
- mojom::Cursor cursor() const { return ws_test_helper_.cursor(); }
+ mojom::CursorType cursor() const { return ws_test_helper_.cursor(); }
protected:
// testing::Test:
@@ -90,8 +90,11 @@ class CursorTest : public testing::Test {
WindowManagerDisplayRoot* active_display_root =
display->GetActiveWindowManagerDisplayRoot();
ASSERT_TRUE(active_display_root);
- static_cast<PlatformDisplayDelegate*>(display)->OnEvent(PointerEvent(
- MouseEvent(ET_MOUSE_MOVED, p, p, base::TimeTicks(), 0, 0)));
+ PointerEvent event(
+ MouseEvent(ET_MOUSE_MOVED, p, p, base::TimeTicks(), 0, 0));
+ ignore_result(static_cast<PlatformDisplayDelegate*>(display)
+ ->GetEventSink()
+ ->OnEventFromSource(&event));
WindowManagerState* wms = active_display_root->window_manager_state();
wms->OnEventAck(wms->window_tree(), mojom::EventResult::HANDLED);
}
@@ -104,81 +107,81 @@ class CursorTest : public testing::Test {
TEST_F(CursorTest, ChangeByMouseMove) {
ServerWindow* win = BuildServerWindow();
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- win->parent()->SetPredefinedCursor(mojom::Cursor::CELL);
- EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor());
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
+ win->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ win->parent()->SetPredefinedCursor(mojom::CursorType::CELL);
+ EXPECT_EQ(mojom::CursorType::IBEAM, win->cursor());
+ win->SetNonClientCursor(mojom::CursorType::EAST_RESIZE);
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, win->non_client_cursor());
// Non client area
MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, cursor());
// Client area, which comes from win->parent().
MoveCursorTo(gfx::Point(25, 25));
- EXPECT_EQ(mojom::Cursor::CELL, cursor());
+ EXPECT_EQ(mojom::CursorType::CELL, cursor());
}
TEST_F(CursorTest, ChangeByClientAreaChange) {
ServerWindow* win = BuildServerWindow();
- win->parent()->SetPredefinedCursor(mojom::Cursor::CROSS);
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, mojom::Cursor(win->cursor()));
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
+ win->parent()->SetPredefinedCursor(mojom::CursorType::CROSS);
+ win->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ EXPECT_EQ(mojom::CursorType::IBEAM, mojom::CursorType(win->cursor()));
+ win->SetNonClientCursor(mojom::CursorType::EAST_RESIZE);
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, win->non_client_cursor());
// Non client area before we move.
MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, cursor());
// Changing the client area should cause a change. The cursor for the client
// area comes from root ancestor, which is win->parent().
win->SetClientArea(gfx::Insets(1, 1), std::vector<gfx::Rect>());
- EXPECT_EQ(mojom::Cursor::CROSS, cursor());
+ EXPECT_EQ(mojom::CursorType::CROSS, cursor());
}
TEST_F(CursorTest, NonClientCursorChange) {
ServerWindow* win = BuildServerWindow();
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor());
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
+ win->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ EXPECT_EQ(mojom::CursorType::IBEAM, win->cursor());
+ win->SetNonClientCursor(mojom::CursorType::EAST_RESIZE);
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, win->non_client_cursor());
MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, cursor());
- win->SetNonClientCursor(mojom::Cursor::WEST_RESIZE);
- EXPECT_EQ(mojom::Cursor::WEST_RESIZE, cursor());
+ win->SetNonClientCursor(mojom::CursorType::WEST_RESIZE);
+ EXPECT_EQ(mojom::CursorType::WEST_RESIZE, cursor());
}
TEST_F(CursorTest, IgnoreClientCursorChangeInNonClientArea) {
ServerWindow* win = BuildServerWindow();
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor());
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
+ win->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ EXPECT_EQ(mojom::CursorType::IBEAM, win->cursor());
+ win->SetNonClientCursor(mojom::CursorType::EAST_RESIZE);
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, win->non_client_cursor());
MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, cursor());
- win->SetPredefinedCursor(mojom::Cursor::HELP);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
+ win->SetPredefinedCursor(mojom::CursorType::HELP);
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, cursor());
}
TEST_F(CursorTest, NonClientToClientByBoundsChange) {
ServerWindow* win = BuildServerWindow();
- win->parent()->SetPredefinedCursor(mojom::Cursor::COPY);
- win->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::IBEAM, win->cursor());
- win->SetNonClientCursor(mojom::Cursor::EAST_RESIZE);
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, win->non_client_cursor());
+ win->parent()->SetPredefinedCursor(mojom::CursorType::COPY);
+ win->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ EXPECT_EQ(mojom::CursorType::IBEAM, win->cursor());
+ win->SetNonClientCursor(mojom::CursorType::EAST_RESIZE);
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, win->non_client_cursor());
// Non client area before we move.
MoveCursorTo(gfx::Point(15, 15));
- EXPECT_EQ(mojom::Cursor::EAST_RESIZE, cursor());
+ EXPECT_EQ(mojom::CursorType::EAST_RESIZE, cursor());
win->SetBounds(gfx::Rect(0, 0, 30, 30));
- EXPECT_EQ(mojom::Cursor::COPY, cursor());
+ EXPECT_EQ(mojom::CursorType::COPY, cursor());
}
} // namespace test
diff --git a/chromium/services/ui/ws/display.cc b/chromium/services/ui/ws/display.cc
index b3981b86032..fa0ec946fae 100644
--- a/chromium/services/ui/ws/display.cc
+++ b/chromium/services/ui/ws/display.cc
@@ -12,12 +12,12 @@
#include "base/strings/utf_string_conversions.h"
#include "services/service_manager/public/interfaces/connector.mojom.h"
#include "services/ui/common/types.h"
-#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/display/viewport_metrics.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/ws/display_binding.h"
#include "services/ui/ws/display_manager.h"
#include "services/ui/ws/focus_controller.h"
#include "services/ui/ws/platform_display.h"
-#include "services/ui/ws/platform_display_init_params.h"
#include "services/ui/ws/user_activity_monitor.h"
#include "services/ui/ws/window_manager_display_root.h"
#include "services/ui/ws/window_manager_state.h"
@@ -27,12 +27,18 @@
#include "services/ui/ws/window_tree.h"
#include "services/ui/ws/window_tree_binding.h"
#include "ui/base/cursor/cursor.h"
+#include "ui/display/screen.h"
+
+#if defined(USE_OZONE)
+#include "ui/ozone/public/ozone_platform.h"
+#endif
namespace ui {
namespace ws {
Display::Display(WindowServer* window_server)
- : window_server_(window_server), last_cursor_(mojom::Cursor::CURSOR_NULL) {
+ : window_server_(window_server),
+ last_cursor_(mojom::CursorType::CURSOR_NULL) {
window_server_->window_manager_window_tree_factory_set()->AddObserver(this);
window_server_->user_id_tracker()->AddObserver(this);
}
@@ -60,21 +66,28 @@ Display::~Display() {
}
}
-void Display::Init(const PlatformDisplayInitParams& init_params,
+void Display::Init(const display::ViewportMetrics& metrics,
std::unique_ptr<DisplayBinding> binding) {
binding_ = std::move(binding);
display_manager()->AddDisplay(this);
- CreateRootWindow(init_params.metrics.pixel_size);
- PlatformDisplayInitParams params_copy = init_params;
- params_copy.root_window = root_.get();
+ CreateRootWindow(metrics.bounds_in_pixels.size());
- platform_display_ = PlatformDisplay::Create(params_copy);
+ platform_display_ = PlatformDisplay::Create(root_.get(), metrics);
platform_display_->Init(this);
}
int64_t Display::GetId() const {
- return platform_display_->GetId();
+ // TODO(tonikitoo): Implement a different ID for external window mode.
+ return display_.id();
+}
+
+void Display::SetDisplay(const display::Display& display) {
+ display_ = display;
+}
+
+const display::Display& Display::GetDisplay() {
+ return display_;
}
DisplayManager* Display::display_manager() {
@@ -85,22 +98,6 @@ const DisplayManager* Display::display_manager() const {
return window_server_->display_manager();
}
-display::Display Display::ToDisplay() const {
- display::Display display(GetId());
-
- const display::ViewportMetrics& metrics =
- platform_display_->GetViewportMetrics();
-
- display.set_bounds(metrics.bounds);
- display.set_work_area(metrics.work_area);
- display.set_device_scale_factor(metrics.device_scale_factor);
- display.set_rotation(metrics.rotation);
- display.set_touch_support(
- display::Display::TouchSupport::TOUCH_SUPPORT_UNKNOWN);
-
- return display;
-}
-
gfx::Size Display::GetSize() const {
DCHECK(root_);
return root_->bounds().size();
@@ -189,7 +186,19 @@ void Display::OnWillDestroyTree(WindowTree* tree) {
}
}
-void Display::UpdateNativeCursor(mojom::Cursor cursor_id) {
+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);
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+void Display::UpdateNativeCursor(mojom::CursorType cursor_id) {
if (cursor_id != last_cursor_) {
platform_display_->SetCursorById(cursor_id);
last_cursor_ = cursor_id;
@@ -220,7 +229,7 @@ void Display::InitWindowManagerDisplayRoots() {
} else {
CreateWindowManagerDisplayRootsFromFactories();
}
- display_manager()->OnDisplayUpdate(this);
+ display_manager()->OnDisplayUpdate(display_);
}
void Display::CreateWindowManagerDisplayRootsFromFactories() {
@@ -258,54 +267,50 @@ void Display::CreateRootWindow(const gfx::Size& size) {
ServerWindow::Properties()));
root_->set_event_targeting_policy(
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
- root_->SetBounds(gfx::Rect(size));
+ root_->SetBounds(gfx::Rect(size), allocator_.GenerateId());
root_->SetVisible(true);
focus_controller_ = base::MakeUnique<FocusController>(this, root_.get());
focus_controller_->AddObserver(this);
}
-display::Display Display::GetDisplay() {
- return ToDisplay();
-}
-
ServerWindow* Display::GetRootWindow() {
return root_.get();
}
+EventSink* Display::GetEventSink() {
+ return this;
+}
+
void Display::OnAcceleratedWidgetAvailable() {
display_manager()->OnDisplayAcceleratedWidgetAvailable(this);
InitWindowManagerDisplayRoots();
}
-bool Display::IsInHighContrastMode() {
- return window_server_->IsActiveUserInHighContrastMode();
-}
-
-void Display::OnEvent(const ui::Event& event) {
- WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
- if (display_root)
- display_root->window_manager_state()->ProcessEvent(event, GetId());
- window_server_
- ->GetUserActivityMonitorForUser(
- window_server_->user_id_tracker()->active_id())
- ->OnUserActivity();
-}
-
void Display::OnNativeCaptureLost() {
WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
if (display_root)
display_root->window_manager_state()->SetCapture(nullptr, kInvalidClientId);
}
+OzonePlatform* Display::GetOzonePlatform() {
+#if defined(USE_OZONE)
+ return OzonePlatform::GetInstance();
+#else
+ return nullptr;
+#endif
+}
+
void Display::OnViewportMetricsChanged(
const display::ViewportMetrics& metrics) {
- if (root_->bounds().size() == metrics.pixel_size)
+ platform_display_->UpdateViewportMetrics(metrics);
+
+ if (root_->bounds().size() == metrics.bounds_in_pixels.size())
return;
- gfx::Rect new_bounds(metrics.pixel_size);
- root_->SetBounds(new_bounds);
+ gfx::Rect new_bounds(metrics.bounds_in_pixels.size());
+ root_->SetBounds(new_bounds, allocator_.GenerateId());
for (auto& pair : window_manager_display_root_map_)
- pair.second->root()->SetBounds(new_bounds);
+ pair.second->root()->SetBounds(new_bounds, allocator_.GenerateId());
}
ServerWindow* Display::GetActiveRootWindow() {
@@ -398,5 +403,19 @@ void Display::OnWindowManagerWindowTreeFactoryReady(
CreateWindowManagerDisplayRootFromFactory(factory);
}
+EventDispatchDetails Display::OnEventFromSource(Event* event) {
+ WindowManagerDisplayRoot* display_root = GetActiveWindowManagerDisplayRoot();
+ if (display_root) {
+ WindowManagerState* wm_state = 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();
+ return EventDispatchDetails();
+}
+
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/display.h b/chromium/services/ui/ws/display.h
index 2fae94d743b..b83ce211e07 100644
--- a/chromium/services/ui/ws/display.h
+++ b/chromium/services/ui/ws/display.h
@@ -14,6 +14,7 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
+#include "cc/surfaces/local_surface_id_allocator.h"
#include "services/ui/common/types.h"
#include "services/ui/public/interfaces/window_manager_constants.mojom.h"
#include "services/ui/public/interfaces/window_tree_host.mojom.h"
@@ -27,6 +28,11 @@
#include "services/ui/ws/user_id_tracker_observer.h"
#include "services/ui/ws/window_manager_window_tree_factory_set_observer.h"
#include "ui/display/display.h"
+#include "ui/events/event_sink.h"
+
+namespace display {
+struct ViewportMetrics;
+}
namespace ui {
namespace ws {
@@ -34,7 +40,6 @@ namespace ws {
class DisplayBinding;
class DisplayManager;
class FocusController;
-struct PlatformDisplayInitParams;
class WindowManagerDisplayRoot;
class WindowServer;
class WindowTree;
@@ -45,8 +50,7 @@ class DisplayTestApi;
// Displays manages the state associated with a single display. Display has a
// single root window whose children are the roots for a per-user
-// WindowManager. Display is configured in two distinct
-// ways:
+// WindowManager. Display is configured in two distinct ways:
// . with a DisplayBinding. In this mode there is only ever one WindowManager
// for the display, which comes from the client that created the
// Display.
@@ -57,26 +61,33 @@ class Display : public PlatformDisplayDelegate,
public FocusControllerObserver,
public FocusControllerDelegate,
public UserIdTrackerObserver,
- public WindowManagerWindowTreeFactorySetObserver {
+ public WindowManagerWindowTreeFactorySetObserver,
+ public EventSink {
public:
explicit Display(WindowServer* window_server);
~Display() override;
// Initializes the display root ServerWindow and PlatformDisplay. Adds this to
// DisplayManager as a pending display, until accelerated widget is available.
- void Init(const PlatformDisplayInitParams& init_params,
+ void Init(const display::ViewportMetrics& metrics,
std::unique_ptr<DisplayBinding> binding);
+ // Returns an ID for this display. In internal mode this the display::Display
+ // ID. In external mode this hasn't been defined yet.
int64_t GetId() const;
+ // Sets the display::Display corresponding to this ws::Display. This is only
+ // valid in internal window mode.
+ void SetDisplay(const display::Display& display);
+
+ // PlatformDisplayDelegate:
+ const display::Display& GetDisplay() override;
+
DisplayManager* display_manager();
const DisplayManager* display_manager() const;
PlatformDisplay* platform_display() { return platform_display_.get(); }
- // Returns a display::Display corresponding to this ws::Display.
- display::Display ToDisplay() const;
-
// Returns the size of the display in physical pixels.
gfx::Size GetSize() const;
@@ -134,7 +145,11 @@ class Display : public PlatformDisplayDelegate,
// Called just before |tree| is destroyed.
void OnWillDestroyTree(WindowTree* tree);
- void UpdateNativeCursor(mojom::Cursor cursor_id);
+ // Removes |display_root| from internal maps. This called prior to
+ // |display_root| being destroyed.
+ void RemoveWindowManagerDisplayRoot(WindowManagerDisplayRoot* display_root);
+
+ void UpdateNativeCursor(mojom::CursorType cursor_id);
// mojom::WindowTreeHost:
void SetSize(const gfx::Size& size) override;
@@ -167,12 +182,11 @@ class Display : public PlatformDisplayDelegate,
void CreateRootWindow(const gfx::Size& size);
// PlatformDisplayDelegate:
- display::Display GetDisplay() override;
ServerWindow* GetRootWindow() override;
+ EventSink* GetEventSink() override;
void OnAcceleratedWidgetAvailable() override;
- bool IsInHighContrastMode() override;
- void OnEvent(const ui::Event& event) override;
void OnNativeCaptureLost() override;
+ OzonePlatform* GetOzonePlatform() override;
// FocusControllerDelegate:
bool CanHaveActiveChildren(ServerWindow* window) const override;
@@ -191,17 +205,26 @@ class Display : public PlatformDisplayDelegate,
void OnWindowManagerWindowTreeFactoryReady(
WindowManagerWindowTreeFactory* factory) override;
+ // EventSink:
+ EventDispatchDetails OnEventFromSource(Event* event) override;
+
std::unique_ptr<DisplayBinding> binding_;
WindowServer* const window_server_;
std::unique_ptr<ServerWindow> root_;
std::unique_ptr<PlatformDisplay> platform_display_;
std::unique_ptr<FocusController> focus_controller_;
+ // In internal window mode this contains information about the display. In
+ // external window mode this will be invalid.
+ display::Display display_;
+
// The last cursor set. Used to track whether we need to change the cursor.
- mojom::Cursor last_cursor_;
+ mojom::CursorType last_cursor_;
ServerWindowTracker activation_parents_;
+ cc::LocalSurfaceIdAllocator allocator_;
+
WindowManagerDisplayRootMap window_manager_display_root_map_;
DISALLOW_COPY_AND_ASSIGN(Display);
diff --git a/chromium/services/ui/ws/display_binding.cc b/chromium/services/ui/ws/display_binding.cc
index f70c92bf01e..09157038fb0 100644
--- a/chromium/services/ui/ws/display_binding.cc
+++ b/chromium/services/ui/ws/display_binding.cc
@@ -31,7 +31,8 @@ WindowTree* DisplayBindingImpl::CreateWindowTree(ServerWindow* root) {
WindowTree* tree = window_server_->EmbedAtWindow(
root, user_id_, std::move(client_), embed_flags,
base::WrapUnique(new WindowManagerAccessPolicy));
- tree->ConfigureWindowManager();
+ const bool automatically_create_display_roots = true;
+ tree->ConfigureWindowManager(automatically_create_display_roots);
return tree;
}
diff --git a/chromium/services/ui/ws/display_client_compositor_frame_sink.cc b/chromium/services/ui/ws/display_client_compositor_frame_sink.cc
new file mode 100644
index 00000000000..65c0fc90172
--- /dev/null
+++ b/chromium/services/ui/ws/display_client_compositor_frame_sink.cc
@@ -0,0 +1,107 @@
+// 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/ui/ws/display_client_compositor_frame_sink.h"
+
+#include "base/threading/thread_checker.h"
+#include "cc/output/compositor_frame_sink_client.h"
+
+namespace ui {
+namespace ws {
+
+DisplayClientCompositorFrameSink::DisplayClientCompositorFrameSink(
+ const cc::FrameSinkId& frame_sink_id,
+ cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink,
+ cc::mojom::DisplayPrivateAssociatedPtr display_private,
+ cc::mojom::MojoCompositorFrameSinkClientRequest client_request)
+ : cc::CompositorFrameSink(nullptr, nullptr, nullptr, nullptr),
+ compositor_frame_sink_(std::move(compositor_frame_sink)),
+ client_binding_(this, std::move(client_request)),
+ display_private_(std::move(display_private)),
+ frame_sink_id_(frame_sink_id) {}
+
+DisplayClientCompositorFrameSink::~DisplayClientCompositorFrameSink() {}
+
+bool DisplayClientCompositorFrameSink::BindToClient(
+ cc::CompositorFrameSinkClient* client) {
+ if (!cc::CompositorFrameSink::BindToClient(client))
+ return false;
+ DCHECK(!thread_checker_);
+ thread_checker_ = base::MakeUnique<base::ThreadChecker>();
+
+ begin_frame_source_ = base::MakeUnique<cc::ExternalBeginFrameSource>(this);
+
+ client->SetBeginFrameSource(begin_frame_source_.get());
+ return true;
+}
+
+void DisplayClientCompositorFrameSink::DetachFromClient() {
+ client_->SetBeginFrameSource(nullptr);
+ begin_frame_source_.reset();
+ cc::CompositorFrameSink::DetachFromClient();
+}
+
+void DisplayClientCompositorFrameSink::SubmitCompositorFrame(
+ cc::CompositorFrame frame) {
+ DCHECK(thread_checker_->CalledOnValidThread());
+ if (!compositor_frame_sink_)
+ return;
+
+ DCHECK_LE(cc::BeginFrameArgs::kStartingFrameNumber,
+ frame.metadata.begin_frame_ack.sequence_number);
+
+ gfx::Size frame_size = last_submitted_frame_size_;
+ if (!frame.render_pass_list.empty())
+ frame_size = frame.render_pass_list.back()->output_rect.size();
+
+ if (!local_surface_id_.is_valid() ||
+ frame_size != last_submitted_frame_size_) {
+ local_surface_id_ = id_allocator_.GenerateId();
+ display_private_->ResizeDisplay(frame_size);
+ }
+ display_private_->SetLocalSurfaceId(local_surface_id_,
+ frame.metadata.device_scale_factor);
+ compositor_frame_sink_->SubmitCompositorFrame(local_surface_id_,
+ std::move(frame));
+ last_submitted_frame_size_ = frame_size;
+}
+
+void DisplayClientCompositorFrameSink::DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) {
+ DCHECK(thread_checker_->CalledOnValidThread());
+ if (!client_)
+ return;
+ client_->ReclaimResources(resources);
+ client_->DidReceiveCompositorFrameAck();
+}
+
+void DisplayClientCompositorFrameSink::OnBeginFrame(
+ const cc::BeginFrameArgs& begin_frame_args) {
+ DCHECK(thread_checker_->CalledOnValidThread());
+ begin_frame_source_->OnBeginFrame(begin_frame_args);
+}
+
+void DisplayClientCompositorFrameSink::ReclaimResources(
+ const cc::ReturnedResourceArray& resources) {
+ DCHECK(thread_checker_->CalledOnValidThread());
+ if (!client_)
+ return;
+ client_->ReclaimResources(resources);
+}
+
+void DisplayClientCompositorFrameSink::OnNeedsBeginFrames(
+ bool needs_begin_frames) {
+ DCHECK(thread_checker_->CalledOnValidThread());
+ compositor_frame_sink_->SetNeedsBeginFrame(needs_begin_frames);
+}
+
+void DisplayClientCompositorFrameSink::OnDidFinishFrame(
+ const cc::BeginFrameAck& ack) {
+ // If there was damage, the submitted CompositorFrame includes the ack.
+ if (!ack.has_damage)
+ compositor_frame_sink_->BeginFrameDidNotSwap(ack);
+}
+
+} // namespace ws
+} // namespace ui
diff --git a/chromium/services/ui/ws/display_client_compositor_frame_sink.h b/chromium/services/ui/ws/display_client_compositor_frame_sink.h
new file mode 100644
index 00000000000..4a98ad13403
--- /dev/null
+++ b/chromium/services/ui/ws/display_client_compositor_frame_sink.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_UI_WS_DISPLAY_CLIENT_COMPOSITOR_FRAME_SINK_H_
+#define SERVICES_UI_WS_DISPLAY_CLIENT_COMPOSITOR_FRAME_SINK_H_
+
+#include "cc/ipc/frame_sink_manager.mojom.h"
+#include "cc/ipc/mojo_compositor_frame_sink.mojom.h"
+#include "cc/output/compositor_frame_sink.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/surfaces/local_surface_id.h"
+#include "cc/surfaces/local_surface_id_allocator.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace base {
+class ThreadChecker;
+} // namespace base
+
+namespace ui {
+namespace ws {
+
+// DisplayClientCompositorFrameSink submits CompositorFrames to a
+// MojoCompositorFrameSink, with the client's frame being the root surface of
+// the Display.
+class DisplayClientCompositorFrameSink
+ : public cc::CompositorFrameSink,
+ public cc::mojom::MojoCompositorFrameSinkClient,
+ public cc::ExternalBeginFrameSourceClient {
+ public:
+ DisplayClientCompositorFrameSink(
+ const cc::FrameSinkId& frame_sink_id,
+ cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink,
+ cc::mojom::DisplayPrivateAssociatedPtr display_private,
+ cc::mojom::MojoCompositorFrameSinkClientRequest client_request);
+
+ ~DisplayClientCompositorFrameSink() override;
+
+ // cc::CompositorFrameSink implementation:
+ bool BindToClient(cc::CompositorFrameSinkClient* client) override;
+ void DetachFromClient() override;
+ void SubmitCompositorFrame(cc::CompositorFrame frame) override;
+
+ private:
+ // cc::mojom::MojoCompositorFrameSinkClient implementation:
+ void DidReceiveCompositorFrameAck(
+ const cc::ReturnedResourceArray& resources) override;
+ void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) override;
+ void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
+
+ // cc::ExternalBeginFrameSourceClient implementation:
+ void OnNeedsBeginFrames(bool needs_begin_frame) override;
+ void OnDidFinishFrame(const cc::BeginFrameAck& ack) override;
+
+ gfx::Size last_submitted_frame_size_;
+ cc::LocalSurfaceId local_surface_id_;
+ cc::LocalSurfaceIdAllocator id_allocator_;
+ cc::mojom::MojoCompositorFrameSinkClientRequest client_request_;
+ cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink_;
+ mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> client_binding_;
+ cc::mojom::DisplayPrivateAssociatedPtr display_private_;
+ std::unique_ptr<base::ThreadChecker> thread_checker_;
+ std::unique_ptr<cc::ExternalBeginFrameSource> begin_frame_source_;
+ const cc::FrameSinkId frame_sink_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(DisplayClientCompositorFrameSink);
+};
+
+} // namespace ws
+} // namespace ui
+
+#endif // SERVICES_UI_WS_DISPLAY_CLIENT_COMPOSITOR_FRAME_SINK_H_
diff --git a/chromium/services/ui/ws/display_manager.cc b/chromium/services/ui/ws/display_manager.cc
index 2cbaa8ebade..2bde1589308 100644
--- a/chromium/services/ui/ws/display_manager.cc
+++ b/chromium/services/ui/ws/display_manager.cc
@@ -8,11 +8,12 @@
#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
+#include "services/ui/display/viewport_metrics.h"
#include "services/ui/ws/cursor_location_manager.h"
#include "services/ui/ws/display.h"
#include "services/ui/ws/display_binding.h"
#include "services/ui/ws/event_dispatcher.h"
-#include "services/ui/ws/platform_display_init_params.h"
+#include "services/ui/ws/frame_generator.h"
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/user_display_manager.h"
#include "services/ui/ws/user_display_manager_delegate.h"
@@ -21,6 +22,11 @@
#include "services/ui/ws/window_manager_window_tree_factory.h"
#include "services/ui/ws/window_server_delegate.h"
#include "services/ui/ws/window_tree.h"
+#include "ui/events/event_rewriter.h"
+
+#if defined(OS_CHROMEOS)
+#include "ui/chromeos/events/event_rewriter_chromeos.h"
+#endif
namespace ui {
namespace ws {
@@ -33,6 +39,13 @@ DisplayManager::DisplayManager(WindowServer* window_server,
: window_server_(window_server),
user_id_tracker_(user_id_tracker),
next_root_id_(0) {
+#if defined(OS_CHROMEOS)
+ // TODO: http://crbug.com/701468 fix function key preferences and sticky keys.
+ ui::EventRewriterChromeOS::Delegate* delegate = nullptr;
+ ui::EventRewriter* sticky_keys_controller = nullptr;
+ event_rewriter_ = base::MakeUnique<ui::EventRewriterChromeOS>(
+ delegate, sticky_keys_controller);
+#endif
user_id_tracker_->AddObserver(this);
}
@@ -98,9 +111,9 @@ std::set<const Display*> DisplayManager::displays() const {
return ret_value;
}
-void DisplayManager::OnDisplayUpdate(Display* display) {
+void DisplayManager::OnDisplayUpdate(const display::Display& display) {
for (const auto& pair : user_display_managers_)
- pair.second->OnDisplayUpdate(display->ToDisplay());
+ pair.second->OnDisplayUpdate(display);
}
Display* DisplayManager::GetDisplayContaining(const ServerWindow* window) {
@@ -161,9 +174,18 @@ void DisplayManager::OnDisplayAcceleratedWidgetAvailable(Display* display) {
const bool is_first_display = displays_.empty();
displays_.insert(display);
pending_displays_.erase(display);
+ if (event_rewriter_)
+ display->platform_display()->AddEventRewriter(event_rewriter_.get());
window_server_->OnDisplayReady(display, is_first_display);
}
+void DisplayManager::SetHighContrastMode(bool enabled) {
+ for (Display* display : displays_) {
+ display->platform_display()->GetFrameGenerator()->SetHighContrastMode(
+ enabled);
+ }
+}
+
void DisplayManager::OnActiveUserIdChanged(const UserId& previously_active_id,
const UserId& active_id) {
WindowManagerState* previous_window_manager_state =
@@ -181,50 +203,50 @@ void DisplayManager::OnActiveUserIdChanged(const UserId& previously_active_id,
current_window_manager_state->Activate(mouse_location_on_screen);
}
-void DisplayManager::OnDisplayAdded(int64_t id,
+void DisplayManager::OnDisplayAdded(const display::Display& display,
const display::ViewportMetrics& metrics) {
- TRACE_EVENT1("mus-ws", "OnDisplayAdded", "id", id);
- PlatformDisplayInitParams params;
- params.display_id = id;
- params.metrics = metrics;
+ DVLOG(3) << "OnDisplayAdded: " << display.ToString();
- ws::Display* display = new ws::Display(window_server_);
- display->Init(params, nullptr);
+ ws::Display* ws_display = new ws::Display(window_server_);
+ ws_display->SetDisplay(display);
+ ws_display->Init(metrics, nullptr);
}
-void DisplayManager::OnDisplayRemoved(int64_t id) {
- TRACE_EVENT1("mus-ws", "OnDisplayRemoved", "id", id);
- Display* display = GetDisplayById(id);
+void DisplayManager::OnDisplayRemoved(int64_t display_id) {
+ DVLOG(3) << "OnDisplayRemoved: " << display_id;
+ Display* display = GetDisplayById(display_id);
if (display)
DestroyDisplay(display);
}
void DisplayManager::OnDisplayModified(
- int64_t id,
+ const display::Display& display,
const display::ViewportMetrics& metrics) {
- TRACE_EVENT1("mus-ws", "OnDisplayModified", "id", id);
+ DVLOG(3) << "OnDisplayModified: " << display.ToString();
- Display* display = GetDisplayById(id);
- DCHECK(display);
+ Display* ws_display = GetDisplayById(display.id());
+ DCHECK(ws_display);
- // Update the platform display and check if anything has actually changed.
- if (!display->platform_display()->UpdateViewportMetrics(metrics))
- return;
+ // Update the cached display information.
+ ws_display->SetDisplay(display);
- // Send IPCs to WM clients first with new display information.
+ // 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->ToDisplay());
+ factory->window_tree()->OnWmDisplayModified(display);
}
- // Change the root ServerWindow size after sending IPC to WM.
- display->OnViewportMetricsChanged(metrics);
+ // Update the PlatformWindow and ServerWindow size. This must happen after
+ // OnWmDisplayModified() so the WM has updated the display size.
+ ws_display->OnViewportMetricsChanged(metrics);
+
OnDisplayUpdate(display);
}
void DisplayManager::OnPrimaryDisplayChanged(int64_t primary_display_id) {
+ DVLOG(3) << "OnPrimaryDisplayChanged: " << primary_display_id;
// TODO(kylechar): Send IPCs to WM clients first.
// Send IPCs to any DisplayManagerObservers.
diff --git a/chromium/services/ui/ws/display_manager.h b/chromium/services/ui/ws/display_manager.h
index 333ebef89ce..3d2d3700060 100644
--- a/chromium/services/ui/ws/display_manager.h
+++ b/chromium/services/ui/ws/display_manager.h
@@ -14,8 +14,10 @@
#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 ui {
+class EventRewriter;
namespace ws {
class CursorLocationManager;
@@ -27,7 +29,7 @@ class WindowManagerDisplayRoot;
class WindowServer;
// DisplayManager manages the set of Displays. DisplayManager distinguishes
-// between displays that do yet have an accelerated widget (pending), vs
+// between displays that do not yet have an accelerated widget (pending), vs
// those that do.
class DisplayManager : public UserIdTrackerObserver,
public display::ScreenManagerDelegate {
@@ -51,7 +53,7 @@ class DisplayManager : public UserIdTrackerObserver,
std::set<const Display*> displays() const;
// Notifies when something about the Display changes.
- void OnDisplayUpdate(Display* display);
+ void OnDisplayUpdate(const display::Display& display);
// Returns the Display that contains |window|, or null if |window| is not
// attached to a display.
@@ -80,22 +82,28 @@ class DisplayManager : public UserIdTrackerObserver,
// Called when the AcceleratedWidget is available for |display|.
void OnDisplayAcceleratedWidgetAvailable(Display* display);
+ // Switch the high contrast mode of all Displays to |enabled|.
+ void SetHighContrastMode(bool enabled);
+
private:
// UserIdTrackerObserver:
void OnActiveUserIdChanged(const UserId& previously_active_id,
const UserId& active_id) override;
// display::ScreenManagerDelegate:
- void OnDisplayAdded(int64_t id,
+ void OnDisplayAdded(const display::Display& display,
const display::ViewportMetrics& metrics) override;
void OnDisplayRemoved(int64_t id) override;
- void OnDisplayModified(int64_t id,
+ void OnDisplayModified(const display::Display& display,
const display::ViewportMetrics& metrics) override;
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_;
+
// Displays are initially added to |pending_displays_|. When the display is
// initialized it is moved to |displays_|. WindowServer owns the Displays.
std::set<Display*> pending_displays_;
diff --git a/chromium/services/ui/ws/display_unittest.cc b/chromium/services/ui/ws/display_unittest.cc
index 47d9e60aaa9..8a832269a63 100644
--- a/chromium/services/ui/ws/display_unittest.cc
+++ b/chromium/services/ui/ws/display_unittest.cc
@@ -25,11 +25,10 @@
#include "services/ui/ws/window_tree.h"
#include "services/ui/ws/window_tree_binding.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/display/display.h"
#include "ui/events/event.h"
#include "ui/gfx/geometry/rect.h"
-using display::ViewportMetrics;
-
namespace ui {
namespace ws {
namespace test {
@@ -123,7 +122,7 @@ class DisplayTest : public testing::Test {
TEST_F(DisplayTest, CreateDisplay) {
AddWindowManager(window_server(), kTestId1);
const int64_t display_id =
- screen_manager().AddDisplay(MakeViewportMetrics(0, 0, 1024, 768, 1.0f));
+ screen_manager().AddDisplay(MakeDisplay(0, 0, 1024, 768, 1.0f));
ASSERT_EQ(1u, display_manager()->displays().size());
Display* display = display_manager()->GetDisplayById(display_id);
@@ -144,7 +143,7 @@ TEST_F(DisplayTest, CreateDisplay) {
TEST_F(DisplayTest, CreateDisplayBeforeWM) {
// Add one display, no WM exists yet.
const int64_t display_id =
- screen_manager().AddDisplay(MakeViewportMetrics(0, 0, 1024, 768, 1.0f));
+ screen_manager().AddDisplay(MakeDisplay(0, 0, 1024, 768, 1.0f));
EXPECT_EQ(1u, display_manager()->displays().size());
Display* display = display_manager()->GetDisplayById(display_id);
@@ -197,22 +196,28 @@ TEST_F(DisplayTest, CreateDisplayWithTwoWindowManagers) {
TEST_F(DisplayTest, CreateDisplayWithDeviceScaleFactor) {
// The display bounds should be the pixel_size / device_scale_factor.
- const ViewportMetrics metrics = MakeViewportMetrics(0, 0, 1024, 768, 2.0f);
- EXPECT_EQ("0,0 512x384", metrics.bounds.ToString());
- EXPECT_EQ("1024x768", metrics.pixel_size.ToString());
+ display::Display display = MakeDisplay(0, 0, 1024, 768, 2.0f);
+ EXPECT_EQ("0,0 512x384", display.bounds().ToString());
- const int64_t display_id = screen_manager().AddDisplay(metrics);
- Display* display = display_manager()->GetDisplayById(display_id);
+ const int64_t display_id = screen_manager().AddDisplay(display);
+ display.set_id(display_id);
+ Display* ws_display = display_manager()->GetDisplayById(display_id);
// The root ServerWindow bounds should be in PP.
- EXPECT_EQ("0,0 1024x768", display->root_window()->bounds().ToString());
+ EXPECT_EQ("0,0 1024x768", ws_display->root_window()->bounds().ToString());
- ViewportMetrics modified_metrics = metrics;
- modified_metrics.work_area.set_height(metrics.work_area.height() - 48);
- screen_manager().ModifyDisplay(display_id, modified_metrics);
+ // Modify the display work area to be 48 DIPs smaller.
+ display::Display modified_display = display;
+ gfx::Rect modified_work_area = display.work_area();
+ modified_work_area.set_height(modified_work_area.height() - 48);
+ modified_display.set_work_area(modified_work_area);
+ screen_manager().ModifyDisplay(modified_display);
+
+ // The display work area should have changed.
+ EXPECT_EQ("0,0 512x336", ws_display->GetDisplay().work_area().ToString());
// The root ServerWindow should still be in PP after updating the work area.
- EXPECT_EQ("0,0 1024x768", display->root_window()->bounds().ToString());
+ EXPECT_EQ("0,0 1024x768", ws_display->root_window()->bounds().ToString());
}
TEST_F(DisplayTest, Destruction) {
@@ -261,10 +266,12 @@ TEST_F(DisplayTest, EventStateResetOnUserSwitch) {
ASSERT_TRUE(active_wms);
EXPECT_EQ(kTestId1, active_wms->user_id());
- static_cast<PlatformDisplayDelegate*>(display)->OnEvent(ui::PointerEvent(
- 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)));
+ 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());
diff --git a/chromium/services/ui/ws/drag_controller.cc b/chromium/services/ui/ws/drag_controller.cc
index 714b37a25d2..3545ac24aad 100644
--- a/chromium/services/ui/ws/drag_controller.cc
+++ b/chromium/services/ui/ws/drag_controller.cc
@@ -7,7 +7,7 @@
#include <utility>
#include "base/logging.h"
-#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/ws/drag_cursor_updater.h"
#include "services/ui/ws/drag_source.h"
#include "services/ui/ws/drag_target_connection.h"
@@ -52,7 +52,7 @@ DragController::DragController(
cursor_updater_(cursor_updater),
drag_operations_(drag_operations),
drag_pointer_id_(drag_pointer),
- current_cursor_(ui::mojom::Cursor::NO_DROP),
+ current_cursor_(ui::mojom::CursorType::NO_DROP),
source_window_(source_window),
source_connection_(source_connection),
mime_data_(mime_data),
@@ -75,6 +75,8 @@ void DragController::Cancel() {
bool DragController::DispatchPointerEvent(const ui::PointerEvent& event,
ServerWindow* current_target) {
+ DVLOG(2) << "DragController dispatching pointer event at "
+ << event.location().ToString();
uint32_t event_flags =
event.flags() &
(ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN);
@@ -83,11 +85,15 @@ bool DragController::DispatchPointerEvent(const ui::PointerEvent& event,
if (waiting_for_final_drop_response_) {
// If we're waiting on a target window to respond to the final drag drop
// call, don't process any more pointer events.
+ DVLOG(1) << "Ignoring event because we're waiting for final drop response";
return false;
}
- if (event.pointer_details().id != drag_pointer_id_)
+ if (event.pointer_details().id != drag_pointer_id_) {
+ DVLOG(1) << "Ignoring event from different pointer "
+ << event.pointer_details().id;
return false;
+ }
// If |current_target| doesn't accept drags, walk its hierarchy up until we
// find one that does (or set to nullptr at the top of the tree).
@@ -101,6 +107,8 @@ bool DragController::DispatchPointerEvent(const ui::PointerEvent& event,
EnsureWindowObserved(current_target);
}
+ source_->OnDragMoved(screen_position);
+
if (current_target && current_target == current_target_window_ &&
event.type() != ET_POINTER_UP) {
QueueOperation(current_target, OperationType::OVER, event_flags,
@@ -119,6 +127,10 @@ bool DragController::DispatchPointerEvent(const ui::PointerEvent& event,
}
SetCurrentTargetWindow(current_target);
+ } else if (event.type() != ET_POINTER_UP) {
+ DVLOG(1) << "Performing no action for pointer event at "
+ << screen_position.ToString()
+ << "! current_target=" << current_target;
}
if (event.type() == ET_POINTER_UP) {
@@ -143,6 +155,8 @@ void DragController::OnWillDestroyDragTargetConnection(
void DragController::MessageDragCompleted(bool success,
DropEffect action_taken) {
+ DVLOG(1) << "Drag Completed: success=" << success
+ << ", action_taken=" << action_taken;
for (DragTargetConnection* connection : called_on_drag_mime_types_)
connection->PerformOnDragDropDone();
called_on_drag_mime_types_.clear();
@@ -173,12 +187,11 @@ void DragController::SetWindowDropOperations(ServerWindow* window,
}
}
-ui::mojom::Cursor DragController::CursorForEffectBitmask(
+ui::mojom::CursorType DragController::CursorForEffectBitmask(
DropEffectBitmask bitmask) {
DropEffectBitmask combined = bitmask & drag_operations_;
- return combined == ui::mojom::kDropEffectNone
- ? ui::mojom::Cursor::NO_DROP
- : ui::mojom::Cursor::COPY;
+ return combined == ui::mojom::kDropEffectNone ? ui::mojom::CursorType::NO_DROP
+ : ui::mojom::CursorType::COPY;
}
void DragController::SetCurrentTargetWindow(ServerWindow* current_target) {
@@ -191,7 +204,7 @@ void DragController::SetCurrentTargetWindow(ServerWindow* current_target) {
current_cursor_ = CursorForEffectBitmask(state.bitmask);
} else {
// Can't drop in empty areas.
- current_cursor_ = ui::mojom::Cursor::NO_DROP;
+ current_cursor_ = ui::mojom::CursorType::NO_DROP;
}
cursor_updater_->OnDragCursorUpdated();
@@ -212,6 +225,8 @@ void DragController::QueueOperation(ServerWindow* window,
OperationType type,
uint32_t event_flags,
const gfx::Point& screen_position) {
+ DVLOG(2) << "Queueing operation " << ToString(type) << " to " << window;
+
// If this window doesn't have the mime data, send it.
DragTargetConnection* connection = source_->GetDragTargetForWindow(window);
if (connection != source_connection_ &&
@@ -329,5 +344,23 @@ void DragController::OnWindowDestroying(ServerWindow* window) {
}
}
+// static
+std::string DragController::ToString(OperationType type) {
+ switch (type) {
+ case OperationType::NONE:
+ return "NONE";
+ case OperationType::ENTER:
+ return "ENTER";
+ case OperationType::OVER:
+ return "OVER";
+ case OperationType::LEAVE:
+ return "LEAVE";
+ case OperationType::DROP:
+ return "DROP";
+ }
+ NOTREACHED();
+ return std::string();
+}
+
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/drag_controller.h b/chromium/services/ui/ws/drag_controller.h
index cb402829e82..de8ea9af733 100644
--- a/chromium/services/ui/ws/drag_controller.h
+++ b/chromium/services/ui/ws/drag_controller.h
@@ -10,7 +10,7 @@
#include "base/memory/weak_ptr.h"
#include "services/ui/common/types.h"
-#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/ws/ids.h"
#include "services/ui/ws/server_window_observer.h"
@@ -53,7 +53,7 @@ class DragController : public ServerWindowObserver {
DropEffectBitmask drag_operations);
~DragController() override;
- ui::mojom::Cursor current_cursor() const { return current_cursor_; }
+ ui::mojom::CursorType current_cursor() const { return current_cursor_; }
// Cancels the current drag, ie, due to the user pressing Escape.
void Cancel();
@@ -91,7 +91,7 @@ class DragController : public ServerWindowObserver {
// Returns the ui::mojom::Cursor for the window |bitmask|, adjusted for types
// that the drag source allows.
- ui::mojom::Cursor CursorForEffectBitmask(DropEffectBitmask bitmask);
+ ui::mojom::CursorType CursorForEffectBitmask(DropEffectBitmask bitmask);
// Ensure that |window| has an entry in |window_state_| and that we're an
// observer.
@@ -111,6 +111,8 @@ class DragController : public ServerWindowObserver {
// ServerWindowObserver:
void OnWindowDestroying(ServerWindow* window) override;
+ static std::string ToString(OperationType type);
+
// Our owner.
DragSource* source_;
@@ -124,7 +126,7 @@ class DragController : public ServerWindowObserver {
const int32_t drag_pointer_id_;
// The current mouse cursor during the drag.
- ui::mojom::Cursor current_cursor_;
+ ui::mojom::CursorType current_cursor_;
// Sending OnDragOver() to our |source_| destroys us; there is a period where
// we have to continue to exist, but not process any more pointer events.
diff --git a/chromium/services/ui/ws/drag_controller_unittest.cc b/chromium/services/ui/ws/drag_controller_unittest.cc
index d26fdcde0fd..7bc192c0509 100644
--- a/chromium/services/ui/ws/drag_controller_unittest.cc
+++ b/chromium/services/ui/ws/drag_controller_unittest.cc
@@ -10,7 +10,7 @@
#include <utility>
#include "base/memory/ptr_util.h"
-#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/ws/drag_source.h"
#include "services/ui/ws/drag_target_connection.h"
#include "services/ui/ws/ids.h"
@@ -155,14 +155,14 @@ class DragControllerTest : public testing::Test,
window->PerformOnDragDropStart(
std::unordered_map<std::string, std::vector<uint8_t>>());
drag_operation_ = base::MakeUnique<DragController>(
- this, this, window->window(), window, PointerEvent::kMousePointerId,
+ this, this, window->window(), window, MouseEvent::kMousePointerId,
std::unordered_map<std::string, std::vector<uint8_t>>(),
drag_operations);
// It would be nice if we could just let the observer method fire, but it
// fires during the constructor when we haven't assigned the unique_ptr
// yet.
- cursor_ = ui::mojom::Cursor(drag_operation_->current_cursor());
+ cursor_ = ui::mojom::CursorType(drag_operation_->current_cursor());
}
void DispatchDrag(DragTestWindow* window,
@@ -181,9 +181,10 @@ class DragControllerTest : public testing::Test,
bool mouse_released,
uint32_t flags,
const gfx::Point& position) {
- ui::PointerEvent event(ET_POINTER_DOWN, position, position, flags,
- drag_pointer, 0, PointerDetails(),
- base::TimeTicks());
+ ui::PointerEvent event(
+ ET_POINTER_DOWN, position, position, flags, 0,
+ PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE, drag_pointer),
+ base::TimeTicks());
drag_operation_->DispatchPointerEvent(event,
window ? window->window() : nullptr);
}
@@ -203,7 +204,7 @@ class DragControllerTest : public testing::Test,
return drag_completed_value_;
}
- ui::mojom::Cursor cursor() { return cursor_; }
+ ui::mojom::CursorType cursor() { return cursor_; }
private:
// Overridden from testing::Test:
@@ -231,10 +232,12 @@ class DragControllerTest : public testing::Test,
// Overridden from DragCursorUpdater:
void OnDragCursorUpdated() override {
if (drag_operation_)
- cursor_ = ui::mojom::Cursor(drag_operation_->current_cursor());
+ cursor_ = ui::mojom::CursorType(drag_operation_->current_cursor());
}
// Overridden from DragControllerSource:
+ void OnDragMoved(const gfx::Point& location) override {}
+
void OnDragCompleted(bool success, uint32_t action_taken) override {
drag_completed_action_ = action_taken;
drag_completed_value_ = success;
@@ -257,7 +260,7 @@ class DragControllerTest : public testing::Test,
int window_id_ = 3;
- ui::mojom::Cursor cursor_;
+ ui::mojom::CursorType cursor_;
std::map<WindowId, ServerWindow*> server_window_by_id_;
std::map<ServerWindow*, DragTargetConnection*> connection_by_window_;
@@ -279,14 +282,14 @@ TEST_F(DragControllerTest, SimpleDragDrop) {
std::unique_ptr<DragTestWindow> window = BuildWindow();
StartDragOperation(window.get(), ui::mojom::kDropEffectMove);
- EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::NO_DROP, cursor());
DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1));
EXPECT_EQ(QueuedType::ENTER, window->queue_response_type());
window->Respond(true);
// (Even though we're doing a move, the cursor name is COPY.)
- EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::COPY, cursor());
DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2));
EXPECT_EQ(QueuedType::OVER, window->queue_response_type());
@@ -535,7 +538,7 @@ TEST_F(DragControllerTest, TargetWindowClosedResetsCursor) {
std::unique_ptr<DragTestWindow> window1 = BuildWindow();
std::unique_ptr<DragTestWindow> window2 = BuildWindow();
StartDragOperation(window1.get(), ui::mojom::kDropEffectMove);
- EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::NO_DROP, cursor());
// Send some events to |window|.
DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
@@ -545,13 +548,13 @@ TEST_F(DragControllerTest, TargetWindowClosedResetsCursor) {
DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
gfx::Point(1, 1));
window2->Respond(true);
- EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::COPY, cursor());
// Force the destruction of |window.window|.
window2.reset();
// The cursor no loner indicates that it can drop on |window2|.
- EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::NO_DROP, cursor());
}
TEST_F(DragControllerTest, SourceWindowClosedWhileDrag) {
@@ -624,7 +627,7 @@ TEST_F(DragControllerTest, CancelDrag) {
TEST_F(DragControllerTest, IgnoreEventsFromOtherPointers) {
std::unique_ptr<DragTestWindow> window = BuildWindow();
- // This starts the operation with PointerEvent::kMousePointerId.
+ // This starts the operation with MouseEvent::kMousePointerId.
StartDragOperation(window.get(), ui::mojom::kDropEffectMove);
// Ignore events from pointer 5.
@@ -637,20 +640,20 @@ TEST_F(DragControllerTest, RejectingWindowHasProperCursor) {
std::unique_ptr<DragTestWindow> window = BuildWindow();
StartDragOperation(window.get(), ui::mojom::kDropEffectMove);
- EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::NO_DROP, cursor());
DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(1, 1));
EXPECT_EQ(QueuedType::ENTER, window->queue_response_type());
window->Respond(true);
- EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::COPY, cursor());
DispatchDrag(window.get(), false, ui::EF_LEFT_MOUSE_BUTTON, gfx::Point(2, 2));
EXPECT_EQ(QueuedType::OVER, window->queue_response_type());
// At this point, we respond with no available drag actions at this pixel.
window->Respond(false);
- EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::NO_DROP, cursor());
}
TEST_F(DragControllerTest, ResopnseFromOtherWindowDoesntChangeCursor) {
@@ -665,7 +668,7 @@ TEST_F(DragControllerTest, ResopnseFromOtherWindowDoesntChangeCursor) {
DispatchDrag(window2.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
gfx::Point(1, 1));
- EXPECT_EQ(ui::mojom::Cursor::NO_DROP, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::NO_DROP, cursor());
// Now enter |window1|, and respond.
DispatchDrag(window1.get(), false, ui::EF_LEFT_MOUSE_BUTTON,
@@ -673,13 +676,13 @@ TEST_F(DragControllerTest, ResopnseFromOtherWindowDoesntChangeCursor) {
EXPECT_EQ(QueuedType::ENTER, window1->queue_response_type());
window1->Respond(true);
- EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::COPY, cursor());
// Window 2 responding negatively to its queued messages shouldn't change the
// cursor.
window2->Respond(false);
- EXPECT_EQ(ui::mojom::Cursor::COPY, cursor());
+ EXPECT_EQ(ui::mojom::CursorType::COPY, cursor());
}
} // namespace ws
diff --git a/chromium/services/ui/ws/drag_source.h b/chromium/services/ui/ws/drag_source.h
index 81428d04341..050a0ced794 100644
--- a/chromium/services/ui/ws/drag_source.h
+++ b/chromium/services/ui/ws/drag_source.h
@@ -18,6 +18,9 @@ class DragSource {
public:
virtual ~DragSource() {}
+ // Called during a drag operation when the mouse cursor moves.
+ virtual void OnDragMoved(const gfx::Point& location) = 0;
+
// Called when a drag operation is completed. |success| is true when a target
// window signaled the successful completion of the drag, false in all other
// cases where a drag was aborted at any step in the process. |action_taken|
diff --git a/chromium/services/ui/ws/event_dispatcher.cc b/chromium/services/ui/ws/event_dispatcher.cc
index 21deea9ddd2..a4710dfa3d9 100644
--- a/chromium/services/ui/ws/event_dispatcher.cc
+++ b/chromium/services/ui/ws/event_dispatcher.cc
@@ -86,18 +86,18 @@ void EventDispatcher::SetMousePointerScreenLocation(
delegate_->OnMouseCursorLocationChanged(screen_location);
}
-ui::mojom::Cursor EventDispatcher::GetCurrentMouseCursor() const {
+ui::mojom::CursorType EventDispatcher::GetCurrentMouseCursor() const {
if (drag_controller_)
return drag_controller_->current_cursor();
if (!mouse_cursor_source_window_)
- return ui::mojom::Cursor::POINTER;
+ return ui::mojom::CursorType::POINTER;
if (mouse_cursor_in_non_client_area_)
return mouse_cursor_source_window_->non_client_cursor();
const ServerWindow* window = GetWindowForMouseCursor();
- return window ? window->cursor() : ui::mojom::Cursor::POINTER;
+ return window ? window->cursor() : ui::mojom::CursorType::POINTER;
}
bool EventDispatcher::SetCaptureWindow(ServerWindow* window,
@@ -288,8 +288,7 @@ void EventDispatcher::ProcessEvent(const ui::Event& event,
#endif
if (event.IsKeyEvent()) {
const ui::KeyEvent* key_event = event.AsKeyEvent();
- if (event.type() == ui::ET_KEY_PRESSED && !key_event->is_char() &&
- match_phase == AcceleratorMatchPhase::ANY) {
+ if (!key_event->is_char() && match_phase == AcceleratorMatchPhase::ANY) {
Accelerator* pre_target =
FindAccelerator(*key_event, ui::mojom::AcceleratorPhase::PRE_TARGET);
if (pre_target) {
@@ -465,9 +464,9 @@ void EventDispatcher::UpdateTargetForPointer(int32_t pointer_id,
if (event.IsMousePointerEvent()) {
ui::PointerEvent exit_event(
ui::ET_POINTER_EXITED, event.location(), event.root_location(),
- event.flags(), ui::PointerEvent::kMousePointerId,
- 0 /* changed_button_flags */,
- ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE),
+ event.flags(), 0 /* changed_button_flags */,
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_MOUSE,
+ ui::MouseEvent::kMousePointerId),
event.time_stamp());
DispatchToPointerTarget(pointer_targets_[pointer_id], exit_event);
}
@@ -618,8 +617,8 @@ void EventDispatcher::CancelImplicitCaptureExcept(ServerWindow* window,
// TODO(jonross): Track previous location in PointerTarget for sending
// cancels.
ui::PointerEvent event(event_type, gfx::Point(), gfx::Point(), ui::EF_NONE,
- pair.first, 0 /* changed_button_flags */,
- ui::PointerDetails(pointer_type),
+ 0 /* changed_button_flags */,
+ ui::PointerDetails(pointer_type, pair.first),
ui::EventTimeForNow());
DispatchToPointerTarget(pair.second, event);
}
diff --git a/chromium/services/ui/ws/event_dispatcher.h b/chromium/services/ui/ws/event_dispatcher.h
index 02e6fcb1222..5d9c786a794 100644
--- a/chromium/services/ui/ws/event_dispatcher.h
+++ b/chromium/services/ui/ws/event_dispatcher.h
@@ -13,7 +13,7 @@
#include "base/macros.h"
#include "services/ui/common/types.h"
-#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/public/interfaces/window_manager.mojom.h"
#include "services/ui/ws/drag_cursor_updater.h"
#include "services/ui/ws/modal_window_controller.h"
@@ -66,7 +66,7 @@ class EventDispatcher : public ServerWindowObserver, public DragCursorUpdater {
// Returns the cursor for the current target, or POINTER if the mouse is not
// over a valid target.
- ui::mojom::Cursor GetCurrentMouseCursor() const;
+ ui::mojom::CursorType GetCurrentMouseCursor() const;
// |capture_window_| will receive all input. See window_tree.mojom for
// details.
diff --git a/chromium/services/ui/ws/event_dispatcher_unittest.cc b/chromium/services/ui/ws/event_dispatcher_unittest.cc
index 2df37991de7..e6d241bc1ab 100644
--- a/chromium/services/ui/ws/event_dispatcher_unittest.cc
+++ b/chromium/services/ui/ws/event_dispatcher_unittest.cc
@@ -798,7 +798,8 @@ TEST_F(EventDispatcherTest, DontFocusOnSecondDown) {
// Press (with a different pointer id) on child2. Event should go to child2,
// but focus should not change.
const ui::PointerEvent touch_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(53, 54), 2, base::TimeTicks()));
+ ui::ET_TOUCH_PRESSED, gfx::Point(53, 54), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 2)));
dispatcher->ProcessEvent(touch_event,
EventDispatcher::AcceleratorMatchPhase::ANY);
details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
@@ -821,7 +822,8 @@ TEST_F(EventDispatcherTest, TwoPointersActive) {
// Press on child1.
const ui::PointerEvent touch_event1(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks()));
+ ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
dispatcher->ProcessEvent(touch_event1,
EventDispatcher::AcceleratorMatchPhase::ANY);
std::unique_ptr<DispatchedEventDetails> details =
@@ -830,7 +832,8 @@ TEST_F(EventDispatcherTest, TwoPointersActive) {
// Drag over child2, child1 should get the drag.
const ui::PointerEvent drag_event1(ui::TouchEvent(
- ui::ET_TOUCH_MOVED, gfx::Point(53, 54), 1, base::TimeTicks()));
+ ui::ET_TOUCH_MOVED, gfx::Point(53, 54), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
dispatcher->ProcessEvent(drag_event1,
EventDispatcher::AcceleratorMatchPhase::ANY);
details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
@@ -838,7 +841,8 @@ TEST_F(EventDispatcherTest, TwoPointersActive) {
// Press on child2 with a different touch id.
const ui::PointerEvent touch_event2(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(54, 55), 2, base::TimeTicks()));
+ ui::ET_TOUCH_PRESSED, gfx::Point(54, 55), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 2)));
dispatcher->ProcessEvent(touch_event2,
EventDispatcher::AcceleratorMatchPhase::ANY);
details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
@@ -846,7 +850,8 @@ TEST_F(EventDispatcherTest, TwoPointersActive) {
// Drag over child1 with id 2, child2 should continue to get the drag.
const ui::PointerEvent drag_event2(ui::TouchEvent(
- ui::ET_TOUCH_MOVED, gfx::Point(13, 14), 2, base::TimeTicks()));
+ ui::ET_TOUCH_MOVED, gfx::Point(13, 14), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 2)));
dispatcher->ProcessEvent(drag_event2,
EventDispatcher::AcceleratorMatchPhase::ANY);
details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
@@ -860,13 +865,15 @@ TEST_F(EventDispatcherTest, TwoPointersActive) {
// Release touch id 1, and click on 2. 2 should get it.
const ui::PointerEvent touch_release(ui::TouchEvent(
- ui::ET_TOUCH_RELEASED, gfx::Point(54, 55), 1, base::TimeTicks()));
+ ui::ET_TOUCH_RELEASED, gfx::Point(54, 55), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
dispatcher->ProcessEvent(touch_release,
EventDispatcher::AcceleratorMatchPhase::ANY);
details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
EXPECT_EQ(child1.get(), details->window);
const ui::PointerEvent touch_event3(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(54, 55), 2, base::TimeTicks()));
+ ui::ET_TOUCH_PRESSED, gfx::Point(54, 55), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 2)));
dispatcher->ProcessEvent(touch_event3,
EventDispatcher::AcceleratorMatchPhase::ANY);
details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
@@ -885,7 +892,8 @@ TEST_F(EventDispatcherTest, DestroyWindowWhileGettingEvents) {
// Press on child.
const ui::PointerEvent touch_event1(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks()));
+ ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
dispatcher->ProcessEvent(touch_event1,
EventDispatcher::AcceleratorMatchPhase::ANY);
std::unique_ptr<DispatchedEventDetails> details =
@@ -897,7 +905,8 @@ TEST_F(EventDispatcherTest, DestroyWindowWhileGettingEvents) {
child.reset();
const ui::PointerEvent drag_event1(ui::TouchEvent(
- ui::ET_TOUCH_MOVED, gfx::Point(53, 54), 1, base::TimeTicks()));
+ ui::ET_TOUCH_MOVED, gfx::Point(53, 54), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
dispatcher->ProcessEvent(drag_event1,
EventDispatcher::AcceleratorMatchPhase::ANY);
details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
@@ -1039,7 +1048,8 @@ TEST_F(EventDispatcherTest, SetExplicitCapture) {
// Touch Event while mouse is down should not affect state.
const ui::PointerEvent touch_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(15, 15), 2, base::TimeTicks()));
+ ui::ET_TOUCH_PRESSED, gfx::Point(15, 15), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 2)));
dispatcher->ProcessEvent(touch_event,
EventDispatcher::AcceleratorMatchPhase::ANY);
details = event_dispatcher_delegate->GetAndAdvanceDispatchedEventDetails();
@@ -1130,7 +1140,8 @@ TEST_F(EventDispatcherTest, ExplicitCaptureOverridesImplicitCapture) {
// Add a second pointer target to the child.
{
const ui::PointerEvent touch_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks()));
+ ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
dispatcher->ProcessEvent(touch_event,
EventDispatcher::AcceleratorMatchPhase::ANY);
}
@@ -1195,7 +1206,8 @@ TEST_F(EventDispatcherTest, CaptureUpdatesActivePointerTargets) {
}
{
const ui::PointerEvent touch_event(ui::TouchEvent(
- ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), 1, base::TimeTicks()));
+ ui::ET_TOUCH_PRESSED, gfx::Point(12, 13), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
dispatcher->ProcessEvent(touch_event,
EventDispatcher::AcceleratorMatchPhase::ANY);
}
@@ -1306,9 +1318,10 @@ TEST_F(EventDispatcherTest, ProcessPointerEvents) {
{
const int touch_id = 3;
- const ui::PointerEvent pointer_event(
- ui::TouchEvent(ui::ET_TOUCH_RELEASED, gfx::Point(25, 20), touch_id,
- base::TimeTicks()));
+ const ui::PointerEvent pointer_event(ui::TouchEvent(
+ ui::ET_TOUCH_RELEASED, gfx::Point(25, 20), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH,
+ touch_id)));
event_dispatcher()->ProcessEvent(
pointer_event, EventDispatcher::AcceleratorMatchPhase::ANY);
@@ -1375,7 +1388,7 @@ TEST_F(EventDispatcherTest, ModalWindowEventOnModalParent) {
w2->SetBounds(gfx::Rect(50, 10, 10, 10));
w1->AddTransientWindow(w2.get());
- w2->SetModal();
+ w2->SetModalType(MODAL_TYPE_WINDOW);
// Send event that is over |w1|.
const ui::PointerEvent mouse_pressed(ui::MouseEvent(
@@ -1408,7 +1421,7 @@ TEST_F(EventDispatcherTest, ModalWindowEventOnModalChild) {
w2->SetBounds(gfx::Rect(50, 10, 10, 10));
w1->AddTransientWindow(w2.get());
- w2->SetModal();
+ w2->SetModalType(MODAL_TYPE_WINDOW);
// Send event that is over |w2|.
const ui::PointerEvent mouse_pressed(ui::MouseEvent(
@@ -1444,7 +1457,7 @@ TEST_F(EventDispatcherTest, ModalWindowEventOnUnrelatedWindow) {
w3->SetBounds(gfx::Rect(70, 10, 10, 10));
w1->AddTransientWindow(w2.get());
- w2->SetModal();
+ w2->SetModalType(MODAL_TYPE_WINDOW);
// Send event that is over |w3|.
const ui::PointerEvent mouse_pressed(ui::MouseEvent(
@@ -1481,7 +1494,7 @@ TEST_F(EventDispatcherTest, ModalWindowEventOnDescendantOfModalParent) {
w2->SetBounds(gfx::Rect(50, 10, 10, 10));
w1->AddTransientWindow(w2.get());
- w2->SetModal();
+ w2->SetModalType(MODAL_TYPE_WINDOW);
// Send event that is over |w11|.
const ui::PointerEvent mouse_pressed(ui::MouseEvent(
@@ -1510,7 +1523,7 @@ TEST_F(EventDispatcherTest, ModalWindowEventOnSystemModal) {
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w1->SetModal();
+ w1->SetModalType(MODAL_TYPE_SYSTEM);
// Send event that is over |w1|.
const ui::PointerEvent mouse_pressed(ui::MouseEvent(
@@ -1539,7 +1552,7 @@ TEST_F(EventDispatcherTest, ModalWindowEventOutsideSystemModal) {
root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
w1->SetBounds(gfx::Rect(10, 10, 30, 30));
- w1->SetModal();
+ w1->SetModalType(MODAL_TYPE_SYSTEM);
event_dispatcher()->AddSystemModalWindow(w1.get());
// Send event that is over |w1|.
@@ -1563,6 +1576,55 @@ TEST_F(EventDispatcherTest, ModalWindowEventOutsideSystemModal) {
EXPECT_EQ(gfx::Point(35, 5), dispatched_event->location());
}
+// Tests events on a sub-window of system modal window target the window itself.
+TEST_F(EventDispatcherTest, ModalWindowEventSubWindowSystemModal) {
+ std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(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));
+
+ root_window()->SetBounds(gfx::Rect(0, 0, 100, 100));
+ w1->SetBounds(gfx::Rect(10, 10, 30, 30));
+ w2->SetBounds(gfx::Rect(10, 10, 10, 10));
+ w3->SetBounds(gfx::Rect(50, 10, 10, 10));
+
+ struct {
+ gfx::Point location;
+ ServerWindow* expected_target;
+ } kTouchData[] = {
+ // Touch on |w1| should go to |w1|.
+ {gfx::Point(11, 11), w1.get()},
+ // Touch on |w2| should go to |w2|.
+ {gfx::Point(25, 25), w2.get()},
+ // Touch on |w3| should go to |w1|.
+ {gfx::Point(11, 31), w1.get()},
+ };
+
+ for (size_t i = 0; i < arraysize(kTouchData); i++) {
+ // Send touch press and check that the expected target receives it.
+ event_dispatcher()->ProcessEvent(
+ ui::PointerEvent(ui::TouchEvent(
+ ui::ET_TOUCH_PRESSED, kTouchData[i].location, base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0))),
+ EventDispatcher::AcceleratorMatchPhase::ANY);
+ std::unique_ptr<DispatchedEventDetails> details =
+ test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
+ ASSERT_TRUE(details) << " details is nullptr " << i;
+ EXPECT_EQ(kTouchData[i].expected_target, details->window);
+
+ // Release touch.
+ event_dispatcher()->ProcessEvent(
+ ui::PointerEvent(ui::TouchEvent(
+ ui::ET_TOUCH_RELEASED, kTouchData[i].location, base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 0))),
+ EventDispatcher::AcceleratorMatchPhase::ANY);
+ test_event_dispatcher_delegate()->GetAndAdvanceDispatchedEventDetails();
+ }
+}
+
// Tests that setting capture to a descendant of a modal parent fails.
TEST_F(EventDispatcherTest, ModalWindowSetCaptureDescendantOfModalParent) {
std::unique_ptr<ServerWindow> w1 = CreateChildWindow(WindowId(1, 3));
@@ -1576,7 +1638,7 @@ TEST_F(EventDispatcherTest, ModalWindowSetCaptureDescendantOfModalParent) {
w2->SetBounds(gfx::Rect(50, 10, 10, 10));
w1->AddTransientWindow(w2.get());
- w2->SetModal();
+ w2->SetModalType(MODAL_TYPE_WINDOW);
EXPECT_FALSE(event_dispatcher()->SetCaptureWindow(w11.get(), kClientAreaId));
EXPECT_EQ(nullptr, event_dispatcher()->capture_window());
@@ -1594,7 +1656,7 @@ TEST_F(EventDispatcherTest, ModalWindowSetCaptureUnrelatedWindow) {
w3->SetBounds(gfx::Rect(70, 10, 10, 10));
w1->AddTransientWindow(w2.get());
- w2->SetModal();
+ w2->SetModalType(MODAL_TYPE_WINDOW);
EXPECT_TRUE(event_dispatcher()->SetCaptureWindow(w3.get(), kClientAreaId));
EXPECT_EQ(w3.get(), event_dispatcher()->capture_window());
diff --git a/chromium/services/ui/ws/event_matcher.cc b/chromium/services/ui/ws/event_matcher.cc
index 1cd91568adf..131e974fe97 100644
--- a/chromium/services/ui/ws/event_matcher.cc
+++ b/chromium/services/ui/ws/event_matcher.cc
@@ -76,7 +76,9 @@ EventMatcher::~EventMatcher() {}
bool EventMatcher::MatchesEvent(const ui::Event& event) const {
if ((fields_to_match_ & TYPE) && event.type() != event_type_)
return false;
- int flags = event.flags() & ~ignore_event_flags_;
+ // Synthetic flags should never be matched against.
+ constexpr int kSyntheticFlags = EF_IS_SYNTHESIZED | EF_IS_REPEAT;
+ int flags = event.flags() & ~(ignore_event_flags_ | kSyntheticFlags);
if ((fields_to_match_ & FLAGS) && flags != event_flags_)
return false;
if (fields_to_match_ & KEYBOARD_CODE) {
diff --git a/chromium/services/ui/ws/event_matcher_unittest.cc b/chromium/services/ui/ws/event_matcher_unittest.cc
index a340f9383b8..29db65b5a50 100644
--- a/chromium/services/ui/ws/event_matcher_unittest.cc
+++ b/chromium/services/ui/ws/event_matcher_unittest.cc
@@ -26,12 +26,14 @@ TEST_F(EventTesterTest, MatchesEventByType) {
matcher->type_matcher->type = ui::mojom::EventType::POINTER_DOWN;
EventMatcher pointer_down_matcher(*matcher);
- ui::PointerEvent pointer_down(
- ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(), 1, base::TimeTicks()));
+ ui::PointerEvent pointer_down(ui::TouchEvent(
+ ui::ET_TOUCH_PRESSED, gfx::Point(), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
EXPECT_TRUE(pointer_down_matcher.MatchesEvent(pointer_down));
ui::PointerEvent pointer_up(ui::TouchEvent(
- ui::ET_TOUCH_RELEASED, gfx::Point(), 1, base::TimeTicks()));
+ ui::ET_TOUCH_RELEASED, gfx::Point(), base::TimeTicks(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
EXPECT_FALSE(pointer_down_matcher.MatchesEvent(pointer_up));
}
diff --git a/chromium/services/ui/ws/frame_generator.cc b/chromium/services/ui/ws/frame_generator.cc
index b1574c4309a..9f6c0fe893d 100644
--- a/chromium/services/ui/ws/frame_generator.cc
+++ b/chromium/services/ui/ws/frame_generator.cc
@@ -7,44 +7,40 @@
#include <utility>
#include <vector>
-#include "base/containers/adapters.h"
#include "cc/output/compositor_frame.h"
+#include "cc/output/compositor_frame_sink.h"
#include "cc/quads/render_pass.h"
#include "cc/quads/render_pass_draw_quad.h"
#include "cc/quads/shared_quad_state.h"
#include "cc/quads/surface_draw_quad.h"
-#include "services/ui/ws/frame_generator_delegate.h"
-#include "services/ui/ws/server_window.h"
-#include "services/ui/ws/server_window_compositor_frame_sink_manager.h"
-#include "services/ui/ws/server_window_delegate.h"
namespace ui {
namespace ws {
-FrameGenerator::FrameGenerator(FrameGeneratorDelegate* delegate,
- ServerWindow* root_window,
- gfx::AcceleratedWidget widget)
- : delegate_(delegate), root_window_(root_window), binding_(this) {
- DCHECK(delegate_);
- DCHECK_NE(gfx::kNullAcceleratedWidget, widget);
- cc::mojom::MojoCompositorFrameSinkAssociatedRequest sink_request =
- mojo::MakeRequest(&compositor_frame_sink_);
- cc::mojom::DisplayPrivateAssociatedRequest display_request =
- mojo::MakeRequest(&display_private_);
- root_window_->CreateRootCompositorFrameSink(
- widget, std::move(sink_request), binding_.CreateInterfacePtrAndBind(),
- std::move(display_request));
+FrameGenerator::FrameGenerator(
+ std::unique_ptr<cc::CompositorFrameSink> compositor_frame_sink)
+ : compositor_frame_sink_(std::move(compositor_frame_sink)) {
+ compositor_frame_sink_->BindToClient(this);
}
-FrameGenerator::~FrameGenerator() = default;
+FrameGenerator::~FrameGenerator() {
+ compositor_frame_sink_->DetachFromClient();
+}
void FrameGenerator::SetDeviceScaleFactor(float device_scale_factor) {
if (device_scale_factor_ == device_scale_factor)
return;
device_scale_factor_ = device_scale_factor;
- if (window_manager_surface_info_.is_valid())
- compositor_frame_sink_->SetNeedsBeginFrame(true);
+ SetNeedsBeginFrame(true);
+}
+
+void FrameGenerator::SetHighContrastMode(bool enabled) {
+ if (high_contrast_mode_enabled_ == enabled)
+ return;
+
+ high_contrast_mode_enabled_ = enabled;
+ SetNeedsBeginFrame(true);
}
void FrameGenerator::OnSurfaceCreated(const cc::SurfaceInfo& surface_info) {
@@ -54,39 +50,30 @@ void FrameGenerator::OnSurfaceCreated(const cc::SurfaceInfo& surface_info) {
// changing is handled immediately after the CompositorFrame is submitted.
if (surface_info != window_manager_surface_info_) {
window_manager_surface_info_ = surface_info;
- compositor_frame_sink_->SetNeedsBeginFrame(true);
+ SetNeedsBeginFrame(true);
}
}
void FrameGenerator::OnWindowDamaged() {
- if (window_manager_surface_info_.is_valid())
- compositor_frame_sink_->SetNeedsBeginFrame(true);
+ SetNeedsBeginFrame(true);
}
-void FrameGenerator::DidReceiveCompositorFrameAck() {}
-
-void FrameGenerator::OnBeginFrame(const cc::BeginFrameArgs& begin_frame_arags) {
- if (!root_window_->visible())
+void FrameGenerator::OnWindowSizeChanged(const gfx::Size& pixel_size) {
+ if (pixel_size_ == pixel_size)
return;
- // TODO(fsamuel): We should add a trace for generating a top level frame.
- cc::CompositorFrame frame(GenerateCompositorFrame(root_window_->bounds()));
+ pixel_size_ = pixel_size;
+ SetNeedsBeginFrame(true);
+}
- gfx::Size frame_size = last_submitted_frame_size_;
- if (!frame.render_pass_list.empty())
- frame_size = frame.render_pass_list.back()->output_rect.size();
+void FrameGenerator::SetBeginFrameSource(cc::BeginFrameSource* source) {
+ if (begin_frame_source_ && observing_begin_frames_)
+ begin_frame_source_->RemoveObserver(this);
- if (!local_surface_id_.is_valid() ||
- frame_size != last_submitted_frame_size_) {
- local_surface_id_ = id_allocator_.GenerateId();
- display_private_->ResizeDisplay(frame_size);
- }
+ begin_frame_source_ = source;
- display_private_->SetLocalSurfaceId(local_surface_id_, device_scale_factor_);
- compositor_frame_sink_->SubmitCompositorFrame(local_surface_id_,
- std::move(frame));
- compositor_frame_sink_->SetNeedsBeginFrame(false);
- last_submitted_frame_size_ = frame_size;
+ if (begin_frame_source_ && observing_begin_frames_)
+ begin_frame_source_->AddObserver(this);
}
void FrameGenerator::ReclaimResources(
@@ -96,43 +83,81 @@ void FrameGenerator::ReclaimResources(
DCHECK(resources.empty());
}
-void FrameGenerator::WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) {
- // TODO(fsamuel, staraz): Implement this.
+void FrameGenerator::SetTreeActivationCallback(const base::Closure& callback) {}
+
+void FrameGenerator::DidReceiveCompositorFrameAck() {}
+
+void FrameGenerator::DidLoseCompositorFrameSink() {}
+
+void FrameGenerator::OnDraw(const gfx::Transform& transform,
+ const gfx::Rect& viewport,
+ bool resourceless_software_draw) {}
+
+void FrameGenerator::SetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) {}
+
+void FrameGenerator::SetExternalTilePriorityConstraints(
+ const gfx::Rect& viewport_rect,
+ const gfx::Transform& transform) {}
+
+void FrameGenerator::OnBeginFrame(const cc::BeginFrameArgs& begin_frame_args) {
+ current_begin_frame_ack_ = cc::BeginFrameAck(
+ begin_frame_args.source_id, begin_frame_args.sequence_number,
+ begin_frame_args.sequence_number, false);
+ if (begin_frame_args.type == cc::BeginFrameArgs::MISSED) {
+ begin_frame_source_->DidFinishFrame(this, current_begin_frame_ack_);
+ return;
+ }
+
+ current_begin_frame_ack_.has_damage = true;
+ last_begin_frame_args_ = begin_frame_args;
+
+ // TODO(fsamuel): We should add a trace for generating a top level frame.
+ cc::CompositorFrame frame(GenerateCompositorFrame());
+
+ compositor_frame_sink_->SubmitCompositorFrame(std::move(frame));
+
+ begin_frame_source_->DidFinishFrame(this, current_begin_frame_ack_);
+ SetNeedsBeginFrame(false);
}
-cc::CompositorFrame FrameGenerator::GenerateCompositorFrame(
- const gfx::Rect& output_rect) {
+const cc::BeginFrameArgs& FrameGenerator::LastUsedBeginFrameArgs() const {
+ return last_begin_frame_args_;
+}
+
+void FrameGenerator::OnBeginFrameSourcePausedChanged(bool paused) {}
+
+cc::CompositorFrame FrameGenerator::GenerateCompositorFrame() {
const int render_pass_id = 1;
+ const gfx::Rect bounds(pixel_size_);
std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
- render_pass->SetNew(render_pass_id, output_rect, output_rect,
- gfx::Transform());
+ render_pass->SetNew(render_pass_id, bounds, bounds, gfx::Transform());
DrawWindow(render_pass.get());
cc::CompositorFrame frame;
frame.render_pass_list.push_back(std::move(render_pass));
- if (delegate_->IsInHighContrastMode()) {
+ if (high_contrast_mode_enabled_) {
std::unique_ptr<cc::RenderPass> invert_pass = cc::RenderPass::Create();
- invert_pass->SetNew(2, output_rect, output_rect, gfx::Transform());
+ invert_pass->SetNew(2, bounds, bounds, gfx::Transform());
cc::SharedQuadState* shared_state =
invert_pass->CreateAndAppendSharedQuadState();
gfx::Size scaled_bounds = gfx::ScaleToCeiledSize(
- output_rect.size(), window_manager_surface_info_.device_scale_factor(),
+ pixel_size_, window_manager_surface_info_.device_scale_factor(),
window_manager_surface_info_.device_scale_factor());
- shared_state->SetAll(gfx::Transform(), scaled_bounds, output_rect,
- output_rect, false, 1.f, SkBlendMode::kSrcOver, 0);
+ shared_state->SetAll(gfx::Transform(), scaled_bounds, bounds, bounds, false,
+ 1.f, SkBlendMode::kSrcOver, 0);
auto* quad = invert_pass->CreateAndAppendDrawQuad<cc::RenderPassDrawQuad>();
- render_pass->filters.Append(cc::FilterOperation::CreateInvertFilter(1.f));
- quad->SetNew(shared_state, output_rect, output_rect, render_pass_id,
- 0 /* mask_resource_id */, gfx::RectF() /* mask_uv_rect */,
- gfx::Size() /* mask_texture_size */,
- gfx::Vector2dF() /* filters_scale */,
- gfx::PointF() /* filters_origin */,
- gfx::RectF() /* tex_coord_rect */);
+ frame.render_pass_list.back()->filters.Append(
+ cc::FilterOperation::CreateInvertFilter(1.f));
+ quad->SetNew(
+ shared_state, bounds, bounds, render_pass_id, 0 /* mask_resource_id */,
+ gfx::RectF() /* mask_uv_rect */, gfx::Size() /* mask_texture_size */,
+ gfx::Vector2dF() /* filters_scale */,
+ gfx::PointF() /* filters_origin */, gfx::RectF() /* tex_coord_rect */);
frame.render_pass_list.push_back(std::move(invert_pass));
}
frame.metadata.device_scale_factor = device_scale_factor_;
+ frame.metadata.begin_frame_ack = current_begin_frame_ack_;
if (window_manager_surface_info_.is_valid()) {
frame.metadata.referenced_surfaces.push_back(
@@ -173,6 +198,18 @@ void FrameGenerator::DrawWindow(cc::RenderPass* pass) {
cc::SurfaceDrawQuadType::PRIMARY, nullptr);
}
+void FrameGenerator::SetNeedsBeginFrame(bool needs_begin_frame) {
+ needs_begin_frame &= window_manager_surface_info_.is_valid();
+ if (needs_begin_frame == observing_begin_frames_)
+ return;
+
+ observing_begin_frames_ = needs_begin_frame;
+ if (needs_begin_frame)
+ begin_frame_source_->AddObserver(this);
+ else
+ begin_frame_source_->RemoveObserver(this);
+}
+
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/frame_generator.h b/chromium/services/ui/ws/frame_generator.h
index 4372581d5c4..5d6666e7913 100644
--- a/chromium/services/ui/ws/frame_generator.h
+++ b/chromium/services/ui/ws/frame_generator.h
@@ -8,80 +8,82 @@
#include <memory>
#include "base/macros.h"
-#include "base/timer/timer.h"
-#include "cc/ipc/display_compositor.mojom.h"
-#include "cc/surfaces/frame_sink_id.h"
-#include "cc/surfaces/local_surface_id_allocator.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/compositor_frame_sink_client.h"
+#include "cc/scheduler/begin_frame_source.h"
#include "cc/surfaces/surface_id.h"
-#include "cc/surfaces/surface_reference.h"
-#include "services/ui/public/interfaces/window_tree_constants.mojom.h"
-#include "services/ui/ws/ids.h"
-#include "services/ui/ws/server_window_delegate.h"
-#include "services/ui/ws/server_window_tracker.h"
+#include "cc/surfaces/surface_info.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/native_widget_types.h"
namespace cc {
+class CompositorFrameSink;
class RenderPass;
}
namespace ui {
namespace ws {
-namespace test {
-class FrameGeneratorTest;
-}
-
-class FrameGeneratorDelegate;
-class ServerWindow;
-
// Responsible for redrawing the display in response to the redraw requests by
// submitting CompositorFrames to the owned CompositorFrameSink.
-class FrameGenerator : public cc::mojom::MojoCompositorFrameSinkClient {
+class FrameGenerator : public cc::CompositorFrameSinkClient,
+ public cc::BeginFrameObserver {
public:
- FrameGenerator(FrameGeneratorDelegate* delegate,
- ServerWindow* root_window,
- gfx::AcceleratedWidget widget);
+ explicit FrameGenerator(
+ std::unique_ptr<cc::CompositorFrameSink> compositor_frame_sink);
~FrameGenerator() override;
void SetDeviceScaleFactor(float device_scale_factor);
+ void SetHighContrastMode(bool enabled);
// Updates the WindowManager's SurfaceInfo.
void OnSurfaceCreated(const cc::SurfaceInfo& surface_info);
void OnWindowDamaged();
+ void OnWindowSizeChanged(const gfx::Size& pixel_size);
private:
- friend class ui::ws::test::FrameGeneratorTest;
-
- // cc::mojom::MojoCompositorFrameSinkClient implementation:
- void DidReceiveCompositorFrameAck() override;
- void OnBeginFrame(const cc::BeginFrameArgs& begin_frame_arags) override;
+ // cc::CompositorFrameSinkClient implementation:
+ void SetBeginFrameSource(cc::BeginFrameSource* source) override;
void ReclaimResources(const cc::ReturnedResourceArray& resources) override;
- void WillDrawSurface(const cc::LocalSurfaceId& local_surface_id,
- const gfx::Rect& damage_rect) override;
+ void SetTreeActivationCallback(const base::Closure& callback) override;
+ void DidReceiveCompositorFrameAck() override;
+ void DidLoseCompositorFrameSink() override;
+ void OnDraw(const gfx::Transform& transform,
+ const gfx::Rect& viewport,
+ bool resourceless_software_draw) override;
+ void SetMemoryPolicy(const cc::ManagedMemoryPolicy& policy) override;
+ void SetExternalTilePriorityConstraints(
+ const gfx::Rect& viewport_rect,
+ const gfx::Transform& transform) override;
+
+ // cc::BeginFrameObserver implementation:
+ void OnBeginFrame(const cc::BeginFrameArgs& args) override;
+ const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override;
+ void OnBeginFrameSourcePausedChanged(bool paused) override;
// Generates the CompositorFrame.
- cc::CompositorFrame GenerateCompositorFrame(const gfx::Rect& output_rect);
+ cc::CompositorFrame GenerateCompositorFrame();
// DrawWindow creates SurfaceDrawQuad for the window manager and appends it to
// the provided cc::RenderPass.
void DrawWindow(cc::RenderPass* pass);
- FrameGeneratorDelegate* delegate_;
- ServerWindow* const root_window_;
+ // SetNeedsBeginFrame sets observing_begin_frames_ and add/remove
+ // FrameGenerator as an observer to/from begin_frame_source_ accordingly.
+ void SetNeedsBeginFrame(bool needs_begin_frame);
+
float device_scale_factor_ = 1.f;
+ gfx::Size pixel_size_;
- gfx::Size last_submitted_frame_size_;
- cc::LocalSurfaceId local_surface_id_;
- cc::LocalSurfaceIdAllocator id_allocator_;
- cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink_;
- cc::mojom::DisplayPrivateAssociatedPtr display_private_;
+ std::unique_ptr<cc::CompositorFrameSink> compositor_frame_sink_;
+ cc::BeginFrameArgs last_begin_frame_args_;
+ cc::BeginFrameAck current_begin_frame_ack_;
+ cc::BeginFrameSource* begin_frame_source_ = nullptr;
+ bool observing_begin_frames_ = false;
+ bool high_contrast_mode_enabled_ = false;
cc::SurfaceInfo window_manager_surface_info_;
- mojo::Binding<cc::mojom::MojoCompositorFrameSinkClient> binding_;
-
DISALLOW_COPY_AND_ASSIGN(FrameGenerator);
};
diff --git a/chromium/services/ui/ws/frame_generator_delegate.h b/chromium/services/ui/ws/frame_generator_delegate.h
deleted file mode 100644
index 03fbcd043ea..00000000000
--- a/chromium/services/ui/ws/frame_generator_delegate.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_FRAME_GENERATOR_DELEGATE_H_
-#define SERVICES_UI_WS_FRAME_GENERATOR_DELEGATE_H_
-
-namespace ui {
-namespace ws {
-
-class FrameGeneratorDelegate {
- public:
- virtual bool IsInHighContrastMode() = 0;
-
- protected:
- virtual ~FrameGeneratorDelegate() {}
-};
-
-} // namespace ws
-} // namespace ui
-
-#endif // SERVICES_UI_WS_FRAME_GENERATOR_DELEGATE_H_
diff --git a/chromium/services/ui/ws/frame_generator_unittest.cc b/chromium/services/ui/ws/frame_generator_unittest.cc
new file mode 100644
index 00000000000..0e2f2b40ec3
--- /dev/null
+++ b/chromium/services/ui/ws/frame_generator_unittest.cc
@@ -0,0 +1,352 @@
+// 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/ui/ws/frame_generator.h"
+
+#include "base/macros.h"
+#include "cc/output/compositor_frame_sink.h"
+#include "cc/scheduler/begin_frame_source.h"
+#include "cc/test/begin_frame_args_test.cc"
+#include "cc/test/fake_external_begin_frame_source.h"
+#include "services/ui/ws/server_window.h"
+#include "services/ui/ws/server_window_delegate.h"
+#include "services/ui/ws/test_utils.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+namespace ws {
+namespace test {
+
+// TestServerWindowDelegate implements ServerWindowDelegate and returns nullptrs
+// when either of the methods from the interface is called.
+class TestServerWindowDelegate : public ServerWindowDelegate {
+ public:
+ TestServerWindowDelegate() {}
+ ~TestServerWindowDelegate() override {}
+
+ // ServerWindowDelegate implementation:
+ cc::mojom::FrameSinkManager* GetFrameSinkManager() override {
+ return nullptr;
+ }
+
+ ServerWindow* GetRootWindow(const ServerWindow* window) override {
+ return nullptr;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestServerWindowDelegate);
+};
+
+// FakeCompositorFrameSink observes a FakeExternalBeginFrameSource and receives
+// CompositorFrames from a FrameGenerator.
+class FakeCompositorFrameSink : public cc::CompositorFrameSink,
+ public cc::BeginFrameObserver,
+ public cc::ExternalBeginFrameSourceClient {
+ public:
+ FakeCompositorFrameSink()
+ : cc::CompositorFrameSink(nullptr, nullptr, nullptr, nullptr) {}
+
+ // cc::CompositorFrameSink implementation:
+ bool BindToClient(cc::CompositorFrameSinkClient* client) override {
+ if (!cc::CompositorFrameSink::BindToClient(client))
+ return false;
+
+ external_begin_frame_source_ =
+ base::MakeUnique<cc::ExternalBeginFrameSource>(this);
+ client_->SetBeginFrameSource(external_begin_frame_source_.get());
+ return true;
+ }
+
+ void DetachFromClient() override {
+ cc::CompositorFrameSink::DetachFromClient();
+ }
+
+ void SubmitCompositorFrame(cc::CompositorFrame frame) override {
+ ++number_frames_received_;
+ last_frame_ = std::move(frame);
+ }
+
+ // cc::BeginFrameObserver implementation.
+ void OnBeginFrame(const cc::BeginFrameArgs& args) override {
+ external_begin_frame_source_->OnBeginFrame(args);
+ last_begin_frame_args_ = args;
+ }
+
+ const cc::BeginFrameArgs& LastUsedBeginFrameArgs() const override {
+ return last_begin_frame_args_;
+ }
+
+ void OnBeginFrameSourcePausedChanged(bool paused) override {}
+
+ // cc::ExternalBeginFrameSourceClient implementation:
+ void OnNeedsBeginFrames(bool needs_begin_frames) override {
+ needs_begin_frames_ = needs_begin_frames;
+ UpdateNeedsBeginFramesInternal();
+ }
+
+ void OnDidFinishFrame(const cc::BeginFrameAck& ack) override {
+ begin_frame_source_->DidFinishFrame(this, ack);
+ }
+
+ void SetBeginFrameSource(cc::BeginFrameSource* source) {
+ if (begin_frame_source_ && observing_begin_frames_) {
+ begin_frame_source_->RemoveObserver(this);
+ observing_begin_frames_ = false;
+ }
+ begin_frame_source_ = source;
+ UpdateNeedsBeginFramesInternal();
+ }
+
+ const cc::CompositorFrameMetadata& last_metadata() const {
+ return last_frame_.metadata;
+ }
+
+ const cc::RenderPassList& last_render_pass_list() const {
+ return last_frame_.render_pass_list;
+ }
+
+ int number_frames_received() { return number_frames_received_; }
+
+ private:
+ void UpdateNeedsBeginFramesInternal() {
+ if (!begin_frame_source_)
+ return;
+
+ if (needs_begin_frames_ == observing_begin_frames_)
+ return;
+
+ observing_begin_frames_ = needs_begin_frames_;
+ if (needs_begin_frames_) {
+ begin_frame_source_->AddObserver(this);
+ } else {
+ begin_frame_source_->RemoveObserver(this);
+ }
+ }
+
+ int number_frames_received_ = 0;
+ std::unique_ptr<cc::ExternalBeginFrameSource> external_begin_frame_source_;
+ cc::BeginFrameSource* begin_frame_source_ = nullptr;
+ cc::BeginFrameArgs last_begin_frame_args_;
+ bool observing_begin_frames_ = false;
+ bool needs_begin_frames_ = false;
+ cc::CompositorFrame last_frame_;
+
+ DISALLOW_COPY_AND_ASSIGN(FakeCompositorFrameSink);
+};
+
+class FrameGeneratorTest : public testing::Test {
+ public:
+ FrameGeneratorTest() {}
+ ~FrameGeneratorTest() override {}
+
+ // testing::Test overrides:
+ void SetUp() override {
+ testing::Test::SetUp();
+
+ std::unique_ptr<FakeCompositorFrameSink> compositor_frame_sink =
+ base::MakeUnique<FakeCompositorFrameSink>();
+ compositor_frame_sink_ = compositor_frame_sink.get();
+
+ constexpr float kRefreshRate = 0.f;
+ constexpr bool kTickAutomatically = false;
+ begin_frame_source_ = base::MakeUnique<cc::FakeExternalBeginFrameSource>(
+ kRefreshRate, kTickAutomatically);
+ compositor_frame_sink_->SetBeginFrameSource(begin_frame_source_.get());
+ server_window_delegate_ = base::MakeUnique<TestServerWindowDelegate>();
+ frame_generator_ =
+ base::MakeUnique<FrameGenerator>(std::move(compositor_frame_sink));
+ frame_generator_->OnWindowSizeChanged(gfx::Size(1, 2));
+ };
+
+ void InitWithSurfaceInfo() {
+ // FrameGenerator requires a valid SurfaceInfo before generating
+ // CompositorFrames.
+ const cc::SurfaceId kArbitrarySurfaceId(
+ cc::FrameSinkId(1, 1),
+ cc::LocalSurfaceId(1, base::UnguessableToken::Create()));
+ const cc::SurfaceInfo kArbitrarySurfaceInfo(kArbitrarySurfaceId, 1.0f,
+ gfx::Size(100, 100));
+
+ frame_generator()->OnSurfaceCreated(kArbitrarySurfaceInfo);
+ IssueBeginFrame();
+ EXPECT_EQ(1, NumberOfFramesReceived());
+ }
+
+ int NumberOfFramesReceived() {
+ return compositor_frame_sink_->number_frames_received();
+ }
+
+ void IssueBeginFrame() {
+ begin_frame_source_->TestOnBeginFrame(cc::CreateBeginFrameArgsForTesting(
+ BEGINFRAME_FROM_HERE, 0, next_sequence_number_));
+ ++next_sequence_number_;
+ }
+
+ FrameGenerator* frame_generator() { return frame_generator_.get(); }
+
+ const cc::CompositorFrameMetadata& LastMetadata() const {
+ return compositor_frame_sink_->last_metadata();
+ }
+
+ const cc::RenderPassList& LastRenderPassList() const {
+ return compositor_frame_sink_->last_render_pass_list();
+ }
+
+ const cc::BeginFrameAck& LastBeginFrameAck() {
+ return begin_frame_source_->LastAckForObserver(compositor_frame_sink_);
+ }
+
+ private:
+ FakeCompositorFrameSink* compositor_frame_sink_ = nullptr;
+ std::unique_ptr<cc::FakeExternalBeginFrameSource> begin_frame_source_;
+ std::unique_ptr<TestServerWindowDelegate> server_window_delegate_;
+ std::unique_ptr<FrameGenerator> frame_generator_;
+ int next_sequence_number_ = 1;
+
+ DISALLOW_COPY_AND_ASSIGN(FrameGeneratorTest);
+};
+
+TEST_F(FrameGeneratorTest, InvalidSurfaceInfo) {
+ // After SetUP(), frame_generator() has its |is_window_visible_| set to true
+ // and |bounds_| to an arbitrary non-empty gfx::Rect but not a valid
+ // SurfaceInfo. frame_generator() should not request BeginFrames in this
+ // state.
+ IssueBeginFrame();
+ EXPECT_EQ(0, NumberOfFramesReceived());
+}
+
+TEST_F(FrameGeneratorTest, OnSurfaceCreated) {
+ EXPECT_EQ(0, NumberOfFramesReceived());
+
+ // FrameGenerator does not request BeginFrames upon creation.
+ IssueBeginFrame();
+ EXPECT_EQ(0, NumberOfFramesReceived());
+ EXPECT_EQ(cc::BeginFrameAck(), LastBeginFrameAck());
+
+ const cc::SurfaceId kArbitrarySurfaceId(
+ cc::FrameSinkId(1, 1),
+ cc::LocalSurfaceId(1, base::UnguessableToken::Create()));
+ const cc::SurfaceInfo kArbitrarySurfaceInfo(kArbitrarySurfaceId, 1.0f,
+ gfx::Size(100, 100));
+ frame_generator()->OnSurfaceCreated(kArbitrarySurfaceInfo);
+ EXPECT_EQ(0, NumberOfFramesReceived());
+
+ IssueBeginFrame();
+ EXPECT_EQ(1, NumberOfFramesReceived());
+
+ // Verify that the CompositorFrame refers to the window manager's surface via
+ // referenced_surfaces.
+ const cc::CompositorFrameMetadata& last_metadata = LastMetadata();
+ const std::vector<cc::SurfaceId>& referenced_surfaces =
+ last_metadata.referenced_surfaces;
+ EXPECT_EQ(1lu, referenced_surfaces.size());
+ EXPECT_EQ(kArbitrarySurfaceId, referenced_surfaces.front());
+
+ cc::BeginFrameAck expected_ack(0, 2, 2, true);
+ EXPECT_EQ(expected_ack, LastBeginFrameAck());
+ EXPECT_EQ(expected_ack, last_metadata.begin_frame_ack);
+
+ // FrameGenerator stops requesting BeginFrames after submitting a
+ // CompositorFrame.
+ IssueBeginFrame();
+ EXPECT_EQ(1, NumberOfFramesReceived());
+ EXPECT_EQ(expected_ack, LastBeginFrameAck());
+}
+
+TEST_F(FrameGeneratorTest, SetDeviceScaleFactor) {
+ EXPECT_EQ(0, NumberOfFramesReceived());
+ const cc::SurfaceId kArbitrarySurfaceId(
+ cc::FrameSinkId(1, 1),
+ cc::LocalSurfaceId(1, base::UnguessableToken::Create()));
+ const cc::SurfaceInfo kArbitrarySurfaceInfo(kArbitrarySurfaceId, 1.0f,
+ gfx::Size(100, 100));
+ constexpr float kDefaultScaleFactor = 1.0f;
+ constexpr float kArbitraryScaleFactor = 0.5f;
+
+ // A valid SurfaceInfo is required before setting device scale factor.
+ frame_generator()->OnSurfaceCreated(kArbitrarySurfaceInfo);
+ IssueBeginFrame();
+ EXPECT_EQ(1, NumberOfFramesReceived());
+
+ // FrameGenerator stops requesting BeginFrames after receiving one.
+ IssueBeginFrame();
+ EXPECT_EQ(1, NumberOfFramesReceived());
+
+ // FrameGenerator does not request BeginFrames if its device scale factor
+ // remains unchanged.
+ frame_generator()->SetDeviceScaleFactor(kDefaultScaleFactor);
+ IssueBeginFrame();
+ EXPECT_EQ(1, NumberOfFramesReceived());
+ const cc::CompositorFrameMetadata& last_metadata = LastMetadata();
+ EXPECT_EQ(kDefaultScaleFactor, last_metadata.device_scale_factor);
+
+ frame_generator()->SetDeviceScaleFactor(kArbitraryScaleFactor);
+ IssueBeginFrame();
+ EXPECT_EQ(2, NumberOfFramesReceived());
+ const cc::CompositorFrameMetadata& second_last_metadata = LastMetadata();
+ EXPECT_EQ(kArbitraryScaleFactor, second_last_metadata.device_scale_factor);
+}
+
+TEST_F(FrameGeneratorTest, SetHighContrastMode) {
+ InitWithSurfaceInfo();
+
+ // Changing high contrast mode should trigger a BeginFrame.
+ frame_generator()->SetHighContrastMode(true);
+ IssueBeginFrame();
+ EXPECT_EQ(2, NumberOfFramesReceived());
+
+ // Verify that the last frame has an invert filter.
+ const cc::RenderPassList& render_pass_list = LastRenderPassList();
+ const cc::FilterOperations expected_filters(
+ {cc::FilterOperation::CreateInvertFilter(1.f)});
+ EXPECT_EQ(expected_filters, render_pass_list.front()->filters);
+}
+
+TEST_F(FrameGeneratorTest, WindowBoundsChanged) {
+ InitWithSurfaceInfo();
+
+ // Window bounds change triggers a BeginFrame.
+ constexpr int expected_render_pass_id = 1;
+ const gfx::Size kArbitrarySize(3, 4);
+ frame_generator()->OnWindowSizeChanged(kArbitrarySize);
+ IssueBeginFrame();
+ EXPECT_EQ(2, NumberOfFramesReceived());
+ cc::RenderPass* received_render_pass = LastRenderPassList().front().get();
+ EXPECT_EQ(expected_render_pass_id, received_render_pass->id);
+ EXPECT_EQ(kArbitrarySize, received_render_pass->output_rect.size());
+ EXPECT_EQ(kArbitrarySize, received_render_pass->damage_rect.size());
+ EXPECT_EQ(gfx::Transform(), received_render_pass->transform_to_root_target);
+}
+
+// Change window bounds twice before issuing a BeginFrame. The CompositorFrame
+// submitted by frame_generator() should only has the second bounds.
+TEST_F(FrameGeneratorTest, WindowBoundsChangedTwice) {
+ InitWithSurfaceInfo();
+
+ const gfx::Size kArbitrarySize(3, 4);
+ const gfx::Size kAnotherArbitrarySize(5, 6);
+ frame_generator()->OnWindowSizeChanged(kArbitrarySize);
+ frame_generator()->OnWindowSizeChanged(kAnotherArbitrarySize);
+ IssueBeginFrame();
+ EXPECT_EQ(2, NumberOfFramesReceived());
+ cc::RenderPass* received_render_pass = LastRenderPassList().front().get();
+ EXPECT_EQ(kAnotherArbitrarySize, received_render_pass->output_rect.size());
+ EXPECT_EQ(kAnotherArbitrarySize, received_render_pass->damage_rect.size());
+
+ // frame_generator() stops requesting BeginFrames after getting one.
+ IssueBeginFrame();
+ EXPECT_EQ(2, NumberOfFramesReceived());
+}
+
+TEST_F(FrameGeneratorTest, WindowDamaged) {
+ InitWithSurfaceInfo();
+
+ frame_generator()->OnWindowDamaged();
+ IssueBeginFrame();
+ EXPECT_EQ(2, NumberOfFramesReceived());
+}
+
+} // namespace test
+} // namespace ws
+} // namespace ui
diff --git a/chromium/services/ui/ws/gpu_client.cc b/chromium/services/ui/ws/gpu_client.cc
new file mode 100644
index 00000000000..c0ec4e6b528
--- /dev/null
+++ b/chromium/services/ui/ws/gpu_client.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/ui/ws/gpu_client.h"
+
+#include "services/ui/common/server_gpu_memory_buffer_manager.h"
+#include "services/ui/gpu/interfaces/gpu_service.mojom.h"
+
+namespace ui {
+namespace ws {
+
+GpuClient::GpuClient(int client_id,
+ gpu::GPUInfo* gpu_info,
+ ServerGpuMemoryBufferManager* gpu_memory_buffer_manager,
+ mojom::GpuService* gpu_service)
+ : client_id_(client_id),
+ gpu_info_(gpu_info),
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ gpu_service_(gpu_service),
+ weak_factory_(this) {
+ DCHECK(gpu_memory_buffer_manager_);
+ DCHECK(gpu_service_);
+}
+
+GpuClient::~GpuClient() {
+ gpu_memory_buffer_manager_->DestroyAllGpuMemoryBufferForClient(client_id_);
+}
+
+void GpuClient::OnGpuChannelEstablished(
+ const EstablishGpuChannelCallback& callback,
+ mojo::ScopedMessagePipeHandle channel_handle) {
+ callback.Run(client_id_, std::move(channel_handle), *gpu_info_);
+}
+
+// mojom::Gpu overrides:
+void GpuClient::EstablishGpuChannel(
+ const EstablishGpuChannelCallback& callback) {
+ // TODO(sad): crbug.com/617415 figure out how to generate a meaningful
+ // tracing id.
+ const uint64_t client_tracing_id = 0;
+ constexpr bool is_gpu_host = false;
+ gpu_service_->EstablishGpuChannel(
+ client_id_, client_tracing_id, is_gpu_host,
+ base::Bind(&GpuClient::OnGpuChannelEstablished,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void GpuClient::CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ const mojom::Gpu::CreateGpuMemoryBufferCallback& callback) {
+ auto handle = gpu_memory_buffer_manager_->CreateGpuMemoryBufferHandle(
+ id, client_id_, size, format, usage, gpu::kNullSurfaceHandle);
+ callback.Run(handle);
+}
+
+void GpuClient::DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ const gpu::SyncToken& sync_token) {
+ gpu_memory_buffer_manager_->DestroyGpuMemoryBuffer(id, client_id_,
+ sync_token);
+}
+
+} // namespace ws
+} // namespace ui
diff --git a/chromium/services/ui/ws/gpu_client.h b/chromium/services/ui/ws/gpu_client.h
new file mode 100644
index 00000000000..ac5f07292b2
--- /dev/null
+++ b/chromium/services/ui/ws/gpu_client.h
@@ -0,0 +1,69 @@
+// 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_UI_WS_GPU_CLIENT_H_
+#define SERVICES_UI_WS_GPU_CLIENT_H_
+
+#include "base/memory/weak_ptr.h"
+#include "gpu/config/gpu_info.h"
+#include "services/ui/public/interfaces/gpu.mojom.h"
+
+namespace ui {
+
+namespace mojom {
+class GpuService;
+} // namespace mojom
+
+class ServerGpuMemoryBufferManager;
+
+namespace ws {
+
+namespace test {
+class GpuHostTest;
+} // namespace test
+
+// The implementation that relays requests from clients to the real
+// service implementation in the GPU process over mojom.GpuService.
+class GpuClient : public mojom::Gpu {
+ public:
+ GpuClient(int client_id,
+ gpu::GPUInfo* gpu_info,
+ ServerGpuMemoryBufferManager* gpu_memory_buffer_manager,
+ mojom::GpuService* gpu_service);
+ ~GpuClient() override;
+
+ private:
+ friend class test::GpuHostTest;
+
+ // EstablishGpuChannelCallback:
+ void OnGpuChannelEstablished(const EstablishGpuChannelCallback& callback,
+ mojo::ScopedMessagePipeHandle channel_handle);
+ // mojom::Gpu overrides:
+ void EstablishGpuChannel(
+ const EstablishGpuChannelCallback& callback) override;
+ void CreateGpuMemoryBuffer(
+ gfx::GpuMemoryBufferId id,
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ const mojom::Gpu::CreateGpuMemoryBufferCallback& callback) override;
+ void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
+ const gpu::SyncToken& sync_token) override;
+
+ const int client_id_;
+
+ // The objects these pointers refer to are owned by the GpuHost object.
+ const gpu::GPUInfo* gpu_info_;
+ ServerGpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ mojom::GpuService* gpu_service_;
+
+ base::WeakPtrFactory<GpuClient> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuClient);
+};
+
+} // namespace ws
+} // namespace ui
+
+#endif // SERVICES_UI_WS_GPU_CLIENT_H_
diff --git a/chromium/services/ui/ws/gpu_host.cc b/chromium/services/ui/ws/gpu_host.cc
index bfa771d2719..85ac3aa25cf 100644
--- a/chromium/services/ui/ws/gpu_host.cc
+++ b/chromium/services/ui/ws/gpu_host.cc
@@ -14,8 +14,8 @@
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "mojo/public/cpp/system/buffer.h"
#include "mojo/public/cpp/system/platform_handle.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/ui/common/server_gpu_memory_buffer_manager.h"
+#include "services/ui/ws/gpu_client.h"
#include "services/ui/ws/gpu_host_delegate.h"
#include "ui/gfx/buffer_format_util.h"
@@ -28,74 +28,9 @@ namespace ws {
namespace {
-// The client Id 1 is reserved for the display compositor.
+// The client Id 1 is reserved for the frame sink manager.
const int32_t kInternalGpuChannelClientId = 2;
-// The implementation that relays requests from clients to the real
-// service implementation in the GPU process over mojom.GpuService.
-class GpuClient : public mojom::Gpu {
- public:
- GpuClient(int client_id,
- gpu::GPUInfo* gpu_info,
- ServerGpuMemoryBufferManager* gpu_memory_buffer_manager,
- mojom::GpuService* gpu_service)
- : client_id_(client_id),
- gpu_info_(gpu_info),
- gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
- gpu_service_(gpu_service) {
- DCHECK(gpu_memory_buffer_manager_);
- DCHECK(gpu_service_);
- }
- ~GpuClient() override {
- gpu_memory_buffer_manager_->DestroyAllGpuMemoryBufferForClient(client_id_);
- }
-
- private:
- void OnGpuChannelEstablished(const EstablishGpuChannelCallback& callback,
- mojo::ScopedMessagePipeHandle channel_handle) {
- callback.Run(client_id_, std::move(channel_handle), *gpu_info_);
- }
-
- // mojom::Gpu overrides:
- void EstablishGpuChannel(
- const EstablishGpuChannelCallback& callback) override {
- // TODO(sad): crbug.com/617415 figure out how to generate a meaningful
- // tracing id.
- const uint64_t client_tracing_id = 0;
- constexpr bool is_gpu_host = false;
- gpu_service_->EstablishGpuChannel(
- client_id_, client_tracing_id, is_gpu_host,
- base::Bind(&GpuClient::OnGpuChannelEstablished, base::Unretained(this),
- callback));
- }
-
- void CreateGpuMemoryBuffer(
- gfx::GpuMemoryBufferId id,
- const gfx::Size& size,
- gfx::BufferFormat format,
- gfx::BufferUsage usage,
- const mojom::Gpu::CreateGpuMemoryBufferCallback& callback) override {
- auto handle = gpu_memory_buffer_manager_->CreateGpuMemoryBufferHandle(
- id, client_id_, size, format, usage, gpu::kNullSurfaceHandle);
- callback.Run(handle);
- }
-
- void DestroyGpuMemoryBuffer(gfx::GpuMemoryBufferId id,
- const gpu::SyncToken& sync_token) override {
- gpu_memory_buffer_manager_->DestroyGpuMemoryBuffer(id, client_id_,
- sync_token);
- }
-
- const int client_id_;
-
- // The objects these pointers refer to are owned by the GpuHost object.
- const gpu::GPUInfo* gpu_info_;
- ServerGpuMemoryBufferManager* gpu_memory_buffer_manager_;
- mojom::GpuService* gpu_service_;
-
- DISALLOW_COPY_AND_ASSIGN(GpuClient);
-};
-
} // namespace
GpuHost::GpuHost(GpuHostDelegate* delegate)
@@ -113,7 +48,7 @@ GpuHost::GpuHost(GpuHostDelegate* delegate)
gpu::GpuPreferences preferences;
gpu_main_->CreateGpuService(MakeRequest(&gpu_service_),
gpu_host_binding_.CreateInterfacePtrAndBind(),
- preferences);
+ preferences, mojo::ScopedSharedBufferHandle());
gpu_memory_buffer_manager_ = base::MakeUnique<ServerGpuMemoryBufferManager>(
gpu_service_.get(), next_client_id_++);
}
@@ -121,11 +56,7 @@ GpuHost::GpuHost(GpuHostDelegate* delegate)
GpuHost::~GpuHost() {}
void GpuHost::Add(mojom::GpuRequest request) {
- mojo::MakeStrongBinding(
- base::MakeUnique<GpuClient>(next_client_id_++, &gpu_info_,
- gpu_memory_buffer_manager_.get(),
- gpu_service_.get()),
- std::move(request));
+ AddInternal(std::move(request));
}
void GpuHost::OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget) {
@@ -140,10 +71,19 @@ void GpuHost::OnAcceleratedWidgetDestroyed(gfx::AcceleratedWidget widget) {
#endif
}
-void GpuHost::CreateDisplayCompositor(
- cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtr client) {
- gpu_main_->CreateDisplayCompositor(std::move(request), std::move(client));
+void GpuHost::CreateFrameSinkManager(
+ cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtr client) {
+ gpu_main_->CreateFrameSinkManager(std::move(request), std::move(client));
+}
+
+GpuClient* GpuHost::AddInternal(mojom::GpuRequest request) {
+ auto client(base::MakeUnique<GpuClient>(next_client_id_++, &gpu_info_,
+ gpu_memory_buffer_manager_.get(),
+ gpu_service_.get()));
+ GpuClient* client_ref = client.get();
+ gpu_bindings_.AddBinding(std::move(client), std::move(request));
+ return client_ref;
}
void GpuHost::OnBadMessageFromGpu() {
@@ -152,11 +92,14 @@ void GpuHost::OnBadMessageFromGpu() {
NOTIMPLEMENTED();
}
-void GpuHost::DidInitialize(const gpu::GPUInfo& gpu_info) {
+void GpuHost::DidInitialize(const gpu::GPUInfo& gpu_info,
+ const gpu::GpuFeatureInfo& gpu_feature_info) {
gpu_info_ = gpu_info;
delegate_->OnGpuServiceInitialized();
}
+void GpuHost::DidFailInitialize() {}
+
void GpuHost::DidCreateOffscreenContext(const GURL& url) {}
void GpuHost::DidDestroyOffscreenContext(const GURL& url) {}
@@ -193,5 +136,9 @@ void GpuHost::StoreShaderToDisk(int32_t client_id,
const std::string& key,
const std::string& shader) {}
+void GpuHost::RecordLogMessage(int32_t severity,
+ const std::string& header,
+ const std::string& message) {}
+
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/gpu_host.h b/chromium/services/ui/ws/gpu_host.h
index b937266a5cc..bb0e0a6372d 100644
--- a/chromium/services/ui/ws/gpu_host.h
+++ b/chromium/services/ui/ws/gpu_host.h
@@ -12,6 +12,7 @@
#include "gpu/ipc/client/gpu_channel_host.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "services/ui/gpu/gpu_main.h"
#include "services/ui/gpu/interfaces/gpu_host.mojom.h"
#include "services/ui/gpu/interfaces/gpu_service.mojom.h"
@@ -23,6 +24,12 @@ class ServerGpuMemoryBufferManager;
namespace ws {
+class GpuClient;
+
+namespace test {
+class GpuHostTest;
+} // namespace test
+
class GpuHostDelegate;
// Sets up connection from clients to the real service implementation in the GPU
@@ -37,15 +44,20 @@ class GpuHost : public mojom::GpuHost {
void OnAcceleratedWidgetAvailable(gfx::AcceleratedWidget widget);
void OnAcceleratedWidgetDestroyed(gfx::AcceleratedWidget widget);
- // Requests a cc::mojom::DisplayCompositor interface from mus-gpu.
- void CreateDisplayCompositor(cc::mojom::DisplayCompositorRequest request,
- cc::mojom::DisplayCompositorClientPtr client);
+ // Requests a cc::mojom::FrameSinkManager interface from mus-gpu.
+ void CreateFrameSinkManager(cc::mojom::FrameSinkManagerRequest request,
+ cc::mojom::FrameSinkManagerClientPtr client);
private:
+ friend class test::GpuHostTest;
+
+ GpuClient* AddInternal(mojom::GpuRequest request);
void OnBadMessageFromGpu();
// mojom::GpuHost:
- void DidInitialize(const gpu::GPUInfo& gpu_info) override;
+ void DidInitialize(const gpu::GPUInfo& gpu_info,
+ const gpu::GpuFeatureInfo& gpu_feature_info) override;
+ void DidFailInitialize() override;
void DidCreateOffscreenContext(const GURL& url) override;
void DidDestroyOffscreenContext(const GURL& url) override;
void DidDestroyChannel(int32_t client_id) override;
@@ -57,6 +69,9 @@ class GpuHost : public mojom::GpuHost {
void StoreShaderToDisk(int32_t client_id,
const std::string& key,
const std::string& shader) override;
+ void RecordLogMessage(int32_t severity,
+ const std::string& header,
+ const std::string& message) override;
GpuHostDelegate* const delegate_;
int32_t next_client_id_;
@@ -72,6 +87,8 @@ class GpuHost : public mojom::GpuHost {
// because that will live in another process soon.
std::unique_ptr<GpuMain> gpu_main_impl_;
+ mojo::StrongBindingSet<mojom::Gpu> gpu_bindings_;
+
DISALLOW_COPY_AND_ASSIGN(GpuHost);
};
diff --git a/chromium/services/ui/ws/gpu_host_unittest.cc b/chromium/services/ui/ws/gpu_host_unittest.cc
new file mode 100644
index 00000000000..e3c1c681f9d
--- /dev/null
+++ b/chromium/services/ui/ws/gpu_host_unittest.cc
@@ -0,0 +1,125 @@
+// 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/ui/ws/gpu_host.h"
+
+#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/config/gpu_info.h"
+#include "services/ui/gpu/gpu_service.h"
+#include "services/ui/public/interfaces/gpu.mojom.h"
+#include "services/ui/ws/gpu_client.h"
+#include "services/ui/ws/gpu_host_delegate.h"
+
+#if defined(USE_X11)
+#include <X11/Xlib.h>
+#undef None
+#undef Bool
+#endif // USE_X11
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace ui {
+namespace ws {
+namespace test {
+namespace {
+
+// No-opt implementation of GpuHostDelegate.
+class TestGpuHostDelegate : public GpuHostDelegate {
+ public:
+ TestGpuHostDelegate() {}
+ ~TestGpuHostDelegate() override {}
+
+ // GpuHostDelegate:
+ void OnGpuServiceInitialized() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestGpuHostDelegate);
+};
+
+// Test implementation of GpuService. For testing behaviour of calls made by
+// GpuClient
+class TestGpuService : public GpuService {
+ public:
+ explicit TestGpuService(
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner);
+ ~TestGpuService() override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestGpuService);
+};
+
+TestGpuService::TestGpuService(
+ scoped_refptr<base::SingleThreadTaskRunner> io_runner)
+ : GpuService(gpu::GPUInfo(),
+ nullptr /* watchdog_thread */,
+ std::move(io_runner),
+ gpu::GpuFeatureInfo()) {}
+
+} // namespace
+
+class GpuHostTest : public testing::Test {
+ public:
+ GpuHostTest() : io_thread_("IOThread") {
+ CHECK(io_thread_.Start());
+ gpu_service_ = base::MakeUnique<TestGpuService>(io_thread_.task_runner());
+ }
+ ~GpuHostTest() override {}
+
+ GpuHost* gpu_host() { return gpu_host_.get(); }
+
+ base::WeakPtr<GpuClient> AddGpuClient();
+ void DestroyHost();
+
+ // testing::Test
+ void SetUp() override;
+
+ private:
+ base::MessageLoop message_loop_;
+
+ base::WeakPtr<GpuClient> client_ref_;
+
+ base::Thread io_thread_;
+ TestGpuHostDelegate gpu_host_delegate_;
+ std::unique_ptr<TestGpuService> gpu_service_;
+ ui::mojom::GpuServicePtr gpu_service_ptr_;
+ std::unique_ptr<GpuHost> gpu_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuHostTest);
+};
+
+base::WeakPtr<GpuClient> GpuHostTest::AddGpuClient() {
+ mojom::GpuRequest request;
+ GpuClient* client = gpu_host_->AddInternal(std::move(request));
+ return client->weak_factory_.GetWeakPtr();
+}
+
+void GpuHostTest::DestroyHost() {
+ gpu_host_.reset();
+}
+
+void GpuHostTest::SetUp() {
+ testing::Test::SetUp();
+ gpu_host_ = base::MakeUnique<GpuHost>(&gpu_host_delegate_);
+
+ ui::mojom::GpuServiceRequest request(&gpu_service_ptr_);
+ gpu_service_->Bind(std::move(request));
+ gpu_host_->gpu_service_ = std::move(gpu_service_ptr_);
+}
+
+// Tests to verify, that if a GpuHost is deleted before GpuClient receives a
+// callback, that GpuClient is torn down and does not attempt to use GpuInfo
+// after deletion. This should not crash on asan-builds.
+TEST_F(GpuHostTest, GpuClientDestructionOrder) {
+ base::WeakPtr<GpuClient> client_ref = AddGpuClient();
+ EXPECT_NE(nullptr, client_ref);
+ DestroyHost();
+ EXPECT_EQ(nullptr, client_ref);
+}
+
+} // namespace test
+} // namespace ws
+} // namespace ui
diff --git a/chromium/services/ui/ws/modal_window_controller.cc b/chromium/services/ui/ws/modal_window_controller.cc
index a07dc1f420c..9ac70b9b6af 100644
--- a/chromium/services/ui/ws/modal_window_controller.cc
+++ b/chromium/services/ui/ws/modal_window_controller.cc
@@ -18,7 +18,8 @@ const ServerWindow* GetModalChildForWindowAncestor(const ServerWindow* window) {
for (const ServerWindow* ancestor = window; ancestor;
ancestor = ancestor->parent()) {
for (auto* transient_child : ancestor->transient_children()) {
- if (transient_child->is_modal() && transient_child->IsDrawn())
+ if (transient_child->modal_type() != MODAL_TYPE_NONE &&
+ transient_child->IsDrawn())
return transient_child;
}
}
@@ -48,7 +49,7 @@ void ModalWindowController::AddSystemModalWindow(ServerWindow* window) {
DCHECK(window);
DCHECK(!base::ContainsValue(system_modal_windows_, window));
- window->SetModal();
+ window->SetModalType(ui::MODAL_TYPE_SYSTEM);
system_modal_windows_.push_back(window);
window_drawn_trackers_.insert(make_pair(
window, base::MakeUnique<ServerWindowDrawnTracker>(window, this)));
@@ -62,8 +63,10 @@ bool ModalWindowController::IsWindowBlockedBy(
const ServerWindow* modal_window) const {
DCHECK(window);
DCHECK(modal_window);
- if (!modal_window->is_modal() || !modal_window->IsDrawn())
+ if (modal_window->modal_type() == MODAL_TYPE_NONE ||
+ !modal_window->IsDrawn()) {
return false;
+ }
if (modal_window->transient_parent() &&
!modal_window->transient_parent()->Contains(window)) {
@@ -75,14 +78,16 @@ bool ModalWindowController::IsWindowBlockedBy(
bool ModalWindowController::IsWindowBlocked(const ServerWindow* window) const {
DCHECK(window);
- return GetActiveSystemModalWindow() || GetModalChildForWindowAncestor(window);
+ return GetTargetForWindow(window) != window;
}
const ServerWindow* ModalWindowController::GetTargetForWindow(
const ServerWindow* window) const {
+ // TODO(moshayedi): crbug.com/697127. Handle MODAL_TYPE_CHILD.
ServerWindow* system_modal_window = GetActiveSystemModalWindow();
if (system_modal_window)
- return system_modal_window;
+ return system_modal_window->Contains(window) ? window : system_modal_window;
+
return window ? GetWindowModalTargetForWindow(window) : nullptr;
}
diff --git a/chromium/services/ui/ws/platform_display.cc b/chromium/services/ui/ws/platform_display.cc
index e008e955ab0..587e4508e44 100644
--- a/chromium/services/ui/ws/platform_display.cc
+++ b/chromium/services/ui/ws/platform_display.cc
@@ -7,7 +7,8 @@
#include "base/memory/ptr_util.h"
#include "services/ui/ws/platform_display_default.h"
#include "services/ui/ws/platform_display_factory.h"
-#include "services/ui/ws/platform_display_init_params.h"
+#include "services/ui/ws/server_window.h"
+#include "ui/base/cursor/image_cursors.h"
namespace ui {
namespace ws {
@@ -17,11 +18,18 @@ PlatformDisplayFactory* PlatformDisplay::factory_ = nullptr;
// static
std::unique_ptr<PlatformDisplay> PlatformDisplay::Create(
- const PlatformDisplayInitParams& init_params) {
+ ServerWindow* root,
+ const display::ViewportMetrics& metrics) {
if (factory_)
- return factory_->CreatePlatformDisplay(init_params);
+ return factory_->CreatePlatformDisplay(root, metrics);
- return base::MakeUnique<PlatformDisplayDefault>(init_params);
+#if defined(OS_ANDROID)
+ return base::MakeUnique<PlatformDisplayDefault>(root, metrics,
+ nullptr /* image_cursors */);
+#else
+ return base::MakeUnique<PlatformDisplayDefault>(
+ root, metrics, base::MakeUnique<ImageCursors>());
+#endif
}
} // namespace ws
diff --git a/chromium/services/ui/ws/platform_display.h b/chromium/services/ui/ws/platform_display.h
index 39299aeddd1..7f82a61350c 100644
--- a/chromium/services/ui/ws/platform_display.h
+++ b/chromium/services/ui/ws/platform_display.h
@@ -12,13 +12,10 @@
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "services/ui/display/viewport_metrics.h"
-#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
+#include "ui/events/event_source.h"
#include "ui/gfx/native_widget_types.h"
-namespace gfx {
-class Rect;
-}
-
namespace ui {
struct TextInputState;
@@ -28,17 +25,16 @@ namespace ws {
class FrameGenerator;
class PlatformDisplayDelegate;
class PlatformDisplayFactory;
-struct PlatformDisplayInitParams;
+class ServerWindow;
// PlatformDisplay is used to connect the root ServerWindow to a display.
-class PlatformDisplay {
+class PlatformDisplay : public ui::EventSource {
public:
- virtual ~PlatformDisplay() {}
+ ~PlatformDisplay() override {}
static std::unique_ptr<PlatformDisplay> Create(
- const PlatformDisplayInitParams& init_params);
-
- virtual int64_t GetId() const = 0;
+ ServerWindow* root_window,
+ const display::ViewportMetrics& metrics);
virtual void Init(PlatformDisplayDelegate* delegate) = 0;
@@ -50,20 +46,15 @@ class PlatformDisplay {
virtual void ReleaseCapture() = 0;
- virtual void SetCursorById(mojom::Cursor cursor) = 0;
+ virtual void SetCursorById(mojom::CursorType cursor) = 0;
virtual void UpdateTextInputState(const ui::TextInputState& state) = 0;
virtual void SetImeVisibility(bool visible) = 0;
- virtual gfx::Rect GetBounds() const = 0;
-
- // Updates the viewport metrics for the display, returning true if any
- // metrics have changed.
- virtual bool UpdateViewportMetrics(
+ // Updates the viewport metrics for the display.
+ virtual void UpdateViewportMetrics(
const display::ViewportMetrics& metrics) = 0;
- virtual const display::ViewportMetrics& GetViewportMetrics() const = 0;
-
// Returns the AcceleratedWidget associated with the Display. It can return
// kNullAcceleratedWidget if the accelerated widget is not available yet.
virtual gfx::AcceleratedWidget GetAcceleratedWidget() const = 0;
diff --git a/chromium/services/ui/ws/platform_display_default.cc b/chromium/services/ui/ws/platform_display_default.cc
index 6d32827f0b7..08f8f9e26da 100644
--- a/chromium/services/ui/ws/platform_display_default.cc
+++ b/chromium/services/ui/ws/platform_display_default.cc
@@ -4,10 +4,12 @@
#include "services/ui/ws/platform_display_default.h"
+#include <utility>
+
#include "base/memory/ptr_util.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "services/ui/display/screen_manager.h"
-#include "services/ui/ws/platform_display_init_params.h"
+#include "services/ui/ws/display_client_compositor_frame_sink.h"
#include "services/ui/ws/server_window.h"
#include "ui/base/cursor/image_cursors.h"
#include "ui/display/display.h"
@@ -30,16 +32,13 @@ namespace ui {
namespace ws {
PlatformDisplayDefault::PlatformDisplayDefault(
- const PlatformDisplayInitParams& init_params)
- : display_id_(init_params.display_id),
-#if !defined(OS_ANDROID)
- image_cursors_(new ImageCursors),
-#endif
- metrics_(init_params.metrics),
- widget_(gfx::kNullAcceleratedWidget),
- root_window_(init_params.root_window),
- init_device_scale_factor_(init_params.metrics.device_scale_factor) {
-}
+ ServerWindow* root_window,
+ const display::ViewportMetrics& metrics,
+ std::unique_ptr<ImageCursors> image_cursors)
+ : root_window_(root_window),
+ image_cursors_(std::move(image_cursors)),
+ metrics_(metrics),
+ widget_(gfx::kNullAcceleratedWidget) {}
PlatformDisplayDefault::~PlatformDisplayDefault() {
// Don't notify the delegate from the destructor.
@@ -52,14 +51,17 @@ PlatformDisplayDefault::~PlatformDisplayDefault() {
platform_window_.reset();
}
+EventSink* PlatformDisplayDefault::GetEventSink() {
+ return delegate_->GetEventSink();
+}
+
void PlatformDisplayDefault::Init(PlatformDisplayDelegate* delegate) {
+ DCHECK(delegate);
delegate_ = delegate;
- DCHECK(!metrics_.pixel_size.IsEmpty());
+ const gfx::Rect& bounds = metrics_.bounds_in_pixels;
+ DCHECK(!bounds.size().IsEmpty());
- // TODO(kylechar): The origin here isn't right if any displays have
- // scale_factor other than 1.0 but will prevent windows from being stacked.
- gfx::Rect bounds(metrics_.bounds.origin(), metrics_.pixel_size);
#if defined(OS_WIN)
platform_window_ = base::MakeUnique<ui::WinWindow>(this, bounds);
#elif defined(USE_X11) && !defined(OS_CHROMEOS)
@@ -69,20 +71,16 @@ void PlatformDisplayDefault::Init(PlatformDisplayDelegate* delegate) {
platform_window_->SetBounds(bounds);
#elif defined(USE_OZONE)
platform_window_ =
- ui::OzonePlatform::GetInstance()->CreatePlatformWindow(this, bounds);
+ delegate_->GetOzonePlatform()->CreatePlatformWindow(this, bounds);
#else
NOTREACHED() << "Unsupported platform";
#endif
platform_window_->Show();
-#if !defined(OS_ANDROID)
- image_cursors_->SetDisplay(delegate_->GetDisplay(),
- metrics_.device_scale_factor);
-#endif
-}
-
-int64_t PlatformDisplayDefault::GetId() const {
- return display_id_;
+ if (image_cursors_) {
+ image_cursors_->SetDisplay(delegate_->GetDisplay(),
+ metrics_.device_scale_factor);
+ }
}
void PlatformDisplayDefault::SetViewportSize(const gfx::Size& size) {
@@ -101,8 +99,10 @@ void PlatformDisplayDefault::ReleaseCapture() {
platform_window_->ReleaseCapture();
}
-void PlatformDisplayDefault::SetCursorById(mojom::Cursor cursor_id) {
-#if !defined(OS_ANDROID)
+void PlatformDisplayDefault::SetCursorById(mojom::CursorType cursor_id) {
+ if (!image_cursors_)
+ return;
+
// TODO(erg): This still isn't sufficient, and will only use native cursors
// that chrome would use, not custom image cursors. For that, we should
// delegate to the window manager to load images from resource packs.
@@ -111,7 +111,6 @@ void PlatformDisplayDefault::SetCursorById(mojom::Cursor cursor_id) {
ui::Cursor cursor(static_cast<int32_t>(cursor_id));
image_cursors_->SetPlatformCursor(&cursor);
platform_window_->SetCursor(cursor.platform());
-#endif
}
void PlatformDisplayDefault::UpdateTextInputState(
@@ -127,34 +126,26 @@ void PlatformDisplayDefault::SetImeVisibility(bool visible) {
ime->SetImeVisibility(visible);
}
-gfx::Rect PlatformDisplayDefault::GetBounds() const {
- return metrics_.bounds;
-}
-
FrameGenerator* PlatformDisplayDefault::GetFrameGenerator() {
return frame_generator_.get();
}
-bool PlatformDisplayDefault::UpdateViewportMetrics(
+void PlatformDisplayDefault::UpdateViewportMetrics(
const display::ViewportMetrics& metrics) {
if (metrics_ == metrics)
- return false;
+ return;
gfx::Rect bounds = platform_window_->GetBounds();
- if (bounds.size() != metrics.pixel_size) {
- bounds.set_size(metrics.pixel_size);
+ if (bounds.size() != metrics.bounds_in_pixels.size()) {
+ bounds.set_size(metrics.bounds_in_pixels.size());
platform_window_->SetBounds(bounds);
}
metrics_ = metrics;
- if (frame_generator_)
+ if (frame_generator_) {
frame_generator_->SetDeviceScaleFactor(metrics_.device_scale_factor);
- return true;
-}
-
-const display::ViewportMetrics& PlatformDisplayDefault::GetViewportMetrics()
- const {
- return metrics_;
+ frame_generator_->OnWindowSizeChanged(metrics_.bounds_in_pixels.size());
+ }
}
gfx::AcceleratedWidget PlatformDisplayDefault::GetAcceleratedWidget() const {
@@ -162,19 +153,21 @@ gfx::AcceleratedWidget PlatformDisplayDefault::GetAcceleratedWidget() const {
}
void PlatformDisplayDefault::UpdateEventRootLocation(ui::LocatedEvent* event) {
+ // TODO(riajiang): This is broken for HDPI because it mixes PPs and DIPs. See
+ // http://crbug.com/701036 for details.
+ const display::Display& display = delegate_->GetDisplay();
gfx::Point location = event->location();
- location.Offset(metrics_.bounds.x(), metrics_.bounds.y());
+ location.Offset(display.bounds().x(), display.bounds().y());
event->set_root_location(location);
}
void PlatformDisplayDefault::OnBoundsChanged(const gfx::Rect& new_bounds) {
// We only care if the window size has changed.
- if (new_bounds.size() == metrics_.pixel_size)
+ if (new_bounds.size() == metrics_.bounds_in_pixels.size())
return;
- // TODO(kylechar): Maybe do something here. For CrOS we don't need to support
- // PlatformWindow initiated resizes. For other platforms we need to do
- // something but that isn't fully flushed out.
+ // TODO(tonikitoo): Handle the bounds changing in external window mode. The
+ // window should be resized by the WS and it shouldn't involve ScreenManager.
}
void PlatformDisplayDefault::OnDamageRect(const gfx::Rect& damaged_region) {
@@ -189,45 +182,26 @@ void PlatformDisplayDefault::DispatchEvent(ui::Event* event) {
if (event->IsScrollEvent()) {
// TODO(moshayedi): crbug.com/602859. Dispatch scroll events as
// they are once we have proper support for scroll events.
- delegate_->OnEvent(
- ui::PointerEvent(ui::MouseWheelEvent(*event->AsScrollEvent())));
+
+ ui::PointerEvent pointer_event(
+ ui::MouseWheelEvent(*event->AsScrollEvent()));
+ SendEventToSink(&pointer_event);
} else if (event->IsMouseEvent()) {
- delegate_->OnEvent(ui::PointerEvent(*event->AsMouseEvent()));
+ ui::PointerEvent pointer_event(*event->AsMouseEvent());
+ SendEventToSink(&pointer_event);
} else if (event->IsTouchEvent()) {
- delegate_->OnEvent(ui::PointerEvent(*event->AsTouchEvent()));
+ ui::PointerEvent pointer_event(*event->AsTouchEvent());
+ SendEventToSink(&pointer_event);
} else {
- delegate_->OnEvent(*event);
- }
-
-#if defined(USE_X11) || defined(USE_OZONE)
- // We want to emulate the WM_CHAR generation behaviour of Windows.
- //
- // On Linux, we've previously inserted characters by having
- // InputMethodAuraLinux take all key down events and send a character event
- // to the TextInputClient. This causes a mismatch in code that has to be
- // shared between Windows and Linux, including blink code. Now that we're
- // trying to have one way of doing things, we need to standardize on and
- // emulate Windows character events.
- //
- // This is equivalent to what we're doing in the current Linux port, but
- // done once instead of done multiple times in different places.
- if (event->type() == ui::ET_KEY_PRESSED) {
- ui::KeyEvent* key_press_event = event->AsKeyEvent();
- ui::KeyEvent char_event(key_press_event->GetCharacter(),
- key_press_event->key_code(),
- key_press_event->flags());
- // We don't check that GetCharacter() is equal because changing a key event
- // with an accelerator to a character event can change the character, for
- // example, from 'M' to '^M'.
- DCHECK_EQ(key_press_event->key_code(), char_event.key_code());
- DCHECK_EQ(key_press_event->flags(), char_event.flags());
- delegate_->OnEvent(char_event);
+ SendEventToSink(event);
}
-#endif
}
void PlatformDisplayDefault::OnCloseRequest() {
- display::ScreenManager::GetInstance()->RequestCloseDisplay(GetId());
+ // TODO(tonikitoo): Handle a close request in external window mode. The window
+ // should be closed by the WS and it shouldn't involve ScreenManager.
+ const int64_t display_id = delegate_->GetDisplay().id();
+ display::ScreenManager::GetInstance()->RequestCloseDisplay(display_id);
}
void PlatformDisplayDefault::OnClosed() {}
@@ -248,9 +222,28 @@ void PlatformDisplayDefault::OnAcceleratedWidgetAvailable(
DCHECK_EQ(gfx::kNullAcceleratedWidget, widget_);
widget_ = widget;
delegate_->OnAcceleratedWidgetAvailable();
- frame_generator_ =
- base::MakeUnique<FrameGenerator>(this, root_window_, widget_);
- frame_generator_->SetDeviceScaleFactor(init_device_scale_factor_);
+
+ cc::mojom::MojoCompositorFrameSinkAssociatedPtr compositor_frame_sink;
+ cc::mojom::DisplayPrivateAssociatedPtr display_private;
+ cc::mojom::MojoCompositorFrameSinkClientPtr compositor_frame_sink_client;
+ cc::mojom::MojoCompositorFrameSinkClientRequest
+ compositor_frame_sink_client_request =
+ mojo::MakeRequest(&compositor_frame_sink_client);
+
+ root_window_->CreateRootCompositorFrameSink(
+ widget_, mojo::MakeRequest(&compositor_frame_sink),
+ std::move(compositor_frame_sink_client),
+ mojo::MakeRequest(&display_private));
+
+ auto display_client_compositor_frame_sink =
+ base::MakeUnique<DisplayClientCompositorFrameSink>(
+ root_window_->frame_sink_id(), std::move(compositor_frame_sink),
+ std::move(display_private),
+ std::move(compositor_frame_sink_client_request));
+ frame_generator_ = base::MakeUnique<FrameGenerator>(
+ std::move(display_client_compositor_frame_sink));
+ frame_generator_->OnWindowSizeChanged(root_window_->bounds().size());
+ frame_generator_->SetDeviceScaleFactor(metrics_.device_scale_factor);
}
void PlatformDisplayDefault::OnAcceleratedWidgetDestroyed() {
@@ -259,9 +252,5 @@ void PlatformDisplayDefault::OnAcceleratedWidgetDestroyed() {
void PlatformDisplayDefault::OnActivationChanged(bool active) {}
-bool PlatformDisplayDefault::IsInHighContrastMode() {
- return delegate_ ? delegate_->IsInHighContrastMode() : false;
-}
-
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/platform_display_default.h b/chromium/services/ui/ws/platform_display_default.h
index 54d36d8b5e8..3c7d5902151 100644
--- a/chromium/services/ui/ws/platform_display_default.h
+++ b/chromium/services/ui/ws/platform_display_default.h
@@ -10,14 +10,16 @@
#include "base/macros.h"
#include "services/ui/display/viewport_metrics.h"
#include "services/ui/ws/frame_generator.h"
-#include "services/ui/ws/frame_generator_delegate.h"
#include "services/ui/ws/platform_display.h"
#include "services/ui/ws/platform_display_delegate.h"
+#include "services/ui/ws/server_window.h"
#include "ui/platform_window/platform_window_delegate.h"
namespace ui {
+class EventSink;
class ImageCursors;
+class LocatedEvent;
class PlatformWindow;
namespace ws {
@@ -25,25 +27,27 @@ namespace ws {
// PlatformDisplay implementation that connects to a PlatformWindow and
// FrameGenerator for Chrome OS.
class PlatformDisplayDefault : public PlatformDisplay,
- public ui::PlatformWindowDelegate,
- public FrameGeneratorDelegate {
+ public ui::PlatformWindowDelegate {
public:
- explicit PlatformDisplayDefault(const PlatformDisplayInitParams& init_params);
+ // |image_cursors| may be null, for example on Android or in tests.
+ PlatformDisplayDefault(ServerWindow* root_window,
+ const display::ViewportMetrics& metrics,
+ std::unique_ptr<ImageCursors> image_cursors);
~PlatformDisplayDefault() override;
+ // EventSource::
+ EventSink* GetEventSink() override;
+
// PlatformDisplay:
void Init(PlatformDisplayDelegate* delegate) override;
- int64_t GetId() const override;
void SetViewportSize(const gfx::Size& size) override;
void SetTitle(const base::string16& title) override;
void SetCapture() override;
void ReleaseCapture() override;
- void SetCursorById(mojom::Cursor cursor) override;
+ void SetCursorById(mojom::CursorType cursor) override;
void UpdateTextInputState(const ui::TextInputState& state) override;
void SetImeVisibility(bool visible) override;
- gfx::Rect GetBounds() const override;
- bool UpdateViewportMetrics(const display::ViewportMetrics& metrics) override;
- const display::ViewportMetrics& GetViewportMetrics() const override;
+ void UpdateViewportMetrics(const display::ViewportMetrics& metrics) override;
gfx::AcceleratedWidget GetAcceleratedWidget() const override;
FrameGenerator* GetFrameGenerator() override;
@@ -68,14 +72,9 @@ class PlatformDisplayDefault : public PlatformDisplay,
void OnAcceleratedWidgetDestroyed() override;
void OnActivationChanged(bool active) override;
- // FrameGeneratorDelegate:
- bool IsInHighContrastMode() override;
-
- const int64_t display_id_;
+ ServerWindow* root_window_;
-#if !defined(OS_ANDROID)
std::unique_ptr<ui::ImageCursors> image_cursors_;
-#endif
PlatformDisplayDelegate* delegate_ = nullptr;
std::unique_ptr<FrameGenerator> frame_generator_;
@@ -83,8 +82,6 @@ class PlatformDisplayDefault : public PlatformDisplay,
display::ViewportMetrics metrics_;
std::unique_ptr<ui::PlatformWindow> platform_window_;
gfx::AcceleratedWidget widget_;
- ServerWindow* root_window_;
- float init_device_scale_factor_;
DISALLOW_COPY_AND_ASSIGN(PlatformDisplayDefault);
};
diff --git a/chromium/services/ui/ws/platform_display_default_unittest.cc b/chromium/services/ui/ws/platform_display_default_unittest.cc
new file mode 100644
index 00000000000..d7e72ffe949
--- /dev/null
+++ b/chromium/services/ui/ws/platform_display_default_unittest.cc
@@ -0,0 +1,153 @@
+// 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/ui/ws/platform_display_default.h"
+
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/base/cursor/image_cursors.h"
+#include "ui/display/types/native_display_delegate.h"
+#include "ui/events/event.h"
+#include "ui/events/event_sink.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/ozone/public/ozone_platform.h"
+#include "ui/ozone/public/system_input_injector.h"
+#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/stub/stub_window.h"
+
+namespace ui {
+namespace ws {
+namespace {
+
+// An EventSink that records events sent to it.
+class TestEventSink : public EventSink {
+ public:
+ TestEventSink() { Reset(); }
+ ~TestEventSink() override = default;
+
+ void Reset() {
+ count_ = 0;
+ last_event_type_ = ET_UNKNOWN;
+ }
+
+ // EventSink:
+ EventDispatchDetails OnEventFromSource(Event* event) override {
+ count_++;
+ last_event_type_ = event->type();
+ return EventDispatchDetails();
+ }
+
+ int count_;
+ EventType last_event_type_;
+};
+
+// A PlatformDisplayDelegate to connect the PlatformDisplay to a TestEventSink.
+class TestPlatformDisplayDelegate : public PlatformDisplayDelegate {
+ public:
+ TestPlatformDisplayDelegate(TestEventSink* sink, OzonePlatform* platform)
+ : event_sink_(sink), ozone_platform_(platform) {}
+ ~TestPlatformDisplayDelegate() override = default;
+
+ // PlatformDisplayDelegate:
+ const display::Display& GetDisplay() override { return stub_display_; }
+ ServerWindow* GetRootWindow() override { return nullptr; }
+ EventSink* GetEventSink() override { return event_sink_; }
+ void OnAcceleratedWidgetAvailable() override {}
+ void OnNativeCaptureLost() override {}
+ OzonePlatform* GetOzonePlatform() override { return ozone_platform_; }
+
+ private:
+ TestEventSink* event_sink_;
+ OzonePlatform* ozone_platform_;
+ display::Display stub_display_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplayDelegate);
+};
+
+// An OzonePlatform that creates StubWindows.
+class TestOzonePlatform : public OzonePlatform {
+ public:
+ TestOzonePlatform() = default;
+ ~TestOzonePlatform() override = default;
+
+ // OzonePlatform:
+ ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override { return nullptr; }
+ ui::OverlayManagerOzone* GetOverlayManager() override { return nullptr; }
+ ui::CursorFactoryOzone* GetCursorFactoryOzone() override { return nullptr; }
+ ui::InputController* GetInputController() override { return nullptr; }
+ ui::GpuPlatformSupportHost* GetGpuPlatformSupportHost() override {
+ return nullptr;
+ }
+ std::unique_ptr<SystemInputInjector> CreateSystemInputInjector() override {
+ return nullptr;
+ }
+ std::unique_ptr<PlatformWindow> CreatePlatformWindow(
+ PlatformWindowDelegate* delegate,
+ const gfx::Rect& bounds) override {
+ return base::MakeUnique<StubWindow>(
+ delegate, false /* use_default_accelerated_widget */);
+ }
+ std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate()
+ override {
+ return nullptr;
+ }
+ void InitializeUI(const InitParams& params) override {}
+ void InitializeGPU(const InitParams& params) override {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestOzonePlatform);
+};
+
+TEST(PlatformDisplayDefaultTest, EventDispatch) {
+ // Setup ozone so the display can be initialized.
+ TestOzonePlatform platform;
+
+ // Create the display.
+ display::ViewportMetrics metrics;
+ metrics.bounds_in_pixels = gfx::Rect(1024, 768);
+ metrics.device_scale_factor = 1.f;
+ metrics.ui_scale_factor = 1.f;
+ PlatformDisplayDefault display(nullptr, metrics,
+ std::unique_ptr<ImageCursors>());
+
+ // Initialize the display with a test EventSink so we can sense events.
+ TestEventSink event_sink;
+ TestPlatformDisplayDelegate delegate(&event_sink, &platform);
+ display.Init(&delegate);
+
+ // Event dispatch is handled at the PlatformWindowDelegate level.
+ PlatformWindowDelegate* display_for_dispatch =
+ static_cast<PlatformWindowDelegate*>(&display);
+
+ // Mouse events are converted to pointer events.
+ MouseEvent mouse(ET_MOUSE_PRESSED, gfx::Point(1, 2), gfx::Point(1, 2),
+ base::TimeTicks(), EF_NONE, 0);
+ display_for_dispatch->DispatchEvent(&mouse);
+ EXPECT_EQ(ET_POINTER_DOWN, event_sink.last_event_type_);
+ event_sink.Reset();
+
+ // Touch events are converted to pointer events.
+ TouchEvent touch(ET_TOUCH_PRESSED, gfx::Point(3, 4), base::TimeTicks(),
+ PointerDetails(EventPointerType::POINTER_TYPE_TOUCH, 0));
+ display_for_dispatch->DispatchEvent(&touch);
+ EXPECT_EQ(ET_POINTER_DOWN, event_sink.last_event_type_);
+ event_sink.Reset();
+
+ // Pressing a key dispatches exactly one event.
+ KeyEvent key_pressed(ET_KEY_PRESSED, VKEY_A, EF_NONE);
+ display_for_dispatch->DispatchEvent(&key_pressed);
+ EXPECT_EQ(1, event_sink.count_);
+ EXPECT_EQ(ET_KEY_PRESSED, event_sink.last_event_type_);
+ event_sink.Reset();
+
+ // Releasing the key dispatches exactly one event.
+ KeyEvent key_released(ET_KEY_RELEASED, VKEY_A, EF_NONE);
+ display_for_dispatch->DispatchEvent(&key_released);
+ EXPECT_EQ(1, event_sink.count_);
+ EXPECT_EQ(ET_KEY_RELEASED, event_sink.last_event_type_);
+}
+
+} // namespace
+} // namespace ws
+} // namespace ui
diff --git a/chromium/services/ui/ws/platform_display_delegate.h b/chromium/services/ui/ws/platform_display_delegate.h
index 0358573ffcf..cc185b9629d 100644
--- a/chromium/services/ui/ws/platform_display_delegate.h
+++ b/chromium/services/ui/ws/platform_display_delegate.h
@@ -11,7 +11,8 @@ class Display;
namespace ui {
-class Event;
+class EventSink;
+class OzonePlatform;
namespace ws {
@@ -23,22 +24,24 @@ class ServerWindow;
class PlatformDisplayDelegate {
public:
// Returns a display::Display for this display.
- virtual display::Display GetDisplay() = 0;
+ virtual const display::Display& GetDisplay() = 0;
// Returns the root window of this display.
virtual ServerWindow* GetRootWindow() = 0;
+ // Returns the event sink of this display;
+ virtual EventSink* GetEventSink() = 0;
+
// Called once when the AcceleratedWidget is available for drawing.
virtual void OnAcceleratedWidgetAvailable() = 0;
- virtual bool IsInHighContrastMode() = 0;
-
- // Called when an event arrives.
- virtual void OnEvent(const ui::Event& event) = 0;
-
// Called when the Display loses capture.
virtual void OnNativeCaptureLost() = 0;
+ // Allows the OzonePlatform to be overridden, e.g. for tests. Returns null
+ // for non-Ozone platforms.
+ virtual OzonePlatform* GetOzonePlatform() = 0;
+
protected:
virtual ~PlatformDisplayDelegate() {}
};
diff --git a/chromium/services/ui/ws/platform_display_factory.h b/chromium/services/ui/ws/platform_display_factory.h
index e0f1be93d70..99e17af3e84 100644
--- a/chromium/services/ui/ws/platform_display_factory.h
+++ b/chromium/services/ui/ws/platform_display_factory.h
@@ -7,18 +7,23 @@
#include <memory>
+namespace display {
+struct ViewportMetrics;
+}
+
namespace ui {
namespace ws {
class PlatformDisplay;
-struct PlatformDisplayInitParams;
+class ServerWindow;
// Abstract factory for PlatformDisplays. Used by tests to construct test
// PlatformDisplays.
class PlatformDisplayFactory {
public:
virtual std::unique_ptr<PlatformDisplay> CreatePlatformDisplay(
- const PlatformDisplayInitParams& init_params) = 0;
+ ServerWindow* root_window,
+ const display::ViewportMetrics& metrics) = 0;
};
} // namespace ws
diff --git a/chromium/services/ui/ws/platform_display_init_params.cc b/chromium/services/ui/ws/platform_display_init_params.cc
deleted file mode 100644
index f8e871c0136..00000000000
--- a/chromium/services/ui/ws/platform_display_init_params.cc
+++ /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.
-
-#include "services/ui/ws/platform_display_init_params.h"
-
-#include "services/ui/ws/server_window.h"
-#include "ui/display/types/display_constants.h"
-
-namespace ui {
-namespace ws {
-
-PlatformDisplayInitParams::PlatformDisplayInitParams()
- : display_id(display::kInvalidDisplayId) {}
-
-PlatformDisplayInitParams::PlatformDisplayInitParams(
- const PlatformDisplayInitParams& other) = default;
-
-PlatformDisplayInitParams::~PlatformDisplayInitParams() {}
-
-} // namespace ws
-} // namespace ui
diff --git a/chromium/services/ui/ws/platform_display_init_params.h b/chromium/services/ui/ws/platform_display_init_params.h
deleted file mode 100644
index 0e93d1fb9c2..00000000000
--- a/chromium/services/ui/ws/platform_display_init_params.h
+++ /dev/null
@@ -1,32 +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_PLATFORM_DISPLAY_INIT_PARAMS_H_
-#define SERVICES_UI_WS_PLATFORM_DISPLAY_INIT_PARAMS_H_
-
-#include <stdint.h>
-
-#include "base/memory/ref_counted.h"
-#include "services/ui/display/viewport_metrics.h"
-
-namespace ui {
-
-namespace ws {
-
-class ServerWindow;
-
-struct PlatformDisplayInitParams {
- PlatformDisplayInitParams();
- PlatformDisplayInitParams(const PlatformDisplayInitParams& other);
- ~PlatformDisplayInitParams();
-
- int64_t display_id;
- ServerWindow* root_window = nullptr;
- display::ViewportMetrics metrics;
-};
-
-} // namespace ws
-} // namespace ui
-
-#endif // SERVICES_UI_WS_PLATFORM_DISPLAY_INIT_PARAMS_H_
diff --git a/chromium/services/ui/ws/server_window.cc b/chromium/services/ui/ws/server_window.cc
index 42bdcabe12d..ca67227dfad 100644
--- a/chromium/services/ui/ws/server_window.cc
+++ b/chromium/services/ui/ws/server_window.cc
@@ -30,12 +30,12 @@ ServerWindow::ServerWindow(ServerWindowDelegate* delegate,
parent_(nullptr),
stacking_target_(nullptr),
transient_parent_(nullptr),
- is_modal_(false),
+ modal_type_(MODAL_TYPE_NONE),
visible_(false),
// Default to POINTER as CURSOR_NULL doesn't change the cursor, it leaves
// the last non-null cursor.
- cursor_id_(mojom::Cursor::POINTER),
- non_client_cursor_id_(mojom::Cursor::POINTER),
+ cursor_id_(mojom::CursorType::POINTER),
+ non_client_cursor_id_(mojom::CursorType::POINTER),
opacity_(1),
can_focus_(true),
properties_(properties),
@@ -172,13 +172,16 @@ void ServerWindow::StackChildAtTop(ServerWindow* child) {
child->Reorder(children_.back(), mojom::OrderDirection::ABOVE);
}
-void ServerWindow::SetBounds(const gfx::Rect& bounds) {
- if (bounds_ == bounds)
+void ServerWindow::SetBounds(
+ const gfx::Rect& bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) {
+ if (bounds_ == bounds && current_local_surface_id_ == local_surface_id)
return;
- // TODO(fsamuel): figure out how will this work with CompositorFrames.
-
const gfx::Rect old_bounds = bounds_;
+
+ current_local_surface_id_ = local_surface_id;
+
bounds_ = bounds;
for (auto& observer : observers_)
observer.OnWindowBoundsChanged(this, old_bounds, bounds);
@@ -228,10 +231,6 @@ ServerWindow* ServerWindow::GetChildWindow(const WindowId& window_id) {
}
bool ServerWindow::AddTransientWindow(ServerWindow* child) {
- // A system modal window cannot become a transient child.
- if (child->is_modal() && !child->transient_parent())
- return false;
-
if (child->transient_parent())
child->transient_parent()->RemoveTransientWindow(child);
@@ -268,8 +267,8 @@ void ServerWindow::RemoveTransientWindow(ServerWindow* child) {
observer.OnTransientWindowRemoved(this, child);
}
-void ServerWindow::SetModal() {
- is_modal_ = true;
+void ServerWindow::SetModalType(ModalType modal_type) {
+ modal_type_ = modal_type;
}
bool ServerWindow::Contains(const ServerWindow* window) const {
@@ -300,7 +299,7 @@ void ServerWindow::SetOpacity(float value) {
observer.OnWindowOpacityChanged(this, old_opacity, opacity_);
}
-void ServerWindow::SetPredefinedCursor(ui::mojom::Cursor value) {
+void ServerWindow::SetPredefinedCursor(ui::mojom::CursorType value) {
if (value == cursor_id_)
return;
cursor_id_ = value;
@@ -308,7 +307,7 @@ void ServerWindow::SetPredefinedCursor(ui::mojom::Cursor value) {
observer.OnWindowPredefinedCursorChanged(this, value);
}
-void ServerWindow::SetNonClientCursor(ui::mojom::Cursor value) {
+void ServerWindow::SetNonClientCursor(ui::mojom::CursorType value) {
if (value == non_client_cursor_id_)
return;
non_client_cursor_id_ = value;
diff --git a/chromium/services/ui/ws/server_window.h b/chromium/services/ui/ws/server_window.h
index c600aa73401..3a7fa5a5ec4 100644
--- a/chromium/services/ui/ws/server_window.h
+++ b/chromium/services/ui/ws/server_window.h
@@ -14,7 +14,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/observer_list.h"
-#include "cc/ipc/display_compositor.mojom.h"
+#include "cc/ipc/frame_sink_manager.mojom.h"
#include "cc/ipc/mojo_compositor_frame_sink.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
@@ -74,6 +74,10 @@ class ServerWindow {
const cc::FrameSinkId& frame_sink_id() const { return frame_sink_id_; }
+ const base::Optional<cc::LocalSurfaceId>& current_local_surface_id() const {
+ return current_local_surface_id_;
+ }
+
void Add(ServerWindow* child);
void Remove(ServerWindow* child);
void Reorder(ServerWindow* relative, mojom::OrderDirection diretion);
@@ -83,7 +87,9 @@ class ServerWindow {
const gfx::Rect& bounds() const { return bounds_; }
// Sets the bounds. If the size changes this implicitly resets the client
// area to fill the whole bounds.
- void SetBounds(const gfx::Rect& bounds);
+ void SetBounds(const gfx::Rect& bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id =
+ base::nullopt);
const std::vector<gfx::Rect>& additional_client_areas() const {
return additional_client_areas_;
@@ -99,8 +105,8 @@ class ServerWindow {
bool can_accept_drops() const { return accepts_drops_; }
void SetCanAcceptDrops(bool accepts_drags);
- ui::mojom::Cursor cursor() const { return cursor_id_; }
- ui::mojom::Cursor non_client_cursor() const {
+ ui::mojom::CursorType cursor() const { return cursor_id_; }
+ ui::mojom::CursorType non_client_cursor() const {
return non_client_cursor_id_;
}
@@ -131,8 +137,8 @@ class ServerWindow {
const Windows& transient_children() const { return transient_children_; }
- bool is_modal() const { return is_modal_; }
- void SetModal();
+ ModalType modal_type() const { return modal_type_; }
+ void SetModalType(ModalType modal_type);
// Returns true if this contains |window| or is |window|.
bool Contains(const ServerWindow* window) const;
@@ -145,8 +151,8 @@ class ServerWindow {
float opacity() const { return opacity_; }
void SetOpacity(float value);
- void SetPredefinedCursor(ui::mojom::Cursor cursor_id);
- void SetNonClientCursor(ui::mojom::Cursor cursor_id);
+ void SetPredefinedCursor(ui::mojom::CursorType cursor_id);
+ void SetNonClientCursor(ui::mojom::CursorType cursor_id);
const gfx::Transform& transform() const { return transform_; }
void SetTransform(const gfx::Transform& transform);
@@ -227,6 +233,8 @@ class ServerWindow {
ServerWindowDelegate* delegate_;
const WindowId id_;
cc::FrameSinkId frame_sink_id_;
+ base::Optional<cc::LocalSurfaceId> current_local_surface_id_;
+
ServerWindow* parent_;
Windows children_;
@@ -237,15 +245,15 @@ class ServerWindow {
ServerWindow* transient_parent_;
Windows transient_children_;
- bool is_modal_;
+ ModalType modal_type_;
bool visible_;
gfx::Rect bounds_;
gfx::Insets client_area_;
std::vector<gfx::Rect> additional_client_areas_;
std::unique_ptr<ServerWindowCompositorFrameSinkManager>
compositor_frame_sink_manager_;
- mojom::Cursor cursor_id_;
- mojom::Cursor non_client_cursor_id_;
+ mojom::CursorType cursor_id_;
+ mojom::CursorType non_client_cursor_id_;
float opacity_;
bool can_focus_;
mojom::EventTargetingPolicy event_targeting_policy_ =
diff --git a/chromium/services/ui/ws/server_window_compositor_frame_sink_manager.cc b/chromium/services/ui/ws/server_window_compositor_frame_sink_manager.cc
index 6c72261ef36..94ab45b5303 100644
--- a/chromium/services/ui/ws/server_window_compositor_frame_sink_manager.cc
+++ b/chromium/services/ui/ws/server_window_compositor_frame_sink_manager.cc
@@ -6,7 +6,6 @@
#include <utility>
-#include "cc/ipc/display_compositor.mojom.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/ui/ws/ids.h"
#include "services/ui/ws/server_window.h"
@@ -36,7 +35,7 @@ void ServerWindowCompositorFrameSinkManager::CreateRootCompositorFrameSink(
// TODO(fsamuel): AcceleratedWidget cannot be transported over IPC for Mac
// or Android. We should instead use GpuSurfaceTracker here on those
// platforms.
- window_->delegate()->GetDisplayCompositor()->CreateRootCompositorFrameSink(
+ window_->delegate()->GetFrameSinkManager()->CreateRootCompositorFrameSink(
window_->frame_sink_id(), widget, std::move(sink_request),
std::move(pending_compositor_frame_sink_request_), std::move(client),
std::move(display_request));
@@ -50,7 +49,7 @@ void ServerWindowCompositorFrameSinkManager::CreateCompositorFrameSink(
mojo::MakeRequest(&compositor_frame_sink_);
}
- window_->delegate()->GetDisplayCompositor()->CreateCompositorFrameSink(
+ window_->delegate()->GetFrameSinkManager()->CreateCompositorFrameSink(
window_->frame_sink_id(), std::move(request),
std::move(pending_compositor_frame_sink_request_), std::move(client));
}
diff --git a/chromium/services/ui/ws/server_window_compositor_frame_sink_manager.h b/chromium/services/ui/ws/server_window_compositor_frame_sink_manager.h
index fbd5483e975..7da79d2404f 100644
--- a/chromium/services/ui/ws/server_window_compositor_frame_sink_manager.h
+++ b/chromium/services/ui/ws/server_window_compositor_frame_sink_manager.h
@@ -7,7 +7,7 @@
#include "base/macros.h"
#include "cc/ipc/compositor_frame.mojom.h"
-#include "cc/ipc/display_compositor.mojom.h"
+#include "cc/ipc/frame_sink_manager.mojom.h"
#include "cc/output/context_provider.h"
#include "cc/surfaces/surface_id.h"
#include "mojo/public/cpp/bindings/binding.h"
diff --git a/chromium/services/ui/ws/server_window_delegate.h b/chromium/services/ui/ws/server_window_delegate.h
index 8caf5bf0b90..d9ed330aae7 100644
--- a/chromium/services/ui/ws/server_window_delegate.h
+++ b/chromium/services/ui/ws/server_window_delegate.h
@@ -7,10 +7,15 @@
#include <memory>
-#include "cc/ipc/display_compositor.mojom.h"
#include "services/ui/public/interfaces/mus_constants.mojom.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
+namespace cc {
+namespace mojom {
+class FrameSinkManager;
+}
+}
+
namespace ui {
namespace ws {
@@ -19,9 +24,9 @@ class ServerWindow;
class ServerWindowDelegate {
public:
- // Returns a display compositor interface pointer. There is only one
- // DisplayCompositor running in the system.
- virtual cc::mojom::DisplayCompositor* GetDisplayCompositor() = 0;
+ // Returns a frame sink manager interface pointer. There is only one
+ // MojoFrameSinkManager running in the system.
+ virtual cc::mojom::FrameSinkManager* GetFrameSinkManager() = 0;
// Returns the root of the window tree to which this |window| is attached.
// Returns null if this window is not attached up through to a root window.
diff --git a/chromium/services/ui/ws/server_window_observer.h b/chromium/services/ui/ws/server_window_observer.h
index f57f0df24df..265c408b5a4 100644
--- a/chromium/services/ui/ws/server_window_observer.h
+++ b/chromium/services/ui/ws/server_window_observer.h
@@ -10,7 +10,7 @@
#include <string>
#include <vector>
-#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/public/interfaces/mus_constants.mojom.h"
namespace gfx {
@@ -67,9 +67,9 @@ class ServerWindowObserver {
float new_opacity) {}
virtual void OnWindowPredefinedCursorChanged(ServerWindow* window,
- mojom::Cursor cursor_id) {}
+ mojom::CursorType cursor_id) {}
virtual void OnWindowNonClientCursorChanged(ServerWindow* window,
- mojom::Cursor cursor_id) {}
+ mojom::CursorType cursor_id) {}
virtual void OnWindowTextInputStateChanged(ServerWindow* window,
const ui::TextInputState& state) {}
diff --git a/chromium/services/ui/ws/test_change_tracker.cc b/chromium/services/ui/ws/test_change_tracker.cc
index eb393854da0..b27d565518c 100644
--- a/chromium/services/ui/ws/test_change_tracker.cc
+++ b/chromium/services/ui/ws/test_change_tracker.cc
@@ -37,7 +37,8 @@ std::string ChangeToDescription(const Change& change,
case CHANGE_TYPE_EMBED:
if (type == ChangeDescriptionType::ONE)
return "OnEmbed";
- return base::StringPrintf("OnEmbed drawn=%s",
+ return base::StringPrintf("OnEmbed %s drawn=%s",
+ change.frame_sink_id.ToString().c_str(),
change.bool_value ? "true" : "false");
case CHANGE_TYPE_EMBEDDED_APP_DISCONNECTED:
@@ -53,6 +54,11 @@ std::string ChangeToDescription(const Change& change,
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(),
@@ -60,9 +66,12 @@ std::string ChangeToDescription(const Change& change,
case CHANGE_TYPE_NODE_BOUNDS_CHANGED:
return base::StringPrintf(
- "BoundsChanged window=%s old_bounds=%s new_bounds=%s",
+ "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.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(
@@ -131,10 +140,11 @@ std::string ChangeToDescription(const Change& change,
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");
+ return base::StringPrintf(
+ "TopLevelCreated id=%d %s window_id=%s drawn=%s", change.change_id,
+ change.frame_sink_id.ToString().c_str(),
+ 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(),
@@ -233,11 +243,13 @@ TestChangeTracker::~TestChangeTracker() {}
void TestChangeTracker::OnEmbed(ClientSpecificId client_id,
mojom::WindowDataPtr root,
- bool drawn) {
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id) {
Change change;
change.type = CHANGE_TYPE_EMBED;
change.client_id = client_id;
change.bool_value = drawn;
+ change.frame_sink_id = frame_sink_id;
change.windows.push_back(WindowDataToTestWindow(root));
AddChange(change);
}
@@ -249,14 +261,17 @@ void TestChangeTracker::OnEmbeddedAppDisconnected(Id window_id) {
AddChange(change);
}
-void TestChangeTracker::OnWindowBoundsChanged(Id window_id,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
+void TestChangeTracker::OnWindowBoundsChanged(
+ Id window_id,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<cc::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);
}
@@ -294,6 +309,16 @@ void TestChangeTracker::OnCaptureChanged(Id new_capture_window_id,
AddChange(change);
}
+void TestChangeTracker::OnFrameSinkIdAllocated(
+ Id window_id,
+ const cc::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,
@@ -359,6 +384,8 @@ void TestChangeTracker::OnWindowInputEvent(Id window_id,
change.window_id = window_id;
change.event_action = static_cast<int32_t>(event.type());
change.matches_pointer_watcher = matches_pointer_watcher;
+ if (event.IsKeyEvent() && event.AsKeyEvent()->properties())
+ change.key_event_properties = *event.AsKeyEvent()->properties();
AddChange(change);
}
@@ -395,7 +422,7 @@ void TestChangeTracker::OnWindowFocused(Id window_id) {
void TestChangeTracker::OnWindowPredefinedCursorChanged(
Id window_id,
- mojom::Cursor cursor_id) {
+ mojom::CursorType cursor_id) {
Change change;
change.type = CHANGE_TYPE_CURSOR_CHANGED;
change.window_id = window_id;
@@ -411,14 +438,17 @@ void TestChangeTracker::OnChangeCompleted(uint32_t change_id, bool success) {
AddChange(change);
}
-void TestChangeTracker::OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr window_data,
- bool drawn) {
+void TestChangeTracker::OnTopLevelCreated(
+ uint32_t change_id,
+ mojom::WindowDataPtr window_data,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id) {
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;
+ change.frame_sink_id = frame_sink_id;
AddChange(change);
}
diff --git a/chromium/services/ui/ws/test_change_tracker.h b/chromium/services/ui/ws/test_change_tracker.h
index 7158f5102ec..98f259f3549 100644
--- a/chromium/services/ui/ws/test_change_tracker.h
+++ b/chromium/services/ui/ws/test_change_tracker.h
@@ -8,6 +8,7 @@
#include <stdint.h>
#include <string>
+#include <unordered_map>
#include <vector>
#include "base/macros.h"
@@ -21,6 +22,7 @@ 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,
@@ -77,6 +79,8 @@ struct Change {
Id window_id3;
gfx::Rect bounds;
gfx::Rect bounds2;
+ cc::FrameSinkId frame_sink_id;
+ base::Optional<cc::LocalSurfaceId> local_surface_id;
int32_t event_action;
bool matches_pointer_watcher;
std::string embed_url;
@@ -90,6 +94,8 @@ struct Change {
cc::SurfaceId surface_id;
gfx::Size frame_size;
float device_scale_factor;
+ // Set in OnWindowInputEvent() if the event is a KeyEvent.
+ std::unordered_map<std::string, std::vector<uint8_t>> key_event_properties;
};
// Converts Changes to string descriptions.
@@ -138,15 +144,20 @@ class TestChangeTracker {
// WindowTreeClient function.
void OnEmbed(ClientSpecificId client_id,
mojom::WindowDataPtr root,
- bool drawn);
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id);
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 cc::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);
+ void OnWindowBoundsChanged(
+ Id window_id,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id);
void OnWindowHierarchyChanged(Id window_id,
Id old_parent_id,
Id new_parent_id,
@@ -168,11 +179,13 @@ class TestChangeTracker {
const std::string& name,
const base::Optional<std::vector<uint8_t>>& data);
void OnWindowFocused(Id window_id);
- void OnWindowPredefinedCursorChanged(Id window_id, mojom::Cursor cursor_id);
+ void OnWindowPredefinedCursorChanged(Id window_id,
+ mojom::CursorType cursor_id);
void OnChangeCompleted(uint32_t change_id, bool success);
void OnTopLevelCreated(uint32_t change_id,
mojom::WindowDataPtr window_data,
- bool drawn);
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id);
void OnWindowSurfaceChanged(Id window_id,
const cc::SurfaceInfo& surface_info);
diff --git a/chromium/services/ui/ws/test_server_window_delegate.cc b/chromium/services/ui/ws/test_server_window_delegate.cc
index 32cd20306e3..db8560c6817 100644
--- a/chromium/services/ui/ws/test_server_window_delegate.cc
+++ b/chromium/services/ui/ws/test_server_window_delegate.cc
@@ -13,7 +13,7 @@ TestServerWindowDelegate::TestServerWindowDelegate() {}
TestServerWindowDelegate::~TestServerWindowDelegate() {}
-cc::mojom::DisplayCompositor* TestServerWindowDelegate::GetDisplayCompositor() {
+cc::mojom::FrameSinkManager* TestServerWindowDelegate::GetFrameSinkManager() {
return nullptr;
}
diff --git a/chromium/services/ui/ws/test_server_window_delegate.h b/chromium/services/ui/ws/test_server_window_delegate.h
index 8ef89a7aa47..9bb538b646b 100644
--- a/chromium/services/ui/ws/test_server_window_delegate.h
+++ b/chromium/services/ui/ws/test_server_window_delegate.h
@@ -8,12 +8,6 @@
#include "base/macros.h"
#include "services/ui/ws/server_window_delegate.h"
-namespace cc {
-namespace mojom {
-class DisplayCompositor;
-}
-}
-
namespace ui {
namespace ws {
@@ -26,7 +20,7 @@ class TestServerWindowDelegate : public ServerWindowDelegate {
private:
// ServerWindowDelegate:
- cc::mojom::DisplayCompositor* GetDisplayCompositor() override;
+ cc::mojom::FrameSinkManager* GetFrameSinkManager() override;
ServerWindow* GetRootWindow(const ServerWindow* window) override;
ServerWindow* root_window_ = nullptr;
diff --git a/chromium/services/ui/ws/test_utils.cc b/chromium/services/ui/ws/test_utils.cc
index 23d10b7ae96..50cbcd27916 100644
--- a/chromium/services/ui/ws/test_utils.cc
+++ b/chromium/services/ui/ws/test_utils.cc
@@ -10,10 +10,9 @@
#include "cc/output/copy_output_request.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "services/service_manager/public/interfaces/connector.mojom.h"
-#include "services/ui/public/interfaces/cursor.mojom.h"
+#include "services/ui/public/interfaces/cursor/cursor.mojom.h"
#include "services/ui/ws/display_binding.h"
#include "services/ui/ws/display_manager.h"
-#include "services/ui/ws/platform_display_init_params.h"
#include "services/ui/ws/window_manager_access_policy.h"
#include "services/ui/ws/window_manager_window_tree_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -28,49 +27,36 @@ namespace {
// Empty implementation of PlatformDisplay.
class TestPlatformDisplay : public PlatformDisplay {
public:
- explicit TestPlatformDisplay(const PlatformDisplayInitParams& params,
- mojom::Cursor* cursor_storage)
- : id_(params.display_id),
- display_metrics_(params.metrics),
- cursor_storage_(cursor_storage) {
- display_metrics_.bounds = gfx::Rect(0, 0, 400, 300);
- display_metrics_.device_scale_factor = 1.f;
- }
+ explicit TestPlatformDisplay(const display::ViewportMetrics& metrics,
+ mojom::CursorType* cursor_storage)
+ : metrics_(metrics), cursor_storage_(cursor_storage) {}
~TestPlatformDisplay() override {}
// PlatformDisplay:
void Init(PlatformDisplayDelegate* delegate) override {
delegate->OnAcceleratedWidgetAvailable();
}
- int64_t GetId() const override { return id_; }
void SetViewportSize(const gfx::Size& size) override {}
void SetTitle(const base::string16& title) override {}
void SetCapture() override {}
void ReleaseCapture() override {}
- void SetCursorById(mojom::Cursor cursor) override {
+ void SetCursorById(mojom::CursorType cursor) override {
*cursor_storage_ = cursor;
}
void UpdateTextInputState(const ui::TextInputState& state) override {}
void SetImeVisibility(bool visible) override {}
- gfx::Rect GetBounds() const override { return display_metrics_.bounds; }
- bool UpdateViewportMetrics(const display::ViewportMetrics& metrics) override {
- if (display_metrics_ == metrics)
- return false;
- display_metrics_ = metrics;
- return true;
- }
- const display::ViewportMetrics& GetViewportMetrics() const override {
- return display_metrics_;
+ void UpdateViewportMetrics(const display::ViewportMetrics& metrics) override {
+ metrics_ = metrics;
}
gfx::AcceleratedWidget GetAcceleratedWidget() const override {
return gfx::kNullAcceleratedWidget;
}
FrameGenerator* GetFrameGenerator() override { return nullptr; }
+ EventSink* GetEventSink() override { return nullptr; }
private:
- const int64_t id_;
- display::ViewportMetrics display_metrics_;
- mojom::Cursor* cursor_storage_;
+ display::ViewportMetrics metrics_;
+ mojom::CursorType* cursor_storage_;
DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplay);
};
@@ -86,16 +72,14 @@ ClientWindowId NextUnusedClientWindowId(WindowTree* tree) {
}
}
-// Creates a Display with |id| and same attributes as |metrics|.
-display::Display CreateDisplay(int64_t id,
- const display::ViewportMetrics& metrics) {
- display::Display display(id);
- display.set_bounds(metrics.bounds);
- display.set_work_area(metrics.work_area);
- display.set_device_scale_factor(metrics.device_scale_factor);
- display.set_rotation(metrics.rotation);
- display.set_touch_support(metrics.touch_support);
- return display;
+display::ViewportMetrics MakeViewportMetrics(const display::Display& display) {
+ gfx::Size pixel_size = gfx::ConvertSizeToPixel(display.device_scale_factor(),
+ display.bounds().size());
+
+ display::ViewportMetrics metrics;
+ metrics.bounds_in_pixels.set_size(pixel_size);
+ metrics.device_scale_factor = display.device_scale_factor();
+ return metrics;
}
} // namespace
@@ -109,21 +93,25 @@ TestScreenManager::~TestScreenManager() {
}
int64_t TestScreenManager::AddDisplay() {
- return AddDisplay(MakeViewportMetrics(0, 0, 100, 100, 1.0f));
+ return AddDisplay(
+ display::Display(display::kInvalidDisplayId, gfx::Rect(100, 100)));
}
-int64_t TestScreenManager::AddDisplay(const display::ViewportMetrics& metrics) {
+int64_t TestScreenManager::AddDisplay(const display::Display& input_display) {
// Generate a unique display id.
int64_t display_id = display_ids_.empty() ? 1 : *display_ids_.rbegin() + 1;
display_ids_.insert(display_id);
+ display::Display display = input_display;
+ display.set_id(display_id);
+
// First display added will be the primary display.
display::DisplayList::Type type = display::DisplayList::Type::NOT_PRIMARY;
if (display_ids_.size() == 1)
type = display::DisplayList::Type::PRIMARY;
- screen_->display_list().AddDisplay(CreateDisplay(display_id, metrics), type);
- delegate_->OnDisplayAdded(display_id, metrics);
+ screen_->display_list().AddDisplay(display, type);
+ delegate_->OnDisplayAdded(display, MakeViewportMetrics(display));
if (type == display::DisplayList::Type::PRIMARY)
delegate_->OnPrimaryDisplayChanged(display_id);
@@ -131,11 +119,10 @@ int64_t TestScreenManager::AddDisplay(const display::ViewportMetrics& metrics) {
return display_id;
}
-void TestScreenManager::ModifyDisplay(int64_t display_id,
- const display::ViewportMetrics& metrics) {
- DCHECK(display_ids_.count(display_id) == 1);
- screen_->display_list().UpdateDisplay(CreateDisplay(display_id, metrics));
- delegate_->OnDisplayModified(display_id, metrics);
+void TestScreenManager::ModifyDisplay(const display::Display& display) {
+ DCHECK(display_ids_.count(display.id()) == 1);
+ screen_->display_list().UpdateDisplay(display);
+ delegate_->OnDisplayModified(display, MakeViewportMetrics(display));
}
void TestScreenManager::RemoveDisplay(int64_t display_id) {
@@ -158,25 +145,16 @@ void TestScreenManager::Init(display::ScreenManagerDelegate* delegate) {
// TestPlatformDisplayFactory -------------------------------------------------
TestPlatformDisplayFactory::TestPlatformDisplayFactory(
- mojom::Cursor* cursor_storage)
+ mojom::CursorType* cursor_storage)
: cursor_storage_(cursor_storage) {}
TestPlatformDisplayFactory::~TestPlatformDisplayFactory() {}
std::unique_ptr<PlatformDisplay>
TestPlatformDisplayFactory::CreatePlatformDisplay(
- const PlatformDisplayInitParams& init_params) {
- return base::MakeUnique<TestPlatformDisplay>(init_params, cursor_storage_);
-}
-
-// TestFrameGeneratorDelegate -------------------------------------------------
-
-TestFrameGeneratorDelegate::TestFrameGeneratorDelegate() {}
-
-TestFrameGeneratorDelegate::~TestFrameGeneratorDelegate() {}
-
-bool TestFrameGeneratorDelegate::IsInHighContrastMode() {
- return false;
+ ServerWindow* root_window,
+ const display::ViewportMetrics& metrics) {
+ return base::MakeUnique<TestPlatformDisplay>(metrics, cursor_storage_);
}
// WindowTreeTestApi ---------------------------------------------------------
@@ -225,17 +203,38 @@ WindowTree* TestDisplayBinding::CreateWindowTree(ServerWindow* root) {
root, service_manager::mojom::kRootUserID,
ui::mojom::WindowTreeClientPtr(), embed_flags,
base::WrapUnique(new WindowManagerAccessPolicy));
- tree->ConfigureWindowManager();
+ tree->ConfigureWindowManager(automatically_create_display_roots_);
return tree;
}
// TestWindowManager ----------------------------------------------------------
+TestWindowManager::TestWindowManager() {}
+
+TestWindowManager::~TestWindowManager() {}
+
+void TestWindowManager::OnConnect(uint16_t client_id) {
+ connect_count_++;
+}
+
+void TestWindowManager::WmNewDisplayAdded(
+ const display::Display& display,
+ ui::mojom::WindowDataPtr root,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) {
+ display_added_count_++;
+}
+
void TestWindowManager::WmDisplayRemoved(int64_t display_id) {
got_display_removed_ = true;
display_removed_id_ = display_id;
}
+void TestWindowManager::WmSetModalType(uint32_t window_id, ui::ModalType type) {
+ on_set_modal_type_called_ = true;
+}
+
void TestWindowManager::WmCreateTopLevelWindow(
uint32_t change_id,
ClientSpecificId requesting_client_id,
@@ -247,6 +246,19 @@ void TestWindowManager::WmCreateTopLevelWindow(
void TestWindowManager::WmClientJankinessChanged(ClientSpecificId client_id,
bool janky) {}
+void TestWindowManager::WmBuildDragImage(const gfx::Point& screen_location,
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ ui::mojom::PointerKind source) {}
+
+void TestWindowManager::WmMoveDragImage(
+ const gfx::Point& screen_location,
+ const WmMoveDragImageCallback& callback) {
+ callback.Run();
+}
+
+void TestWindowManager::WmDestroyDragImage() {}
+
void TestWindowManager::WmPerformMoveLoop(uint32_t change_id,
uint32_t window_id,
mojom::MoveLoopSource source,
@@ -282,14 +294,17 @@ void TestWindowTreeClient::Bind(
binding_.Bind(std::move(request));
}
-void TestWindowTreeClient::OnEmbed(uint16_t client_id,
- mojom::WindowDataPtr root,
- ui::mojom::WindowTreePtr tree,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) {
+void TestWindowTreeClient::OnEmbed(
+ uint16_t client_id,
+ mojom::WindowDataPtr root,
+ ui::mojom::WindowTreePtr tree,
+ int64_t display_id,
+ Id focused_window_id,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) {
// TODO(sky): add test coverage of |focused_window_id|.
- tracker_.OnEmbed(client_id, std::move(root), drawn);
+ tracker_.OnEmbed(client_id, std::move(root), drawn, frame_sink_id);
}
void TestWindowTreeClient::OnEmbeddedAppDisconnected(uint32_t window) {
@@ -305,18 +320,29 @@ void TestWindowTreeClient::OnCaptureChanged(Id new_capture_window_id,
tracker_.OnCaptureChanged(new_capture_window_id, old_capture_window_id);
}
-void TestWindowTreeClient::OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr data,
- int64_t display_id,
- bool drawn) {
- tracker_.OnTopLevelCreated(change_id, std::move(data), drawn);
+void TestWindowTreeClient::OnFrameSinkIdAllocated(
+ Id window_id,
+ const cc::FrameSinkId& frame_sink_id) {
+ tracker_.OnFrameSinkIdAllocated(window_id, frame_sink_id);
}
-void TestWindowTreeClient::OnWindowBoundsChanged(uint32_t window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
+void TestWindowTreeClient::OnTopLevelCreated(
+ uint32_t change_id,
+ mojom::WindowDataPtr data,
+ int64_t display_id,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) {
+ tracker_.OnTopLevelCreated(change_id, std::move(data), drawn, frame_sink_id);
+}
+
+void TestWindowTreeClient::OnWindowBoundsChanged(
+ uint32_t window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) {
tracker_.OnWindowBoundsChanged(window, std::move(old_bounds),
- std::move(new_bounds));
+ std::move(new_bounds), local_surface_id);
}
void TestWindowTreeClient::OnClientAreaChanged(
@@ -395,7 +421,7 @@ void TestWindowTreeClient::OnWindowFocused(uint32_t focused_window_id) {
void TestWindowTreeClient::OnWindowPredefinedCursorChanged(
uint32_t window_id,
- mojom::Cursor cursor_id) {
+ mojom::CursorType cursor_id) {
tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id);
}
@@ -500,7 +526,7 @@ bool TestWindowServerDelegate::IsTestConfig() const {
// WindowServerTestHelper ---------------------------------------------------
WindowServerTestHelper::WindowServerTestHelper()
- : cursor_id_(mojom::Cursor::CURSOR_NULL),
+ : cursor_id_(mojom::CursorType::CURSOR_NULL),
platform_display_factory_(&cursor_id_) {
// Some tests create their own message loop, for example to add a task runner.
if (!base::MessageLoop::current())
@@ -517,10 +543,12 @@ WindowServerTestHelper::~WindowServerTestHelper() {
// WindowEventTargetingHelper ------------------------------------------------
-WindowEventTargetingHelper::WindowEventTargetingHelper() {
+WindowEventTargetingHelper::WindowEventTargetingHelper(
+ bool automatically_create_display_roots) {
display_ = new Display(window_server());
- display_binding_ = new TestDisplayBinding(window_server());
- display_->Init(PlatformDisplayInitParams(),
+ display_binding_ = new TestDisplayBinding(window_server(),
+ automatically_create_display_roots);
+ display_->Init(display::ViewportMetrics(),
base::WrapUnique(display_binding_));
wm_client_ = ws_test_helper_.window_server_delegate()->last_client();
wm_client_->tracker()->changes()->clear();
@@ -537,7 +565,7 @@ ServerWindow* WindowEventTargetingHelper::CreatePrimaryTree(
EXPECT_TRUE(wm_tree->NewWindow(embed_window_id, ServerWindow::Properties()));
EXPECT_TRUE(wm_tree->SetWindowVisibility(embed_window_id, true));
EXPECT_TRUE(wm_tree->AddWindow(FirstRootId(wm_tree), embed_window_id));
- display_->root_window()->SetBounds(root_window_bounds);
+ display_->root_window()->SetBounds(root_window_bounds, base::nullopt);
mojom::WindowTreeClientPtr client;
mojom::WindowTreeClientRequest client_request(&client);
ws_test_helper_.window_server_delegate()->last_client()->Bind(
@@ -552,7 +580,7 @@ ServerWindow* WindowEventTargetingHelper::CreatePrimaryTree(
EXPECT_NE(tree1, wm_tree);
WindowTreeTestApi(tree1).set_user_id(wm_tree->user_id());
- embed_window->SetBounds(window_bounds);
+ embed_window->SetBounds(window_bounds, base::nullopt);
return embed_window;
}
@@ -575,7 +603,7 @@ void WindowEventTargetingHelper::CreateSecondaryTree(
tree1->GetDisplay(embed_window)->AddActivationParent(embed_window);
child1->SetVisible(true);
- child1->SetBounds(window_bounds);
+ child1->SetBounds(window_bounds, base::nullopt);
TestWindowTreeClient* embed_client =
ws_test_helper_.window_server_delegate()->last_client();
@@ -594,25 +622,28 @@ void WindowEventTargetingHelper::SetTaskRunner(
// ----------------------------------------------------------------------------
-void AddWindowManager(WindowServer* window_server, const UserId& user_id) {
+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);
+ ->CreateWindowTree(nullptr, nullptr, automatically_create_display_roots);
}
-display::ViewportMetrics MakeViewportMetrics(int origin_x,
- int origin_y,
- int width_pixels,
- int height_pixels,
- float scale_factor) {
- display::ViewportMetrics metrics;
+display::Display MakeDisplay(int origin_x,
+ int origin_y,
+ int width_pixels,
+ int height_pixels,
+ float scale_factor) {
gfx::Size scaled_size = gfx::ConvertSizeToDIP(
scale_factor, gfx::Size(width_pixels, height_pixels));
- metrics.bounds = gfx::Rect(gfx::Point(origin_x, origin_y), scaled_size);
- metrics.work_area = metrics.bounds;
- metrics.pixel_size = gfx::Size(width_pixels, height_pixels);
- metrics.device_scale_factor = scale_factor;
- return metrics;
+ gfx::Rect bounds(gfx::Point(origin_x, origin_y), scaled_size);
+
+ display::Display display;
+ display.set_bounds(bounds);
+ display.set_work_area(bounds);
+ display.set_device_scale_factor(scale_factor);
+ return display;
}
ServerWindow* FirstRoot(WindowTree* tree) {
diff --git a/chromium/services/ui/ws/test_utils.h b/chromium/services/ui/ws/test_utils.h
index 7e2cb3fecf8..bc7d52d85eb 100644
--- a/chromium/services/ui/ws/test_utils.h
+++ b/chromium/services/ui/ws/test_utils.h
@@ -21,7 +21,6 @@
#include "services/ui/ws/display_binding.h"
#include "services/ui/ws/drag_controller.h"
#include "services/ui/ws/event_dispatcher.h"
-#include "services/ui/ws/frame_generator_delegate.h"
#include "services/ui/ws/platform_display.h"
#include "services/ui/ws/platform_display_factory.h"
#include "services/ui/ws/test_change_tracker.h"
@@ -55,18 +54,18 @@ class TestScreenManager : public display::ScreenManager {
// returns it. Calls OnDisplayAdded() on delegate.
int64_t AddDisplay();
- // Adds a new display with provided |metrics|, generates a unique display id
+ // Adds a new display with provided |display|, generates a unique display id
// and returns it. Calls OnDisplayAdded() on delegate.
- int64_t AddDisplay(const display::ViewportMetrics& metrics);
+ int64_t AddDisplay(const display::Display& display);
// Calls OnDisplayModified() on delegate.
- void ModifyDisplay(int64_t id, const display::ViewportMetrics& metrics);
+ void ModifyDisplay(const display::Display& display);
// Calls OnDisplayRemoved() on delegate.
void RemoveDisplay(int64_t id);
// display::ScreenManager:
- void AddInterfaces(service_manager::InterfaceRegistry* registry) override {}
+ void AddInterfaces(service_manager::BinderRegistry* registry) override {}
void Init(display::ScreenManagerDelegate* delegate) override;
void RequestCloseDisplay(int64_t display_id) override {}
@@ -118,13 +117,21 @@ class WindowTreeTestApi {
void AckLastEvent(mojom::EventResult result) {
tree_->OnWindowInputEventAck(tree_->event_ack_id_, result);
}
- void AckLastAccelerator(mojom::EventResult result) {
- tree_->OnAcceleratorAck(tree_->event_ack_id_, result);
+ void AckLastAccelerator(
+ mojom::EventResult result,
+ const std::unordered_map<std::string, std::vector<uint8_t>>& properties =
+ std::unordered_map<std::string, std::vector<uint8_t>>()) {
+ tree_->OnAcceleratorAck(tree_->event_ack_id_, result, properties);
}
void StartPointerWatcher(bool want_moves);
void StopPointerWatcher();
+ bool ProcessSetDisplayRoot(int64_t display_id,
+ const ClientWindowId& client_window_id) {
+ return tree_->ProcessSetDisplayRoot(display_id, client_window_id);
+ }
+
private:
WindowTree* tree_;
@@ -138,9 +145,9 @@ class DisplayTestApi {
explicit DisplayTestApi(Display* display);
~DisplayTestApi();
- void OnEvent(const ui::Event& event) { display_->OnEvent(event); }
+ void OnEvent(ui::Event* event) { display_->OnEventFromSource(event); }
- mojom::Cursor last_cursor() const { return display_->last_cursor_; }
+ mojom::CursorType last_cursor() const { return display_->last_cursor_; }
private:
Display* display_;
@@ -225,6 +232,11 @@ class WindowManagerStateTestApi {
: nullptr;
}
+ const std::vector<std::unique_ptr<WindowManagerDisplayRoot>>&
+ window_manager_display_roots() const {
+ return wms_->window_manager_display_roots_;
+ }
+
private:
WindowManagerState* wms_;
@@ -255,8 +267,11 @@ class DragControllerTestApi {
// Factory that always embeds the new WindowTree as the root user id.
class TestDisplayBinding : public DisplayBinding {
public:
- explicit TestDisplayBinding(WindowServer* window_server)
- : window_server_(window_server) {}
+ explicit TestDisplayBinding(WindowServer* window_server,
+ bool automatically_create_display_roots = true)
+ : window_server_(window_server),
+ automatically_create_display_roots_(
+ automatically_create_display_roots) {}
~TestDisplayBinding() override {}
private:
@@ -264,6 +279,7 @@ class TestDisplayBinding : public DisplayBinding {
WindowTree* CreateWindowTree(ServerWindow* root) override;
WindowServer* window_server_;
+ const bool automatically_create_display_roots_;
DISALLOW_COPY_AND_ASSIGN(TestDisplayBinding);
};
@@ -273,43 +289,26 @@ class TestDisplayBinding : public DisplayBinding {
// Factory that dispenses TestPlatformDisplays.
class TestPlatformDisplayFactory : public PlatformDisplayFactory {
public:
- explicit TestPlatformDisplayFactory(mojom::Cursor* cursor_storage);
+ explicit TestPlatformDisplayFactory(mojom::CursorType* cursor_storage);
~TestPlatformDisplayFactory();
// PlatformDisplayFactory:
std::unique_ptr<PlatformDisplay> CreatePlatformDisplay(
- const PlatformDisplayInitParams& init_params) override;
+ ServerWindow* root_window,
+ const display::ViewportMetrics& metrics) override;
private:
- mojom::Cursor* cursor_storage_;
+ mojom::CursorType* cursor_storage_;
DISALLOW_COPY_AND_ASSIGN(TestPlatformDisplayFactory);
};
// -----------------------------------------------------------------------------
-// A stub implementation of FrameGeneratorDelegate.
-class TestFrameGeneratorDelegate : public FrameGeneratorDelegate {
- public:
- TestFrameGeneratorDelegate();
- ~TestFrameGeneratorDelegate() override;
-
- // FrameGeneratorDelegate:
- bool IsInHighContrastMode() override;
-
- DISALLOW_COPY_AND_ASSIGN(TestFrameGeneratorDelegate);
-};
-
-// -----------------------------------------------------------------------------
-
class TestWindowManager : public mojom::WindowManager {
public:
- TestWindowManager()
- : got_create_top_level_window_(false),
- change_id_(0u),
- on_accelerator_called_(false),
- on_accelerator_id_(0u) {}
- ~TestWindowManager() override {}
+ TestWindowManager();
+ ~TestWindowManager() override;
bool did_call_create_top_level_window(uint32_t* change_id) {
if (!got_create_top_level_window_)
@@ -330,13 +329,19 @@ class TestWindowManager : public mojom::WindowManager {
uint32_t on_accelerator_id() { return on_accelerator_id_; }
bool got_display_removed() const { return got_display_removed_; }
int64_t display_removed_id() const { return display_removed_id_; }
+ bool on_set_modal_type_called() { return on_set_modal_type_called_; }
+ int connect_count() const { return connect_count_; }
+ int display_added_count() const { return display_added_count_; }
private:
// WindowManager:
- void OnConnect(uint16_t client_id) override {}
- void WmNewDisplayAdded(const display::Display& display,
- ui::mojom::WindowDataPtr root,
- bool drawn) override {}
+ void OnConnect(uint16_t client_id) override;
+ void WmNewDisplayAdded(
+ const display::Display& display,
+ ui::mojom::WindowDataPtr root,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) override;
void WmDisplayRemoved(int64_t display_id) override;
void WmDisplayModified(const display::Display& display) override {}
void WmSetBounds(uint32_t change_id,
@@ -347,6 +352,7 @@ class TestWindowManager : public mojom::WindowManager {
uint32_t 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 WmCreateTopLevelWindow(
uint32_t change_id,
@@ -355,6 +361,13 @@ class TestWindowManager : public mojom::WindowManager {
override;
void WmClientJankinessChanged(ClientSpecificId client_id,
bool janky) override;
+ 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;
+ void WmDestroyDragImage() override;
void WmPerformMoveLoop(uint32_t change_id,
uint32_t window_id,
mojom::MoveLoopSource source,
@@ -369,16 +382,20 @@ class TestWindowManager : public mojom::WindowManager {
std::unique_ptr<ui::Event> event) override;
bool on_perform_move_loop_called_ = false;
+ bool on_set_modal_type_called_ = false;
- bool got_create_top_level_window_;
- uint32_t change_id_;
+ bool got_create_top_level_window_ = false;
+ uint32_t change_id_ = 0u;
- bool on_accelerator_called_;
- uint32_t on_accelerator_id_;
+ bool on_accelerator_called_ = false;
+ uint32_t on_accelerator_id_ = 0u;
bool got_display_removed_ = false;
int64_t display_removed_id_ = 0;
+ int connect_count_ = 0;
+ int display_added_count_ = 0;
+
DISALLOW_COPY_AND_ASSIGN(TestWindowManager);
};
@@ -400,23 +417,33 @@ class TestWindowTreeClient : public ui::mojom::WindowTreeClient {
private:
// WindowTreeClient:
- void OnEmbed(uint16_t client_id,
- mojom::WindowDataPtr root,
- ui::mojom::WindowTreePtr tree,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) override;
+ void OnEmbed(
+ uint16_t client_id,
+ mojom::WindowDataPtr root,
+ ui::mojom::WindowTreePtr tree,
+ int64_t display_id,
+ Id focused_window_id,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) override;
void OnEmbeddedAppDisconnected(uint32_t window) override;
void OnUnembed(Id window_id) override;
void OnCaptureChanged(Id new_capture_window_id,
Id old_capture_window_id) override;
- void OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr data,
- int64_t display_id,
- bool drawn) override;
- void OnWindowBoundsChanged(uint32_t window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) override;
+ void OnFrameSinkIdAllocated(Id window_id,
+ const cc::FrameSinkId& frame_sink_id) override;
+ void OnTopLevelCreated(
+ uint32_t change_id,
+ mojom::WindowDataPtr data,
+ int64_t display_id,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) override;
+ void OnWindowBoundsChanged(
+ uint32_t window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) override;
void OnClientAreaChanged(
uint32_t window_id,
const gfx::Insets& new_client_area,
@@ -453,7 +480,7 @@ class TestWindowTreeClient : public ui::mojom::WindowTreeClient {
int64_t display_id) override;
void OnWindowFocused(uint32_t focused_window_id) override;
void OnWindowPredefinedCursorChanged(uint32_t window_id,
- mojom::Cursor cursor_id) override;
+ mojom::CursorType cursor_id) override;
void OnWindowSurfaceChanged(Id window_id,
const cc::SurfaceInfo& surface_info) override;
void OnDragDropStart(
@@ -584,14 +611,14 @@ class WindowServerTestHelper {
~WindowServerTestHelper();
WindowServer* window_server() { return window_server_.get(); }
- mojom::Cursor cursor() const { return cursor_id_; }
+ mojom::CursorType cursor() const { return cursor_id_; }
TestWindowServerDelegate* window_server_delegate() {
return &window_server_delegate_;
}
private:
- mojom::Cursor cursor_id_;
+ mojom::CursorType cursor_id_;
TestPlatformDisplayFactory platform_display_factory_;
TestWindowServerDelegate window_server_delegate_;
std::unique_ptr<WindowServer> window_server_;
@@ -606,7 +633,8 @@ class WindowServerTestHelper {
// of ServerWindow objects.
class WindowEventTargetingHelper {
public:
- WindowEventTargetingHelper();
+ explicit WindowEventTargetingHelper(
+ bool automatically_create_display_roots = true);
~WindowEventTargetingHelper();
// Creates |window| as an embeded window of the primary tree. This window is a
@@ -626,7 +654,7 @@ class WindowEventTargetingHelper {
// Sets the task runner for |message_loop_|
void SetTaskRunner(scoped_refptr<base::SingleThreadTaskRunner> task_runner);
- mojom::Cursor cursor() const { return ws_test_helper_.cursor(); }
+ mojom::CursorType cursor() const { return ws_test_helper_.cursor(); }
Display* display() { return display_; }
TestWindowTreeBinding* last_binding() {
return ws_test_helper_.window_server_delegate()->last_binding();
@@ -655,16 +683,18 @@ class WindowEventTargetingHelper {
// Adds a new WM to |window_server| for |user_id|. Creates
// WindowManagerWindowTreeFactory and associated WindowTree for the WM.
-void AddWindowManager(WindowServer* window_server, const UserId& user_id);
-
-// Create a new ViewportMetrics object with specified bounds, size and
-// scale factor. Bounds origin, |origin_x| and |origin_y|, are in DIP and bounds
-// size is computed.
-display::ViewportMetrics MakeViewportMetrics(int origin_x,
- int origin_y,
- int width_pixels,
- int height_pixels,
- float scale_factor);
+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
+// scale factor. The bounds size is computed based on the pixel size and device
+// scale factor.
+display::Display MakeDisplay(int origin_x,
+ int origin_y,
+ int width_pixels,
+ int height_pixels,
+ float scale_factor);
// Returns the first and only root of |tree|. If |tree| has zero or more than
// one root returns null.
@@ -680,7 +710,8 @@ ClientWindowId ClientWindowIdForWindow(WindowTree* tree,
// Creates a new visible window as a child of the single root of |tree|.
// |client_id| is set to the ClientWindowId of the new window.
-ServerWindow* NewWindowInTree(WindowTree* tree, ClientWindowId* client_id);
+ServerWindow* NewWindowInTree(WindowTree* tree,
+ ClientWindowId* client_id = nullptr);
ServerWindow* NewWindowInTreeWithParent(WindowTree* tree,
ServerWindow* parent,
ClientWindowId* client_id = nullptr);
diff --git a/chromium/services/ui/ws/window_finder_unittest.cc b/chromium/services/ui/ws/window_finder_unittest.cc
index 717dcd09e38..102057f91e4 100644
--- a/chromium/services/ui/ws/window_finder_unittest.cc
+++ b/chromium/services/ui/ws/window_finder_unittest.cc
@@ -20,17 +20,17 @@ TEST(WindowFinderTest, FindDeepestVisibleWindow) {
mojom::EventTargetingPolicy::DESCENDANTS_ONLY);
window_delegate.set_root_window(&root);
root.SetVisible(true);
- root.SetBounds(gfx::Rect(0, 0, 100, 100));
+ root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
ServerWindow child1(&window_delegate, WindowId(1, 3));
root.Add(&child1);
child1.SetVisible(true);
- child1.SetBounds(gfx::Rect(10, 10, 20, 20));
+ child1.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
ServerWindow child2(&window_delegate, WindowId(1, 4));
root.Add(&child2);
child2.SetVisible(true);
- child2.SetBounds(gfx::Rect(15, 15, 20, 20));
+ child2.SetBounds(gfx::Rect(15, 15, 20, 20), base::nullopt);
EXPECT_EQ(
&child2,
@@ -56,12 +56,12 @@ TEST(WindowFinderTest, FindDeepestVisibleWindowNonClientArea) {
ServerWindow root(&window_delegate, WindowId(1, 2));
window_delegate.set_root_window(&root);
root.SetVisible(true);
- root.SetBounds(gfx::Rect(0, 0, 100, 100));
+ root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
ServerWindow child1(&window_delegate, WindowId(1, 3));
root.Add(&child1);
child1.SetVisible(true);
- child1.SetBounds(gfx::Rect(10, 10, 20, 20));
+ child1.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
DeepestWindow result =
FindDeepestVisibleWindowForEvents(&root, gfx::Point(13, 14));
@@ -102,12 +102,12 @@ TEST(WindowFinderTest, FindDeepestVisibleWindowHitTestMask) {
ServerWindow root(&window_delegate, WindowId(1, 2));
window_delegate.set_root_window(&root);
root.SetVisible(true);
- root.SetBounds(gfx::Rect(0, 0, 100, 100));
+ root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
ServerWindow child_with_mask(&window_delegate, WindowId(1, 4));
root.Add(&child_with_mask);
child_with_mask.SetVisible(true);
- child_with_mask.SetBounds(gfx::Rect(10, 10, 20, 20));
+ child_with_mask.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
child_with_mask.SetHitTestMask(gfx::Rect(2, 2, 16, 16));
// Test a point inside the window but outside the mask.
@@ -126,20 +126,20 @@ TEST(WindowFinderTest, FindDeepestVisibleWindowOverNonTarget) {
ServerWindow root(&window_delegate, WindowId(1, 2));
window_delegate.set_root_window(&root);
root.SetVisible(true);
- root.SetBounds(gfx::Rect(0, 0, 100, 100));
+ 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));
root.Add(&child1);
child1.SetVisible(true);
- child1.SetBounds(gfx::Rect(10, 10, 20, 20));
+ child1.SetBounds(gfx::Rect(10, 10, 20, 20), base::nullopt);
ServerWindow child2(&window_delegate, WindowId(1, 4));
root.Add(&child2);
child2.set_event_targeting_policy(mojom::EventTargetingPolicy::NONE);
child2.SetVisible(true);
- child2.SetBounds(gfx::Rect(15, 15, 20, 20));
+ child2.SetBounds(gfx::Rect(15, 15, 20, 20), base::nullopt);
// 16, 16 is over |child2| and |child1|, but as |child2| isn't a valid event
// target |child1| should be picked.
@@ -153,7 +153,7 @@ TEST(WindowFinderTest, NonClientPreferredOverChild) {
ServerWindow root(&window_delegate, WindowId(1, 2));
window_delegate.set_root_window(&root);
root.SetVisible(true);
- root.SetBounds(gfx::Rect(0, 0, 100, 100));
+ root.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
// 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
@@ -161,13 +161,13 @@ TEST(WindowFinderTest, NonClientPreferredOverChild) {
ServerWindow child(&window_delegate, WindowId(1, 3));
root.Add(&child);
child.SetVisible(true);
- child.SetBounds(gfx::Rect(0, 0, 100, 100));
+ 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));
child.Add(&child_child);
child_child.SetVisible(true);
- child_child.SetBounds(gfx::Rect(0, 0, 100, 100));
+ child_child.SetBounds(gfx::Rect(0, 0, 100, 100), base::nullopt);
// |child| was should be returned as the event is over the non-client area.
EXPECT_EQ(&child,
diff --git a/chromium/services/ui/ws/window_manager_client_unittest.cc b/chromium/services/ui/ws/window_manager_client_unittest.cc
index 075b70b25f7..1f24a882f97 100644
--- a/chromium/services/ui/ws/window_manager_client_unittest.cc
+++ b/chromium/services/ui/ws/window_manager_client_unittest.cc
@@ -45,15 +45,14 @@ class TestWindowManagerDelegate : public aura::WindowManagerDelegate {
// WindowManagerDelegate:
void SetWindowManagerClient(aura::WindowManagerClient* client) override {}
- bool OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) override {
- return false;
- }
+ void OnWmSetBounds(aura::Window* window, const gfx::Rect& bounds) override {}
bool OnWmSetProperty(
aura::Window* window,
const std::string& name,
std::unique_ptr<std::vector<uint8_t>>* new_data) override {
return false;
}
+ void OnWmSetModalType(aura::Window* window, ui::ModalType type) override {}
void OnWmSetCanFocus(aura::Window* window, bool can_focus) override {}
aura::Window* OnWmCreateTopLevelWindow(
ui::mojom::WindowType window_type,
@@ -62,13 +61,22 @@ class TestWindowManagerDelegate : public aura::WindowManagerDelegate {
}
void OnWmClientJankinessChanged(const std::set<aura::Window*>& client_windows,
bool not_responding) override {}
+ void OnWmBuildDragImage(const gfx::Point& screen_location,
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ ui::mojom::PointerKind source) override {}
+ void OnWmMoveDragImage(const gfx::Point& screen_location) override {}
+ void OnWmDestroyDragImage() override {}
void OnWmWillCreateDisplay(const display::Display& display) override {}
void OnWmNewDisplay(std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
const display::Display& display) override {}
void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) override {}
void OnWmDisplayModified(const display::Display& display) override {}
- mojom::EventResult OnAccelerator(uint32_t accelerator_id,
- const ui::Event& event) override {
+ mojom::EventResult OnAccelerator(
+ uint32_t accelerator_id,
+ const ui::Event& event,
+ std::unordered_map<std::string, std::vector<uint8_t>>* properties)
+ override {
return ui::mojom::EventResult::UNHANDLED;
}
void OnWmPerformMoveLoop(aura::Window* window,
@@ -711,9 +719,11 @@ class EstablishConnectionViaFactoryDelegate : public TestWindowManagerDelegate {
TEST_F(WindowServerTest, EstablishConnectionViaFactory) {
EstablishConnectionViaFactoryDelegate delegate(window_manager());
set_window_manager_delegate(&delegate);
- aura::WindowTreeClient second_client(connector(), this);
+ aura::WindowTreeClient second_client(connector(), this, nullptr, nullptr,
+ nullptr, false);
second_client.ConnectViaWindowTreeFactory();
- aura::WindowTreeHostMus window_tree_host_in_second_client(&second_client);
+ aura::WindowTreeHostMus window_tree_host_in_second_client(
+ &second_client, cc::FrameSinkId(1, 1));
window_tree_host_in_second_client.InitHost();
window_tree_host_in_second_client.window()->Show();
ASSERT_TRUE(second_client.GetRoots().count(
@@ -739,9 +749,11 @@ TEST_F(WindowServerTest, OnWindowHierarchyChangedIncludesTransientParent) {
// of the first window and then add it.
EstablishConnectionViaFactoryDelegate delegate(window_manager());
set_window_manager_delegate(&delegate);
- aura::WindowTreeClient second_client(connector(), this);
+ aura::WindowTreeClient second_client(connector(), this, nullptr, nullptr,
+ nullptr, false);
second_client.ConnectViaWindowTreeFactory();
- aura::WindowTreeHostMus window_tree_host_in_second_client(&second_client);
+ aura::WindowTreeHostMus window_tree_host_in_second_client(
+ &second_client, cc::FrameSinkId(1, 1));
window_tree_host_in_second_client.InitHost();
window_tree_host_in_second_client.window()->Show();
aura::Window* second_client_child = NewVisibleWindow(
diff --git a/chromium/services/ui/ws/window_manager_display_root.cc b/chromium/services/ui/ws/window_manager_display_root.cc
index 7248714109f..5a933de2c07 100644
--- a/chromium/services/ui/ws/window_manager_display_root.cc
+++ b/chromium/services/ui/ws/window_manager_display_root.cc
@@ -31,7 +31,8 @@ WindowManagerDisplayRoot::WindowManagerDisplayRoot(Display* display)
// Our root is always a child of the Display's root. Do this
// before the WindowTree has been created so that the client doesn't get
// notified of the add, bounds change and visibility change.
- root_->SetBounds(gfx::Rect(display->root_window()->bounds().size()));
+ root_->SetBounds(gfx::Rect(display->root_window()->bounds().size()),
+ allocator_.GenerateId());
root_->SetVisible(true);
display->root_window()->Add(root_.get());
}
diff --git a/chromium/services/ui/ws/window_manager_display_root.h b/chromium/services/ui/ws/window_manager_display_root.h
index 2ba39a08af8..1eacb3a9568 100644
--- a/chromium/services/ui/ws/window_manager_display_root.h
+++ b/chromium/services/ui/ws/window_manager_display_root.h
@@ -10,6 +10,7 @@
#include <memory>
#include "base/macros.h"
+#include "cc/surfaces/local_surface_id_allocator.h"
namespace ui {
namespace ws {
@@ -49,6 +50,7 @@ class WindowManagerDisplayRoot {
// the root ServerWindow of the Display.
std::unique_ptr<ServerWindow> root_;
WindowManagerState* window_manager_state_ = nullptr;
+ cc::LocalSurfaceIdAllocator allocator_;
DISALLOW_COPY_AND_ASSIGN(WindowManagerDisplayRoot);
};
diff --git a/chromium/services/ui/ws/window_manager_state.cc b/chromium/services/ui/ws/window_manager_state.cc
index 1c9665b28e0..66d1e915bd2 100644
--- a/chromium/services/ui/ws/window_manager_state.cc
+++ b/chromium/services/ui/ws/window_manager_state.cc
@@ -137,8 +137,10 @@ WindowManagerState::~WindowManagerState() {
for (auto& display_root : window_manager_display_roots_)
display_root->display()->OnWillDestroyTree(window_tree_);
- for (auto& display_root : orphaned_window_manager_display_roots_)
- display_root->root()->RemoveObserver(this);
+ if (window_tree_->automatically_create_display_roots()) {
+ for (auto& display_root : orphaned_window_manager_display_roots_)
+ display_root->root()->RemoveObserver(this);
+ }
}
void WindowManagerState::SetFrameDecorationValues(
@@ -182,7 +184,7 @@ void WindowManagerState::SetDragDropSourceWindow(
DragTargetConnection* source_connection,
const std::unordered_map<std::string, std::vector<uint8_t>>& drag_data,
uint32_t drag_operation) {
- int32_t drag_pointer = PointerEvent::kMousePointerId;
+ int32_t drag_pointer = MouseEvent::kMousePointerId;
if (in_flight_event_details_ &&
in_flight_event_details_->event->IsPointerEvent()) {
drag_pointer =
@@ -209,10 +211,31 @@ void WindowManagerState::EndDragDrop() {
}
void WindowManagerState::AddSystemModalWindow(ServerWindow* window) {
- DCHECK(!window->transient_parent());
event_dispatcher_.AddSystemModalWindow(window);
}
+void WindowManagerState::DeleteWindowManagerDisplayRoot(
+ ServerWindow* display_root) {
+ for (auto iter = orphaned_window_manager_display_roots_.begin();
+ iter != orphaned_window_manager_display_roots_.end(); ++iter) {
+ if ((*iter)->root() == display_root) {
+ orphaned_window_manager_display_roots_.erase(iter);
+ return;
+ }
+ }
+
+ for (auto iter = window_manager_display_roots_.begin();
+ iter != window_manager_display_roots_.end(); ++iter) {
+ if ((*iter)->root() == display_root) {
+ (*iter)->display()->RemoveWindowManagerDisplayRoot((*iter).get());
+ window_manager_display_roots_.erase(iter);
+ return;
+ }
+ }
+
+ NOTREACHED();
+}
+
const UserId& WindowManagerState::user_id() const {
return window_tree_->user_id();
}
@@ -299,7 +322,9 @@ void WindowManagerState::OnEventAck(mojom::WindowTree* tree,
ProcessNextEventFromQueue();
}
-void WindowManagerState::OnAcceleratorAck(mojom::EventResult result) {
+void WindowManagerState::OnAcceleratorAck(
+ mojom::EventResult result,
+ const std::unordered_map<std::string, std::vector<uint8_t>>& properties) {
if (!in_flight_event_details_ ||
in_flight_event_details_->phase !=
EventDispatchPhase::PRE_TARGET_ACCELERATOR) {
@@ -312,6 +337,9 @@ void WindowManagerState::OnAcceleratorAck(mojom::EventResult result) {
std::move(in_flight_event_details_);
if (result == mojom::EventResult::UNHANDLED) {
+ DCHECK(details->event->IsKeyEvent());
+ if (!properties.empty())
+ details->event->AsKeyEvent()->SetProperties(properties);
event_processing_display_id_ = details->display_id;
event_dispatcher_.ProcessEvent(
*details->event, EventDispatcher::AcceleratorMatchPhase::POST_ONLY);
@@ -352,14 +380,15 @@ void WindowManagerState::OnDisplayDestroying(Display* display) {
for (auto iter = window_manager_display_roots_.begin();
iter != window_manager_display_roots_.end(); ++iter) {
if ((*iter)->display() == display) {
- (*iter)->root()->AddObserver(this);
+ if (window_tree_->automatically_create_display_roots())
+ (*iter)->root()->AddObserver(this);
orphaned_window_manager_display_roots_.push_back(std::move(*iter));
window_manager_display_roots_.erase(iter);
window_tree_->OnDisplayDestroying(display->GetId());
+ orphaned_window_manager_display_roots_.back()->display_ = nullptr;
return;
}
}
- NOTREACHED();
}
void WindowManagerState::SetAllRootWindowsVisible(bool value) {
@@ -382,7 +411,7 @@ void WindowManagerState::OnEventAckTimeout(ClientSpecificId client_id) {
window_tree_->ClientJankinessChanged(hung_tree);
if (in_flight_event_details_->phase ==
EventDispatchPhase::PRE_TARGET_ACCELERATOR) {
- OnAcceleratorAck(mojom::EventResult::UNHANDLED);
+ OnAcceleratorAck(mojom::EventResult::UNHANDLED, KeyEvent::Properties());
} else {
OnEventAck(
in_flight_event_details_ ? in_flight_event_details_->tree : nullptr,
@@ -560,7 +589,8 @@ void WindowManagerState::ReleaseNativeCapture() {
}
void WindowManagerState::UpdateNativeCursorFromDispatcher() {
- const ui::mojom::Cursor cursor_id = event_dispatcher_.GetCurrentMouseCursor();
+ const ui::mojom::CursorType cursor_id =
+ event_dispatcher_.GetCurrentMouseCursor();
for (Display* display : display_manager()->displays())
display->UpdateNativeCursor(cursor_id);
}
@@ -631,9 +661,11 @@ ServerWindow* WindowManagerState::GetRootWindowContaining(
if (window_manager_display_roots_.empty())
return nullptr;
+ // TODO(riajiang): This is broken for HDPI because it mixes PPs and DIPs. See
+ // http://crbug.com/701036 for details.
WindowManagerDisplayRoot* target_display_root = nullptr;
for (auto& display_root_ptr : window_manager_display_roots_) {
- if (display_root_ptr->display()->platform_display()->GetBounds().Contains(
+ if (display_root_ptr->display()->GetDisplay().bounds().Contains(
*location)) {
target_display_root = display_root_ptr.get();
break;
@@ -650,7 +682,7 @@ ServerWindow* WindowManagerState::GetRootWindowContaining(
// Translate the location to be relative to the display instead of relative
// to the screen space.
gfx::Point origin =
- target_display_root->display()->platform_display()->GetBounds().origin();
+ target_display_root->display()->GetDisplay().bounds().origin();
*location -= origin.OffsetFromOrigin();
return target_display_root->root();
}
diff --git a/chromium/services/ui/ws/window_manager_state.h b/chromium/services/ui/ws/window_manager_state.h
index 67a343b5336..3921fdfaace 100644
--- a/chromium/services/ui/ws/window_manager_state.h
+++ b/chromium/services/ui/ws/window_manager_state.h
@@ -9,6 +9,8 @@
#include <memory>
#include <queue>
+#include <string>
+#include <unordered_map>
#include <vector>
#include "base/memory/weak_ptr.h"
@@ -76,6 +78,9 @@ class WindowManagerState : public EventDispatcherDelegate,
void AddSystemModalWindow(ServerWindow* window);
+ // 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.
@@ -100,7 +105,9 @@ class WindowManagerState : public EventDispatcherDelegate,
void OnEventAck(mojom::WindowTree* tree, mojom::EventResult result);
// Called when the WindowManager acks an accelerator.
- void OnAcceleratorAck(mojom::EventResult result);
+ void OnAcceleratorAck(
+ mojom::EventResult result,
+ const std::unordered_map<std::string, std::vector<uint8_t>>& properties);
private:
class ProcessedEventTarget;
diff --git a/chromium/services/ui/ws/window_manager_state_unittest.cc b/chromium/services/ui/ws/window_manager_state_unittest.cc
index 9a516957818..a4856df6d13 100644
--- a/chromium/services/ui/ws/window_manager_state_unittest.cc
+++ b/chromium/services/ui/ws/window_manager_state_unittest.cc
@@ -17,7 +17,6 @@
#include "services/ui/ws/display.h"
#include "services/ui/ws/display_manager.h"
#include "services/ui/ws/platform_display.h"
-#include "services/ui/ws/platform_display_init_params.h"
#include "services/ui/ws/test_change_tracker.h"
#include "services/ui/ws/test_server_window_delegate.h"
#include "services/ui/ws/test_utils.h"
@@ -51,7 +50,8 @@ class WindowManagerStateTest : public testing::Test {
Accelerator* accelerator);
void OnEventAckTimeout(ClientSpecificId client_id);
- // This is the tree associated with the WindowManagerState.
+ // This is the tree associated with the WindowManagerState. That is, this is
+ // the WindowTree of the WindowManager.
WindowTree* tree() {
return window_event_targeting_helper_.window_server()->GetTreeWithId(1);
}
@@ -236,7 +236,7 @@ TEST_F(WindowManagerStateTest, PreTargetConsumed) {
TestChangeTracker* tracker2 = window_tree_client()->tracker();
tracker2->changes()->clear();
- // Send an ensure only the pre accelerator is called.
+ // Send and ensure only the pre accelerator is called.
ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
window_manager_state()->ProcessEvent(key, 0);
EXPECT_TRUE(window_manager()->on_accelerator_called());
@@ -266,6 +266,79 @@ TEST_F(WindowManagerStateTest, PreTargetConsumed) {
SingleChangeToDescription(*tracker2->changes()));
}
+TEST_F(WindowManagerStateTest, AckWithProperties) {
+ // Set up two trees with focus on a child in the second.
+ const ClientWindowId child_window_id(11);
+ window_tree()->NewWindow(child_window_id, ServerWindow::Properties());
+ ServerWindow* child_window =
+ window_tree()->GetWindowByClientId(child_window_id);
+ window_tree()->AddWindow(FirstRootId(window_tree()), child_window_id);
+ child_window->SetVisible(true);
+ SetCanFocusUp(child_window);
+ tree()->GetDisplay(child_window)->AddActivationParent(child_window->parent());
+ ASSERT_TRUE(window_tree()->SetFocus(child_window_id));
+
+ // Register a pre-accelerator.
+ uint32_t accelerator_id = 11;
+ {
+ mojom::EventMatcherPtr matcher = ui::CreateKeyMatcher(
+ ui::mojom::KeyboardCode::W, ui::mojom::kEventFlagControlDown);
+
+ ASSERT_TRUE(window_manager_state()->event_dispatcher()->AddAccelerator(
+ accelerator_id, std::move(matcher)));
+ }
+ TestChangeTracker* tracker = wm_client()->tracker();
+ tracker->changes()->clear();
+ TestChangeTracker* tracker2 = window_tree_client()->tracker();
+ tracker2->changes()->clear();
+
+ // Send and ensure only the pre accelerator is called.
+ ui::KeyEvent key(ui::ET_KEY_PRESSED, ui::VKEY_W, ui::EF_CONTROL_DOWN);
+ window_manager_state()->ProcessEvent(key, 0);
+ EXPECT_TRUE(window_manager()->on_accelerator_called());
+ EXPECT_EQ(accelerator_id, window_manager()->on_accelerator_id());
+ EXPECT_TRUE(tracker->changes()->empty());
+ EXPECT_TRUE(tracker2->changes()->empty());
+
+ // Ack the accelerator, with unhandled.
+ std::unordered_map<std::string, std::vector<uint8_t>> event_properties;
+ const std::string property_key = "x";
+ const std::vector<uint8_t> property_value(2, 0xAB);
+ event_properties[property_key] = property_value;
+ EXPECT_TRUE(tracker->changes()->empty());
+ EXPECT_TRUE(tracker2->changes()->empty());
+ WindowTreeTestApi(tree()).AckLastAccelerator(mojom::EventResult::UNHANDLED,
+ event_properties);
+
+ // The focused window should get the event.
+ EXPECT_EQ("InputEvent window=0,11 event_action=7",
+ SingleChangeToDescription(*tracker2->changes()));
+ ASSERT_EQ(1u, tracker2->changes()->size());
+ EXPECT_EQ(1u, (*tracker2->changes())[0].key_event_properties.size());
+ EXPECT_EQ(event_properties, (*tracker2->changes())[0].key_event_properties);
+
+ WindowTreeTestApi(window_tree()).AckLastEvent(mojom::EventResult::HANDLED);
+ tracker2->changes()->clear();
+
+ // Send the event again, and ack with no properties. Ensure client gets no
+ // properties.
+ window_manager()->ClearAcceleratorCalled();
+ window_manager_state()->ProcessEvent(key, 0);
+ EXPECT_TRUE(window_manager()->on_accelerator_called());
+ EXPECT_EQ(accelerator_id, window_manager()->on_accelerator_id());
+ EXPECT_TRUE(tracker->changes()->empty());
+ EXPECT_TRUE(tracker2->changes()->empty());
+
+ // Ack the accelerator with unhandled.
+ WindowTreeTestApi(tree()).AckLastAccelerator(mojom::EventResult::UNHANDLED);
+
+ // The focused window should get the event.
+ EXPECT_EQ("InputEvent window=0,11 event_action=7",
+ SingleChangeToDescription(*tracker2->changes()));
+ ASSERT_EQ(1u, tracker2->changes()->size());
+ EXPECT_TRUE((*tracker2->changes())[0].key_event_properties.empty());
+}
+
// Tests that when a client handles an event that post target accelerators are
// not called.
TEST_F(WindowManagerStateTest, ClientHandlesEvent) {
@@ -574,18 +647,18 @@ TEST_F(WindowManagerStateTest, CursorResetOverNoTarget) {
window_tree()->AddWindow(FirstRootId(window_tree()), child_window_id);
child_window->SetVisible(true);
child_window->SetBounds(gfx::Rect(0, 0, 20, 20));
- child_window->parent()->SetPredefinedCursor(ui::mojom::Cursor::COPY);
- EXPECT_EQ(ui::mojom::Cursor::COPY, display_test_api.last_cursor());
+ child_window->parent()->SetPredefinedCursor(ui::mojom::CursorType::COPY);
+ EXPECT_EQ(ui::mojom::CursorType::COPY, display_test_api.last_cursor());
// Move the mouse outside the bounds of the child, so that the mouse is not
// over any valid windows. Cursor should change to POINTER.
ui::PointerEvent move(
- ui::ET_POINTER_MOVED, gfx::Point(25, 25), gfx::Point(25, 25), 0, 0, 0,
- ui::PointerDetails(EventPointerType::POINTER_TYPE_MOUSE),
+ ui::ET_POINTER_MOVED, gfx::Point(25, 25), gfx::Point(25, 25), 0, 0,
+ ui::PointerDetails(EventPointerType::POINTER_TYPE_MOUSE, 0),
base::TimeTicks());
window_manager_state()->ProcessEvent(move, 0);
// The event isn't over a valid target, which should trigger resetting the
// cursor to POINTER.
- EXPECT_EQ(ui::mojom::Cursor::POINTER, display_test_api.last_cursor());
+ EXPECT_EQ(ui::mojom::CursorType::POINTER, display_test_api.last_cursor());
}
} // namespace test
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 26be4b7058d..0f9589b8176 100644
--- a/chromium/services/ui/ws/window_manager_window_tree_factory.cc
+++ b/chromium/services/ui/ws/window_manager_window_tree_factory.cc
@@ -26,14 +26,21 @@ WindowManagerWindowTreeFactory::~WindowManagerWindowTreeFactory() {}
void WindowManagerWindowTreeFactory::CreateWindowTree(
mojom::WindowTreeRequest window_tree_request,
- mojom::WindowTreeClientPtr window_tree_client) {
+ mojom::WindowTreeClientPtr window_tree_client,
+ bool automatically_create_display_roots) {
+ if (window_tree_) {
+ DVLOG(1) << "CreateWindowTree() called more than once.";
+ return;
+ }
+
// CreateWindowTree() can only be called once, so there is no reason to keep
// the binding around.
if (binding_.is_bound())
binding_.Close();
SetWindowTree(GetWindowServer()->CreateTreeForWindowManager(
- user_id_, std::move(window_tree_request), std::move(window_tree_client)));
+ user_id_, std::move(window_tree_request), std::move(window_tree_client),
+ automatically_create_display_roots));
}
WindowManagerWindowTreeFactory::WindowManagerWindowTreeFactory(
@@ -42,8 +49,7 @@ WindowManagerWindowTreeFactory::WindowManagerWindowTreeFactory(
: window_manager_window_tree_factory_set_(
window_manager_window_tree_factory_set),
user_id_(user_id),
- binding_(this),
- window_tree_(nullptr) {}
+ binding_(this) {}
WindowServer* WindowManagerWindowTreeFactory::GetWindowServer() {
return window_manager_window_tree_factory_set_->window_server();
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 df5c4b0e8c5..ce56479db8b 100644
--- a/chromium/services/ui/ws/window_manager_window_tree_factory.h
+++ b/chromium/services/ui/ws/window_manager_window_tree_factory.h
@@ -34,7 +34,8 @@ class WindowManagerWindowTreeFactory
// mojom::WindowManagerWindowTreeFactory:
void CreateWindowTree(mojom::WindowTreeRequest window_tree_request,
- mojom::WindowTreeClientPtr window_tree_client) override;
+ mojom::WindowTreeClientPtr window_tree_client,
+ bool window_manager_creates_roots) override;
private:
// Used by tests.
@@ -50,7 +51,7 @@ class WindowManagerWindowTreeFactory
mojo::Binding<mojom::WindowManagerWindowTreeFactory> binding_;
// Owned by WindowServer.
- WindowTree* window_tree_;
+ WindowTree* window_tree_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(WindowManagerWindowTreeFactory);
};
diff --git a/chromium/services/ui/ws/window_server.cc b/chromium/services/ui/ws/window_server.cc
index 8bcba9bdff6..d012b886dc2 100644
--- a/chromium/services/ui/ws/window_server.cc
+++ b/chromium/services/ui/ws/window_server.cc
@@ -10,7 +10,6 @@
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/ui/ws/display.h"
#include "services/ui/ws/display_manager.h"
#include "services/ui/ws/frame_generator.h"
@@ -45,8 +44,6 @@ struct WindowServer::CurrentDragLoopState {
WindowTree* initiator;
};
-// TODO(fsamuel): DisplayCompositor should be a mojo interface dispensed by
-// GpuHost.
WindowServer::WindowServer(WindowServerDelegate* delegate)
: delegate_(delegate),
next_client_id_(1),
@@ -56,12 +53,12 @@ WindowServer::WindowServer(WindowServerDelegate* delegate)
next_wm_change_id_(0),
gpu_host_(new GpuHost(this)),
window_manager_window_tree_factory_set_(this, &user_id_tracker_),
- display_compositor_client_binding_(this) {
+ frame_sink_manager_client_binding_(this) {
user_id_tracker_.AddObserver(this);
OnUserIdAdded(user_id_tracker_.active_id());
- gpu_host_->CreateDisplayCompositor(
- mojo::MakeRequest(&display_compositor_),
- display_compositor_client_binding_.CreateInterfacePtrAndBind());
+ gpu_host_->CreateFrameSinkManager(
+ mojo::MakeRequest(&frame_sink_manager_),
+ frame_sink_manager_client_binding_.CreateInterfacePtrAndBind());
}
WindowServer::~WindowServer() {
@@ -135,7 +132,8 @@ 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) {
+ mojom::WindowTreeClientPtr window_tree_client,
+ bool automatically_create_display_roots) {
std::unique_ptr<WindowTree> window_tree(new WindowTree(
this, user_id, nullptr, base::WrapUnique(new WindowManagerAccessPolicy)));
std::unique_ptr<WindowTreeBinding> window_tree_binding =
@@ -149,7 +147,7 @@ WindowTree* WindowServer::CreateTreeForWindowManager(
}
WindowTree* window_tree_ptr = window_tree.get();
AddTree(std::move(window_tree), std::move(window_tree_binding), nullptr);
- window_tree_ptr->ConfigureWindowManager();
+ window_tree_ptr->ConfigureWindowManager(automatically_create_display_roots);
return window_tree_ptr;
}
@@ -276,15 +274,17 @@ ServerWindow* WindowServer::GetFocusedWindow() {
return nullptr;
}
-bool WindowServer::IsActiveUserInHighContrastMode() const {
- return IsUserInHighContrastMode(user_id_tracker_.active_id());
-}
-
void WindowServer::SetHighContrastMode(const UserId& user, bool enabled) {
// TODO(fsamuel): This doesn't really seem like it's a window server concept?
if (IsUserInHighContrastMode(user) == enabled)
return;
high_contrast_mode_[user] = enabled;
+
+ if (user == user_id_tracker_.active_id()) {
+ // Propagate the change to all Displays so that FrameGenerators start
+ // requesting BeginFrames.
+ display_manager_->SetHighContrastMode(enabled);
+ }
}
uint32_t WindowServer::GenerateWindowManagerChangeId(
@@ -346,12 +346,15 @@ void WindowServer::WindowManagerCreatedTopLevelWindow(
change.client_change_id, window);
}
-void WindowServer::ProcessWindowBoundsChanged(const ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) {
+void WindowServer::ProcessWindowBoundsChanged(
+ const ServerWindow* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) {
for (auto& pair : tree_map_) {
pair.second->ProcessWindowBoundsChanged(window, old_bounds, new_bounds,
- IsOperationSource(pair.first));
+ IsOperationSource(pair.first),
+ local_surface_id);
}
}
@@ -415,7 +418,8 @@ void WindowServer::ProcessWindowDeleted(ServerWindow* window) {
}
void WindowServer::ProcessWillChangeWindowPredefinedCursor(
- ServerWindow* window, mojom::Cursor cursor_id) {
+ ServerWindow* window,
+ mojom::CursorType cursor_id) {
for (auto& pair : tree_map_) {
pair.second->ProcessCursorChanged(window, cursor_id,
IsOperationSource(pair.first));
@@ -529,8 +533,8 @@ WindowManagerState* WindowServer::GetWindowManagerStateForUser(
user_id);
}
-cc::mojom::DisplayCompositor* WindowServer::GetDisplayCompositor() {
- return display_compositor_.get();
+cc::mojom::FrameSinkManager* WindowServer::GetFrameSinkManager() {
+ return frame_sink_manager_.get();
}
bool WindowServer::GetFrameDecorationsForUser(
@@ -632,7 +636,7 @@ void WindowServer::HandleTemporaryReferenceForNewSurface(
current->GetOrCreateCompositorFrameSinkManager()->ClaimTemporaryReference(
surface_id);
} else {
- display_compositor_->DropTemporaryReference(surface_id);
+ frame_sink_manager_->DropTemporaryReference(surface_id);
}
}
@@ -669,11 +673,11 @@ void WindowServer::OnWindowHierarchyChanged(ServerWindow* window,
ProcessWindowHierarchyChanged(window, new_parent, old_parent);
if (old_parent) {
- display_compositor_->UnregisterFrameSinkHierarchy(
+ frame_sink_manager_->UnregisterFrameSinkHierarchy(
old_parent->frame_sink_id(), window->frame_sink_id());
}
if (new_parent) {
- display_compositor_->RegisterFrameSinkHierarchy(new_parent->frame_sink_id(),
+ frame_sink_manager_->RegisterFrameSinkHierarchy(new_parent->frame_sink_id(),
window->frame_sink_id());
}
@@ -686,7 +690,8 @@ void WindowServer::OnWindowBoundsChanged(ServerWindow* window,
if (in_destructor_)
return;
- ProcessWindowBoundsChanged(window, old_bounds, new_bounds);
+ ProcessWindowBoundsChanged(window, old_bounds, new_bounds,
+ window->current_local_surface_id());
if (!window->parent())
return;
@@ -745,8 +750,9 @@ void WindowServer::OnWindowVisibilityChanged(ServerWindow* window) {
window);
}
-void WindowServer::OnWindowPredefinedCursorChanged(ServerWindow* window,
- mojom::Cursor cursor_id) {
+void WindowServer::OnWindowPredefinedCursorChanged(
+ ServerWindow* window,
+ mojom::CursorType cursor_id) {
if (in_destructor_)
return;
@@ -756,7 +762,7 @@ void WindowServer::OnWindowPredefinedCursorChanged(ServerWindow* window,
}
void WindowServer::OnWindowNonClientCursorChanged(ServerWindow* window,
- mojom::Cursor cursor_id) {
+ mojom::CursorType cursor_id) {
if (in_destructor_)
return;
@@ -810,7 +816,7 @@ void WindowServer::OnSurfaceCreated(const cc::SurfaceInfo& surface_info) {
// If the window doesn't exist then we have nothing to propagate.
if (!window) {
- display_compositor_->DropTemporaryReference(surface_info.id());
+ frame_sink_manager_->DropTemporaryReference(surface_info.id());
return;
}
diff --git a/chromium/services/ui/ws/window_server.h b/chromium/services/ui/ws/window_server.h
index fce14fad9a3..d01c2e00913 100644
--- a/chromium/services/ui/ws/window_server.h
+++ b/chromium/services/ui/ws/window_server.h
@@ -14,7 +14,7 @@
#include "base/macros.h"
#include "base/optional.h"
-#include "cc/ipc/display_compositor.mojom.h"
+#include "cc/ipc/frame_sink_manager.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "services/ui/public/interfaces/window_manager_window_tree_factory.mojom.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
@@ -49,7 +49,7 @@ class WindowServer : public ServerWindowDelegate,
public GpuHostDelegate,
public UserDisplayManagerDelegate,
public UserIdTrackerObserver,
- public cc::mojom::DisplayCompositorClient {
+ public cc::mojom::FrameSinkManagerClient {
public:
explicit WindowServer(WindowServerDelegate* delegate);
~WindowServer() override;
@@ -91,7 +91,8 @@ class WindowServer : public ServerWindowDelegate,
WindowTree* CreateTreeForWindowManager(
const UserId& user_id,
mojom::WindowTreeRequest window_tree_request,
- mojom::WindowTreeClientPtr window_tree_client);
+ mojom::WindowTreeClientPtr window_tree_client,
+ bool automatically_create_display_roots);
// Invoked when a WindowTree's connection encounters an error.
void DestroyTree(WindowTree* tree);
@@ -142,7 +143,6 @@ class WindowServer : public ServerWindowDelegate,
bool SetFocusedWindow(ServerWindow* window);
ServerWindow* GetFocusedWindow();
- bool IsActiveUserInHighContrastMode() const;
void SetHighContrastMode(const UserId& user, bool enabled);
// Returns a change id for the window manager that is associated with
@@ -167,9 +167,11 @@ class WindowServer : public ServerWindowDelegate,
// These functions trivially delegate to all WindowTrees, which in
// term notify their clients.
- void ProcessWindowBoundsChanged(const ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds);
+ void ProcessWindowBoundsChanged(
+ const ServerWindow* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id);
void ProcessClientAreaChanged(
const ServerWindow* window,
const gfx::Insets& new_client_area,
@@ -187,7 +189,7 @@ class WindowServer : public ServerWindowDelegate,
const mojom::OrderDirection direction);
void ProcessWindowDeleted(ServerWindow* window);
void ProcessWillChangeWindowPredefinedCursor(ServerWindow* window,
- mojom::Cursor cursor_id);
+ mojom::CursorType cursor_id);
// 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
@@ -228,7 +230,7 @@ class WindowServer : public ServerWindowDelegate,
WindowManagerState* GetWindowManagerStateForUser(const UserId& user_id);
// ServerWindowDelegate:
- cc::mojom::DisplayCompositor* GetDisplayCompositor() override;
+ cc::mojom::FrameSinkManager* GetFrameSinkManager() override;
// UserDisplayManagerDelegate:
bool GetFrameDecorationsForUser(
@@ -321,9 +323,9 @@ class WindowServer : public ServerWindowDelegate,
const std::string& name,
const std::vector<uint8_t>* new_data) override;
void OnWindowPredefinedCursorChanged(ServerWindow* window,
- mojom::Cursor cursor_id) override;
+ mojom::CursorType cursor_id) override;
void OnWindowNonClientCursorChanged(ServerWindow* window,
- mojom::Cursor cursor_id) override;
+ mojom::CursorType cursor_id) override;
void OnWindowTextInputStateChanged(ServerWindow* window,
const ui::TextInputState& state) override;
void OnTransientWindowAdded(ServerWindow* window,
@@ -334,7 +336,7 @@ class WindowServer : public ServerWindowDelegate,
// GpuHostDelegate:
void OnGpuServiceInitialized() override;
- // cc::mojom::DisplayCompositorClient:
+ // cc::mojom::FrameSinkManagerClient:
void OnSurfaceCreated(const cc::SurfaceInfo& surface_info) override;
// UserIdTrackerObserver:
@@ -381,10 +383,10 @@ class WindowServer : public ServerWindowDelegate,
cc::SurfaceId root_surface_id_;
- mojo::Binding<cc::mojom::DisplayCompositorClient>
- display_compositor_client_binding_;
- // State for rendering into a Surface.
- cc::mojom::DisplayCompositorPtr display_compositor_;
+ // Provides interfaces to create and manage FrameSinks.
+ mojo::Binding<cc::mojom::FrameSinkManagerClient>
+ frame_sink_manager_client_binding_;
+ cc::mojom::FrameSinkManagerPtr frame_sink_manager_;
DISALLOW_COPY_AND_ASSIGN(WindowServer);
};
diff --git a/chromium/services/ui/ws/window_server_service_test_base.cc b/chromium/services/ui/ws/window_server_service_test_base.cc
index 4289dca2f44..ab3f357ce73 100644
--- a/chromium/services/ui/ws/window_server_service_test_base.cc
+++ b/chromium/services/ui/ws/window_server_service_test_base.cc
@@ -29,9 +29,11 @@ class WindowServerServiceTestClient
private:
// service_manager::test::ServiceTestClient:
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override {
- return test_->OnConnect(remote_info.identity, registry);
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
+ test_->OnBindInterface(source_info, interface_name,
+ std::move(interface_pipe));
}
WindowServerServiceTestBase* test_;
diff --git a/chromium/services/ui/ws/window_server_service_test_base.h b/chromium/services/ui/ws/window_server_service_test_base.h
index e3635257136..8cff44c98a5 100644
--- a/chromium/services/ui/ws/window_server_service_test_base.h
+++ b/chromium/services/ui/ws/window_server_service_test_base.h
@@ -6,7 +6,6 @@
#define SERVICES_UI_WS_WINDOW_SERVER_SERVICE_TEST_BASE_H_
#include "base/macros.h"
-#include "services/service_manager/public/cpp/connection.h"
#include "services/service_manager/public/cpp/service_test.h"
namespace ui {
@@ -17,8 +16,10 @@ class WindowServerServiceTestBase : public service_manager::test::ServiceTest {
WindowServerServiceTestBase();
~WindowServerServiceTestBase() override;
- virtual bool OnConnect(const service_manager::Identity& remote_identity,
- service_manager::InterfaceRegistry* registry) = 0;
+ virtual void OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) = 0;
private:
// service_manager::test::ServiceTest:
diff --git a/chromium/services/ui/ws/window_server_test_base.cc b/chromium/services/ui/ws/window_server_test_base.cc
index 492bad06abb..2062520b7b0 100644
--- a/chromium/services/ui/ws/window_server_test_base.cc
+++ b/chromium/services/ui/ws/window_server_test_base.cc
@@ -12,7 +12,6 @@
#include "base/test/test_timeouts.h"
#include "base/threading/thread_task_runner_handle.h"
#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
#include "ui/aura/env.h"
#include "ui/aura/mus/window_tree_client.h"
#include "ui/aura/mus/window_tree_host_mus.h"
@@ -33,7 +32,9 @@ void TimeoutRunLoop(const base::Closure& timeout_task, bool* timeout) {
} // namespace
-WindowServerTestBase::WindowServerTestBase() {}
+WindowServerTestBase::WindowServerTestBase() {
+ registry_.AddInterface<mojom::WindowTreeClient>(this);
+}
WindowServerTestBase::~WindowServerTestBase() {}
@@ -114,11 +115,12 @@ void WindowServerTestBase::TearDown() {
WindowServerServiceTestBase::TearDown();
}
-bool WindowServerTestBase::OnConnect(
- const service_manager::Identity& remote_identity,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface<mojom::WindowTreeClient>(this);
- return true;
+void WindowServerTestBase::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
void WindowServerTestBase::OnEmbed(
@@ -152,11 +154,11 @@ void WindowServerTestBase::SetWindowManagerClient(
window_manager_client_ = client;
}
-bool WindowServerTestBase::OnWmSetBounds(aura::Window* window,
- gfx::Rect* bounds) {
- return window_manager_delegate_
- ? window_manager_delegate_->OnWmSetBounds(window, bounds)
- : true;
+void WindowServerTestBase::OnWmSetBounds(aura::Window* window,
+ const gfx::Rect& bounds) {
+ if (!window_manager_delegate_)
+ return;
+ window_manager_delegate_->OnWmSetBounds(window, bounds);
}
bool WindowServerTestBase::OnWmSetProperty(
@@ -168,6 +170,12 @@ bool WindowServerTestBase::OnWmSetProperty(
: true;
}
+void WindowServerTestBase::OnWmSetModalType(aura::Window* window,
+ ui::ModalType type) {
+ if (window_manager_delegate_)
+ window_manager_delegate_->OnWmSetModalType(window, type);
+}
+
void WindowServerTestBase::OnWmSetCanFocus(aura::Window* window,
bool can_focus) {
if (window_manager_delegate_)
@@ -225,10 +233,11 @@ void WindowServerTestBase::OnWmDisplayModified(
ui::mojom::EventResult WindowServerTestBase::OnAccelerator(
uint32_t accelerator_id,
- const ui::Event& event) {
- return window_manager_delegate_
- ? window_manager_delegate_->OnAccelerator(accelerator_id, event)
- : ui::mojom::EventResult::UNHANDLED;
+ const ui::Event& event,
+ std::unordered_map<std::string, std::vector<uint8_t>>* properties) {
+ return window_manager_delegate_ ? window_manager_delegate_->OnAccelerator(
+ accelerator_id, event, properties)
+ : ui::mojom::EventResult::UNHANDLED;
}
void WindowServerTestBase::OnWmPerformMoveLoop(
@@ -271,8 +280,10 @@ void WindowServerTestBase::OnWmDeactivateWindow(aura::Window* window) {
void WindowServerTestBase::Create(
const service_manager::Identity& remote_identity,
mojom::WindowTreeClientRequest request) {
+ const bool create_discardable_memory = false;
window_tree_clients_.push_back(base::MakeUnique<aura::WindowTreeClient>(
- connector(), this, nullptr, std::move(request)));
+ connector(), this, nullptr, std::move(request), nullptr,
+ create_discardable_memory));
}
bool WindowServerTestBase::DeleteWindowTreeHost(
diff --git a/chromium/services/ui/ws/window_server_test_base.h b/chromium/services/ui/ws/window_server_test_base.h
index c983761d2bc..d5b0ec36cd9 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 "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
#include "services/ui/ws/window_server_service_test_base.h"
@@ -74,8 +75,9 @@ class WindowServerTestBase
void TearDown() override;
// WindowServerServiceTestBase:
- bool OnConnect(const service_manager::Identity& remote_identity,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// WindowTreeClientDelegate:
void OnEmbed(
@@ -88,24 +90,34 @@ class WindowServerTestBase
// WindowManagerDelegate:
void SetWindowManagerClient(aura::WindowManagerClient* client) override;
- bool OnWmSetBounds(aura::Window* window, gfx::Rect* bounds) override;
+ void OnWmSetBounds(aura::Window* window, const gfx::Rect& bounds) override;
bool OnWmSetProperty(
aura::Window* window,
const std::string& name,
std::unique_ptr<std::vector<uint8_t>>* new_data) override;
+ void OnWmSetModalType(aura::Window* window, ui::ModalType type) override;
void OnWmSetCanFocus(aura::Window* window, bool can_focus) override;
aura::Window* OnWmCreateTopLevelWindow(
ui::mojom::WindowType window_type,
std::map<std::string, std::vector<uint8_t>>* properties) override;
void OnWmClientJankinessChanged(const std::set<aura::Window*>& client_windows,
bool not_responding) override;
+ void OnWmBuildDragImage(const gfx::Point& screen_location,
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ ui::mojom::PointerKind source) override {}
+ void OnWmMoveDragImage(const gfx::Point& screen_location) override {}
+ void OnWmDestroyDragImage() override {}
void OnWmWillCreateDisplay(const display::Display& display) override;
void OnWmNewDisplay(std::unique_ptr<aura::WindowTreeHostMus> window_tree_host,
const display::Display& display) override;
void OnWmDisplayRemoved(aura::WindowTreeHostMus* window_tree_host) override;
void OnWmDisplayModified(const display::Display& display) override;
- mojom::EventResult OnAccelerator(uint32_t accelerator_id,
- const ui::Event& event) override;
+ mojom::EventResult OnAccelerator(
+ uint32_t accelerator_id,
+ const ui::Event& event,
+ std::unordered_map<std::string, std::vector<uint8_t>>* properties)
+ override;
void OnWmPerformMoveLoop(aura::Window* window,
mojom::MoveLoopSource source,
const gfx::Point& cursor_location,
@@ -149,6 +161,8 @@ class WindowServerTestBase
bool window_tree_client_lost_connection_ = false;
+ service_manager::BinderRegistry registry_;
+
DISALLOW_COPY_AND_ASSIGN(WindowServerTestBase);
};
diff --git a/chromium/services/ui/ws/window_server_test_impl.cc b/chromium/services/ui/ws/window_server_test_impl.cc
index 20bc295c323..7e580aed937 100644
--- a/chromium/services/ui/ws/window_server_test_impl.cc
+++ b/chromium/services/ui/ws/window_server_test_impl.cc
@@ -5,6 +5,8 @@
#include "services/ui/ws/window_server_test_impl.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
+#include "services/ui/ws/display.h"
+#include "services/ui/ws/display_manager.h"
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/server_window_compositor_frame_sink_manager.h"
#include "services/ui/ws/window_server.h"
@@ -49,5 +51,28 @@ void WindowServerTestImpl::EnsureClientHasDrawnWindow(
client_name, std::move(callback)));
}
+void WindowServerTestImpl::DispatchEvent(int64_t display_id,
+ std::unique_ptr<ui::Event> event,
+ const DispatchEventCallback& cb) {
+ DisplayManager* manager = window_server_->display_manager();
+ if (!manager) {
+ DVLOG(1) << "No display manager in DispatchEvent.";
+ cb.Run(false);
+ return;
+ }
+
+ Display* display = manager->GetDisplayById(display_id);
+ if (!display) {
+ DVLOG(1) << "Invalid display_id in DispatchEvent.";
+ cb.Run(false);
+ return;
+ }
+
+ ignore_result(static_cast<PlatformDisplayDelegate*>(display)
+ ->GetEventSink()
+ ->OnEventFromSource(event.get()));
+ cb.Run(true);
+}
+
} // namespace ws
} // namespace ui
diff --git a/chromium/services/ui/ws/window_server_test_impl.h b/chromium/services/ui/ws/window_server_test_impl.h
index 9a6dc788ee4..17fa60beaf8 100644
--- a/chromium/services/ui/ws/window_server_test_impl.h
+++ b/chromium/services/ui/ws/window_server_test_impl.h
@@ -27,6 +27,9 @@ class WindowServerTestImpl : public mojom::WindowServerTest {
void EnsureClientHasDrawnWindow(
const std::string& client_name,
const EnsureClientHasDrawnWindowCallback& callback) override;
+ void DispatchEvent(int64_t display_id,
+ std::unique_ptr<ui::Event> event,
+ const DispatchEventCallback& cb) override;
WindowServer* window_server_;
diff --git a/chromium/services/ui/ws/window_tree.cc b/chromium/services/ui/ws/window_tree.cc
index f642e1f1c32..85acf92d84d 100644
--- a/chromium/services/ui/ws/window_tree.cc
+++ b/chromium/services/ui/ws/window_tree.cc
@@ -35,6 +35,8 @@
using mojo::InterfaceRequest;
+using EventProperties = std::unordered_map<std::string, std::vector<uint8_t>>;
+
namespace ui {
namespace ws {
@@ -66,6 +68,16 @@ class TargetedEvent : public ServerWindowObserver {
DISALLOW_COPY_AND_ASSIGN(TargetedEvent);
};
+struct WindowTree::DragMoveState {
+ // Whether we've queued a move to |queued_cursor_location_| when we get an
+ // ack from WmMoveDragImage.
+ bool has_queued_drag_window_move = false;
+
+ // When |has_queued_drag_window_move_| is true, this is a location which
+ // should be sent to the window manager as soon as it acked the last one.
+ gfx::Point queued_cursor_location;
+};
+
WindowTree::WindowTree(WindowServer* window_server,
const UserId& user_id,
ServerWindow* root,
@@ -76,7 +88,8 @@ WindowTree::WindowTree(WindowServer* window_server,
next_window_id_(1),
access_policy_(std::move(access_policy)),
event_ack_id_(0),
- window_manager_internal_(nullptr) {
+ window_manager_internal_(nullptr),
+ drag_weak_factory_(this) {
if (root)
roots_.insert(root);
access_policy_->Init(id_, this);
@@ -88,8 +101,10 @@ WindowTree::~WindowTree() {
// We alert the WindowManagerState that we're destroying this state here
// because WindowManagerState would attempt to use things that wouldn't have
// been cleaned up by OnWindowDestroyingTreeImpl().
- if (window_manager_state_)
+ if (window_manager_state_) {
window_manager_state_->OnWillDestroyTree(this);
+ window_manager_state_.reset();
+ }
}
void WindowTree::Init(std::unique_ptr<WindowTreeBinding> binding,
@@ -117,10 +132,12 @@ void WindowTree::Init(std::unique_ptr<WindowTreeBinding> binding,
const bool drawn = root->parent() && root->parent()->IsDrawn();
client()->OnEmbed(id_, WindowToWindowData(to_send.front()), std::move(tree),
- display_id, focused_window_id.id, drawn);
+ display_id, focused_window_id.id, drawn,
+ root->frame_sink_id(), root->current_local_surface_id());
}
-void WindowTree::ConfigureWindowManager() {
+void WindowTree::ConfigureWindowManager(
+ bool automatically_create_display_roots) {
// ConfigureWindowManager() should be called early on, before anything
// else. |waiting_for_top_level_window_info_| must be null as if
// |waiting_for_top_level_window_info_| is non-null it means we're about to
@@ -128,6 +145,7 @@ void WindowTree::ConfigureWindowManager() {
// TODO(sky): DCHECK temporary until 626869 is sorted out.
DCHECK(!waiting_for_top_level_window_info_);
DCHECK(!window_manager_internal_);
+ automatically_create_display_roots_ = automatically_create_display_roots;
window_manager_internal_ = binding_->GetWindowManager();
window_manager_internal_->OnConnect(id_);
window_manager_state_ = base::MakeUnique<WindowManagerState>(this);
@@ -190,6 +208,10 @@ void WindowTree::PrepareForWindowServerShutdown() {
}
void WindowTree::AddRootForWindowManager(const ServerWindow* root) {
+ if (!automatically_create_display_roots_)
+ return;
+
+ DCHECK(automatically_create_display_roots_);
DCHECK(window_manager_internal_);
const ClientWindowId client_window_id(WindowIdToTransportId(root->id()));
DCHECK_EQ(0u, client_id_to_window_id_map_.count(client_window_id));
@@ -197,12 +219,13 @@ void WindowTree::AddRootForWindowManager(const ServerWindow* root) {
window_id_to_client_id_map_[root->id()] = client_window_id;
roots_.insert(root);
- Display* display = GetDisplay(root);
- DCHECK(display);
+ Display* ws_display = GetDisplay(root);
+ DCHECK(ws_display);
- window_manager_internal_->WmNewDisplayAdded(display->ToDisplay(),
- WindowToWindowData(root),
- root->parent()->IsDrawn());
+ window_manager_internal_->WmNewDisplayAdded(
+ ws_display->GetDisplay(), WindowToWindowData(root),
+ root->parent()->IsDrawn(), root->frame_sink_id(),
+ root->current_local_surface_id());
}
void WindowTree::OnWindowDestroyingTreeImpl(WindowTree* tree) {
@@ -230,6 +253,62 @@ void WindowTree::NotifyChangeCompleted(
change_id, error_code == mojom::WindowManagerErrorCode::SUCCESS);
}
+void WindowTree::OnWmMoveDragImageAck() {
+ if (drag_move_state_->has_queued_drag_window_move) {
+ gfx::Point queued_location = drag_move_state_->queued_cursor_location;
+ drag_move_state_.reset();
+ OnDragMoved(queued_location);
+ } else {
+ drag_move_state_.reset();
+ }
+}
+
+bool WindowTree::ProcessSetDisplayRoot(int64_t display_id,
+ const ClientWindowId& client_window_id) {
+ DCHECK(window_manager_state_); // Only called for window manager.
+ Display* display =
+ window_server_->display_manager()->GetDisplayById(display_id);
+ if (!display) {
+ DVLOG(1) << "SetDisplayRoot called with unknown display " << display_id;
+ return false;
+ }
+
+ if (automatically_create_display_roots_) {
+ DVLOG(1) << "SetDisplayRoot is only applicable when "
+ << "automatically_create_display_roots is false";
+ return false;
+ }
+
+ ServerWindow* window = GetWindowByClientId(client_window_id);
+ // The window must not have a parent.
+ if (!window || window->parent()) {
+ DVLOG(1) << "SetDisplayRoot called with invalid window id "
+ << client_window_id.id;
+ return false;
+ }
+
+ WindowManagerDisplayRoot* display_root =
+ display->GetWindowManagerDisplayRootForUser(
+ window_manager_state_->user_id());
+ DCHECK(display_root);
+ if (!display_root->root()->children().empty()) {
+ DVLOG(1) << "SetDisplayRoot called more than once";
+ return false;
+ }
+
+ if (base::ContainsValue(roots_, window)) {
+ DVLOG(1) << "SetDisplayRoot called with existing root";
+ return false;
+ }
+
+ // NOTE: this doesn't resize the window in anyway. We assume the client takes
+ // care of any modifications it needs to do.
+ roots_.insert(window);
+ Operation op(this, window_server_, OperationType::ADD_WINDOW);
+ display_root->root()->Add(window);
+ return true;
+}
+
bool WindowTree::SetCapture(const ClientWindowId& client_window_id) {
ServerWindow* window = GetWindowByClientId(client_window_id);
WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(window);
@@ -352,25 +431,58 @@ bool WindowTree::DeleteWindow(const ClientWindowId& window_id) {
return tree && tree->DeleteWindowImpl(this, window);
}
-bool WindowTree::SetModal(const ClientWindowId& window_id) {
+bool WindowTree::SetModalType(const ClientWindowId& window_id,
+ ModalType modal_type) {
ServerWindow* window = GetWindowByClientId(window_id);
- if (window && access_policy_->CanSetModal(window)) {
- WindowManagerDisplayRoot* display_root =
- GetWindowManagerDisplayRoot(window);
- if (window->transient_parent()) {
- window->SetModal();
- } else if (user_id_ != InvalidUserId()) {
- if (display_root)
- display_root->window_manager_state()->AddSystemModalWindow(window);
- } else {
- return false;
- }
- if (display_root)
- display_root->window_manager_state()->ReleaseCaptureBlockedByModalWindow(
- window);
+ if (!window) {
+ DVLOG(1) << "SetModalType failed (invalid id)";
+ return false;
+ }
+
+ if (ShouldRouteToWindowManager(window)) {
+ WindowTree* wm_tree = GetWindowManagerDisplayRoot(window)
+ ->window_manager_state()
+ ->window_tree();
+ wm_tree->window_manager_internal_->WmSetModalType(
+ wm_tree->ClientWindowIdForWindow(window).id, modal_type);
return true;
}
- return false;
+
+ if (!access_policy_->CanSetModal(window)) {
+ DVLOG(1) << "SetModalType failed (access denied)";
+ return false;
+ }
+
+ if (window->modal_type() == modal_type)
+ return true;
+
+ // TODO(moshayedi): crbug.com/697176. When modality of a window that used to
+ // be a system modal changes, notify window manager state.
+ auto* display_root = GetWindowManagerDisplayRoot(window);
+ switch (modal_type) {
+ case MODAL_TYPE_SYSTEM:
+ if (user_id_ == InvalidUserId()) {
+ DVLOG(1) << "SetModalType failed (invalid user id)";
+ return false;
+ }
+ if (!display_root) {
+ DVLOG(1) << "SetModalType failed (no display root)";
+ return false;
+ }
+ window->SetModalType(modal_type);
+ display_root->window_manager_state()->AddSystemModalWindow(window);
+ break;
+ case MODAL_TYPE_NONE:
+ case MODAL_TYPE_WINDOW:
+ case MODAL_TYPE_CHILD:
+ window->SetModalType(modal_type);
+ break;
+ }
+ if (display_root && modal_type != MODAL_TYPE_NONE) {
+ display_root->window_manager_state()->ReleaseCaptureBlockedByModalWindow(
+ window);
+ }
+ return true;
}
std::vector<const ServerWindow*> WindowTree::GetWindowTree(
@@ -434,17 +546,18 @@ bool WindowTree::SetFocus(const ClientWindowId& window_id) {
}
bool WindowTree::Embed(const ClientWindowId& window_id,
- mojom::WindowTreeClientPtr client,
+ mojom::WindowTreeClientPtr window_tree_client,
uint32_t flags) {
- if (!client || !CanEmbed(window_id))
+ if (!window_tree_client || !CanEmbed(window_id))
return false;
ServerWindow* window = GetWindowByClientId(window_id);
PrepareForEmbed(window);
// 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(client),
- flags,
+ window_server_->EmbedAtWindow(window, InvalidUserId(),
+ std::move(window_tree_client), flags,
base::WrapUnique(new DefaultAccessPolicy));
+ client()->OnFrameSinkIdAllocated(window_id.id, window->frame_sink_id());
return true;
}
@@ -499,7 +612,8 @@ void WindowTree::OnWindowManagerCreatedTopLevelWindow(
int64_t display_id = display ? display->GetId() : display::kInvalidDisplayId;
const bool drawn = window->parent() && window->parent()->IsDrawn();
client()->OnTopLevelCreated(client_change_id, WindowToWindowData(window),
- display_id, drawn);
+ display_id, drawn, window->frame_sink_id(),
+ window->current_local_surface_id());
}
void WindowTree::AddActivationParent(const ClientWindowId& window_id) {
@@ -522,6 +636,7 @@ void WindowTree::OnChangeCompleted(uint32_t change_id, bool success) {
void WindowTree::OnAccelerator(uint32_t accelerator_id,
const ui::Event& event,
bool needs_ack) {
+ DVLOG(3) << "OnAccelerator client=" << id_;
DCHECK(window_manager_internal_);
if (needs_ack)
GenerateEventAckId();
@@ -535,7 +650,9 @@ void WindowTree::OnAccelerator(uint32_t accelerator_id,
void WindowTree::OnDisplayDestroying(int64_t display_id) {
DCHECK(window_manager_internal_);
- window_manager_internal_->WmDisplayRemoved(display_id);
+ if (automatically_create_display_roots_)
+ window_manager_internal_->WmDisplayRemoved(display_id);
+ // For the else case the client should detect removal directly.
}
void WindowTree::ClientJankinessChanged(WindowTree* tree) {
@@ -548,14 +665,17 @@ void WindowTree::ClientJankinessChanged(WindowTree* tree) {
}
}
-void WindowTree::ProcessWindowBoundsChanged(const ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds,
- bool originated_change) {
+void WindowTree::ProcessWindowBoundsChanged(
+ const ServerWindow* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ bool originated_change,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) {
ClientWindowId client_window_id;
if (originated_change || !IsWindowKnown(window, &client_window_id))
return;
- client()->OnWindowBoundsChanged(client_window_id.id, old_bounds, new_bounds);
+ client()->OnWindowBoundsChanged(client_window_id.id, old_bounds, new_bounds,
+ local_surface_id);
}
void WindowTree::ProcessClientAreaChanged(
@@ -726,7 +846,7 @@ void WindowTree::ProcessWindowOpacityChanged(const ServerWindow* window,
}
void WindowTree::ProcessCursorChanged(const ServerWindow* window,
- mojom::Cursor cursor_id,
+ mojom::CursorType cursor_id,
bool originated_change) {
if (originated_change)
return;
@@ -980,11 +1100,19 @@ void WindowTree::RemoveRoot(ServerWindow* window, RemoveRootReason reason) {
DCHECK(roots_.count(window) > 0);
roots_.erase(window);
- const ClientWindowId client_window_id(ClientWindowIdForWindow(window));
-
- // No need to do anything if we created the window.
- if (window->id().client_id == id_)
+ if (window->id().client_id == id_) {
+ // This cllient 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.
+ if (window_manager_state_ && !automatically_create_display_roots_) {
+ // The window manager is asking to delete the root it created.
+ window_manager_state_->DeleteWindowManagerDisplayRoot(window->parent());
+ DeleteWindowImpl(this, window);
+ }
return;
+ }
+
+ const ClientWindowId client_window_id(ClientWindowIdForWindow(window));
if (reason == RemoveRootReason::EMBED) {
client()->OnUnembed(client_window_id.id);
@@ -1141,6 +1269,7 @@ uint32_t WindowTree::GenerateEventAckId() {
void WindowTree::DispatchInputEventImpl(ServerWindow* target,
const ui::Event& event) {
+ DVLOG(3) << "DispatchInputEventImpl client=" << id_;
GenerateEventAckId();
WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(target);
DCHECK(display_root);
@@ -1278,8 +1407,11 @@ void WindowTree::RemoveTransientWindowFromParent(uint32_t change_id,
client()->OnChangeCompleted(change_id, success);
}
-void WindowTree::SetModal(uint32_t change_id, Id window_id) {
- client()->OnChangeCompleted(change_id, SetModal(ClientWindowId(window_id)));
+void WindowTree::SetModalType(uint32_t change_id,
+ Id window_id,
+ ModalType modal_type) {
+ client()->OnChangeCompleted(
+ change_id, SetModalType(ClientWindowId(window_id), modal_type));
}
void WindowTree::ReorderWindow(uint32_t change_id,
@@ -1336,11 +1468,16 @@ void WindowTree::StopPointerWatcher() {
pointer_watcher_want_moves_ = false;
}
-void WindowTree::SetWindowBounds(uint32_t change_id,
- Id window_id,
- const gfx::Rect& bounds) {
+void WindowTree::SetWindowBounds(
+ uint32_t change_id,
+ Id window_id,
+ const gfx::Rect& bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) {
ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id));
if (window && ShouldRouteToWindowManager(window)) {
+ DVLOG(3) << "Redirecting request to change bounds for "
+ << (window ? WindowIdToTransportId(window->id()) : 0)
+ << " to window manager...";
const uint32_t wm_change_id =
window_server_->GenerateWindowManagerChangeId(this, change_id);
// |window_id| may be a client id, use the id from the window to ensure
@@ -1362,7 +1499,9 @@ void WindowTree::SetWindowBounds(uint32_t change_id,
bool success = window && access_policy_->CanSetWindowBounds(window);
if (success) {
Operation op(this, window_server_, OperationType::SET_WINDOW_BOUNDS);
- window->SetBounds(bounds);
+ window->SetBounds(bounds, local_surface_id);
+ } else {
+ DVLOG(1) << "Failed to set bounds on window.";
}
client()->OnChangeCompleted(change_id, success);
}
@@ -1454,6 +1593,7 @@ void WindowTree::SetImeVisibility(Id transport_window_id,
void WindowTree::OnWindowInputEventAck(uint32_t event_id,
mojom::EventResult result) {
+ DVLOG(3) << "OnWindowInputEventAck client=" << id_;
if (event_ack_id_ == 0 || event_id != event_ack_id_) {
// TODO(sad): Something bad happened. Kill the client?
NOTIMPLEMENTED() << ": Wrong event acked. event_id=" << event_id
@@ -1579,7 +1719,7 @@ void WindowTree::SetEventTargetingPolicy(Id transport_window_id,
void WindowTree::SetPredefinedCursor(uint32_t change_id,
Id transport_window_id,
- ui::mojom::Cursor cursor_id) {
+ ui::mojom::CursorType cursor_id) {
ServerWindow* window =
GetWindowByClientId(ClientWindowId(transport_window_id));
@@ -1616,20 +1756,20 @@ void WindowTree::DeactivateWindow(Id window_id) {
void WindowTree::StackAbove(uint32_t change_id, Id above_id, Id below_id) {
ServerWindow* above = GetWindowByClientId(ClientWindowId(above_id));
if (!above) {
- DVLOG(1) << "StackAtTop failed (invalid above id)";
+ DVLOG(1) << "StackAbove failed (invalid above id)";
client()->OnChangeCompleted(change_id, false);
return;
}
ServerWindow* below = GetWindowByClientId(ClientWindowId(below_id));
if (!below) {
- DVLOG(1) << "StackAtTop failed (invalid below id)";
+ DVLOG(1) << "StackAbove failed (invalid below id)";
client()->OnChangeCompleted(change_id, false);
return;
}
if (!access_policy_->CanStackAbove(above, below)) {
- DVLOG(1) << "StackAtTop failed (access denied)";
+ DVLOG(1) << "StackAbove failed (access denied)";
client()->OnChangeCompleted(change_id, false);
return;
}
@@ -1637,24 +1777,24 @@ void WindowTree::StackAbove(uint32_t change_id, Id above_id, Id below_id) {
ServerWindow* parent = above->parent();
ServerWindow* below_parent = below->parent();
if (!parent) {
- DVLOG(1) << "StackAtTop failed (above unparented)";
+ DVLOG(1) << "StackAbove failed (above unparented)";
client()->OnChangeCompleted(change_id, false);
return;
}
if (!below_parent) {
- DVLOG(1) << "StackAtTop failed (below unparented)";
+ DVLOG(1) << "StackAbove failed (below unparented)";
client()->OnChangeCompleted(change_id, false);
return;
}
if (parent != below_parent) {
- DVLOG(1) << "StackAtTop failed (windows have different parents)";
+ DVLOG(1) << "StackAbove failed (windows have different parents)";
client()->OnChangeCompleted(change_id, false);
return;
}
WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(above);
if (!display_root) {
- DVLOG(1) << "StackAtTop (no display root)";
+ DVLOG(1) << "StackAbove (no display root)";
client()->OnChangeCompleted(change_id, false);
return;
}
@@ -1738,15 +1878,23 @@ void WindowTree::GetCursorLocationMemory(
void WindowTree::PerformDragDrop(
uint32_t change_id,
Id source_window_id,
+ const gfx::Point& screen_location,
const std::unordered_map<std::string, std::vector<uint8_t>>& drag_data,
- uint32_t drag_operation) {
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ uint32_t drag_operation,
+ ui::mojom::PointerKind source) {
+ // TODO(erg): SkBitmap is the wrong data type for the drag image; we should
+ // be passing ImageSkias once http://crbug.com/655874 is implemented.
+
ServerWindow* window = GetWindowByClientId(ClientWindowId(source_window_id));
bool success = window && access_policy_->CanInitiateDragLoop(window);
if (!success || !ShouldRouteToWindowManager(window)) {
// We need to fail this move loop change, otherwise the client will just be
// waiting for |change_id|.
DVLOG(1) << "PerformDragDrop failed (access denied).";
- OnChangeCompleted(change_id, false);
+ client()->OnPerformDragDropCompleted(change_id, false,
+ mojom::kDropEffectNone);
return;
}
@@ -1754,7 +1902,8 @@ void WindowTree::PerformDragDrop(
if (!display_root) {
// The window isn't parented. There's nothing to do.
DVLOG(1) << "PerformDragDrop failed (window unparented).";
- OnChangeCompleted(change_id, false);
+ client()->OnPerformDragDropCompleted(change_id, false,
+ mojom::kDropEffectNone);
return;
}
@@ -1762,17 +1911,20 @@ void WindowTree::PerformDragDrop(
// Either the window manager is servicing a window drag or we're servicing
// a drag and drop operation. We can't start a second drag.
DVLOG(1) << "PerformDragDrop failed (already performing a drag).";
- OnChangeCompleted(change_id, false);
+ client()->OnPerformDragDropCompleted(change_id, false,
+ mojom::kDropEffectNone);
return;
}
- // TODO(erg): Dealing with |drag_representation| is hard, so we're going to
- // deal with that later.
+ WindowManagerState* wms = display_root->window_manager_state();
+
+ // Send the drag representation to the window manager.
+ wms->window_tree()->window_manager_internal_->WmBuildDragImage(
+ screen_location, drag_image, drag_image_offset, source);
// Here, we need to dramatically change how the mouse pointer works. Once
// we've started a drag drop operation, cursor events don't go to windows as
// normal.
- WindowManagerState* wms = display_root->window_manager_state();
window_server_->StartDragLoop(change_id, window, this);
wms->SetDragDropSourceWindow(this, window, this, drag_data, drag_operation);
}
@@ -1880,7 +2032,7 @@ void WindowTree::CancelWindowMove(Id window_id) {
}
void WindowTree::AddAccelerators(
- std::vector<mojom::AcceleratorPtr> accelerators,
+ std::vector<mojom::WmAcceleratorPtr> accelerators,
const AddAcceleratorsCallback& callback) {
DCHECK(window_manager_state_);
@@ -1953,6 +2105,12 @@ void WindowTree::SetExtendedHitArea(Id window_id, const gfx::Insets& hit_area) {
window->set_extended_hit_test_region(hit_area);
}
+void WindowTree::SetDisplayRoot(int64_t display_id,
+ Id window_id,
+ const SetDisplayRootCallback& callback) {
+ callback.Run(ProcessSetDisplayRoot(display_id, ClientWindowId(window_id)));
+}
+
void WindowTree::WmResponse(uint32_t change_id, bool response) {
if (window_server_->in_move_loop() &&
window_server_->GetCurrentMoveLoopChangeId() == change_id) {
@@ -1974,7 +2132,8 @@ void WindowTree::WmResponse(uint32_t change_id, bool response) {
if (!response && window) {
// Our move loop didn't succeed, which means that we must restore the
// original bounds of the window.
- window->SetBounds(window_server_->GetCurrentMoveLoopRevertBounds());
+ window->SetBounds(window_server_->GetCurrentMoveLoopRevertBounds(),
+ base::nullopt);
}
window_server_->EndMoveLoop();
@@ -1983,6 +2142,13 @@ void WindowTree::WmResponse(uint32_t change_id, bool response) {
window_server_->WindowManagerChangeCompleted(change_id, response);
}
+void WindowTree::WmSetBoundsResponse(uint32_t change_id) {
+ // The window manager will always give a response of false to the client
+ // because it will always update the bounds of the top level window itself
+ // which will overwrite the request made by the client.
+ WmResponse(change_id, false);
+}
+
void WindowTree::WmRequestClose(Id transport_window_id) {
ServerWindow* window =
GetWindowByClientId(ClientWindowId(transport_window_id));
@@ -2000,7 +2166,7 @@ void WindowTree::WmSetFrameDecorationValues(
}
void WindowTree::WmSetNonClientCursor(uint32_t window_id,
- mojom::Cursor cursor_id) {
+ mojom::CursorType cursor_id) {
DCHECK(window_manager_state_);
ServerWindow* window = GetWindowByClientId(ClientWindowId(window_id));
if (window) {
@@ -2019,11 +2185,17 @@ void WindowTree::OnWmCreatedTopLevelWindow(uint32_t change_id,
window_server_->WindowManagerSentBogusMessage();
window = nullptr;
}
+ if (window) {
+ client()->OnFrameSinkIdAllocated(transport_window_id,
+ window->frame_sink_id());
+ }
window_server_->WindowManagerCreatedTopLevelWindow(this, change_id, window);
}
void WindowTree::OnAcceleratorAck(uint32_t event_id,
- mojom::EventResult result) {
+ mojom::EventResult result,
+ const EventProperties& properties) {
+ DVLOG(3) << "OnAcceleratorAck client=" << id_;
if (event_ack_id_ == 0 || event_id != event_ack_id_) {
DVLOG(1) << "OnAcceleratorAck supplied invalid event_id";
window_server_->WindowManagerSentBogusMessage();
@@ -2031,7 +2203,7 @@ void WindowTree::OnAcceleratorAck(uint32_t event_id,
}
event_ack_id_ = 0;
DCHECK(window_manager_state_);
- window_manager_state_->OnAcceleratorAck(result);
+ window_manager_state_->OnAcceleratorAck(result, properties);
}
bool WindowTree::HasRootForAccessPolicy(const ServerWindow* window) const {
@@ -2062,6 +2234,27 @@ bool WindowTree::IsWindowCreatedByWindowManager(
window->id().client_id;
}
+void WindowTree::OnDragMoved(const gfx::Point& location) {
+ DCHECK(window_server_->in_drag_loop());
+ DCHECK_EQ(this, window_server_->GetCurrentDragLoopInitiator());
+
+ ServerWindow* window = window_server_->GetCurrentDragLoopWindow();
+ WindowManagerDisplayRoot* display_root = GetWindowManagerDisplayRoot(window);
+ if (!display_root)
+ return;
+
+ if (drag_move_state_) {
+ drag_move_state_->has_queued_drag_window_move = true;
+ drag_move_state_->queued_cursor_location = location;
+ } else {
+ WindowManagerState* wms = display_root->window_manager_state();
+ drag_move_state_ = base::MakeUnique<DragMoveState>();
+ wms->window_tree()->window_manager_internal_->WmMoveDragImage(
+ location, base::Bind(&WindowTree::OnWmMoveDragImageAck,
+ drag_weak_factory_.GetWeakPtr()));
+ }
+}
+
void WindowTree::OnDragCompleted(bool success, uint32_t action_taken) {
DCHECK(window_server_->in_drag_loop());
@@ -2077,6 +2270,8 @@ void WindowTree::OnDragCompleted(bool success, uint32_t action_taken) {
window_server_->EndDragLoop();
WindowManagerState* wms = display_root->window_manager_state();
wms->EndDragDrop();
+ wms->window_tree()->window_manager_internal_->WmDestroyDragImage();
+ drag_weak_factory_.InvalidateWeakPtrs();
client()->OnPerformDragDropCompleted(change_id, success, action_taken);
}
diff --git a/chromium/services/ui/ws/window_tree.h b/chromium/services/ui/ws/window_tree.h
index 6fc0a9667b5..fd7da3ac691 100644
--- a/chromium/services/ui/ws/window_tree.h
+++ b/chromium/services/ui/ws/window_tree.h
@@ -17,6 +17,7 @@
#include "base/callback.h"
#include "base/macros.h"
+#include "base/memory/weak_ptr.h"
#include "cc/ipc/surface_id.mojom.h"
#include "mojo/public/cpp/bindings/associated_binding.h"
#include "services/ui/public/interfaces/window_tree.mojom.h"
@@ -77,8 +78,13 @@ class WindowTree : public mojom::WindowTree,
void Init(std::unique_ptr<WindowTreeBinding> binding,
mojom::WindowTreePtr tree);
- // Called if this WindowTree hosts a WindowManager.
- void ConfigureWindowManager();
+ // Called if this WindowTree hosts a WindowManager. See mojom for details
+ // on |automatically_create_display_roots|.
+ void ConfigureWindowManager(bool automatically_create_display_roots);
+
+ bool automatically_create_display_roots() const {
+ return automatically_create_display_roots_;
+ }
ClientSpecificId id() const { return id_; }
@@ -173,14 +179,14 @@ class WindowTree : public mojom::WindowTree,
bool AddTransientWindow(const ClientWindowId& window_id,
const ClientWindowId& transient_window_id);
bool DeleteWindow(const ClientWindowId& window_id);
- bool SetModal(const ClientWindowId& window_id);
+ bool SetModalType(const ClientWindowId& window_id, ModalType modal_type);
std::vector<const ServerWindow*> GetWindowTree(
const ClientWindowId& window_id) const;
bool SetWindowVisibility(const ClientWindowId& window_id, bool visible);
bool SetWindowOpacity(const ClientWindowId& window_id, float opacity);
bool SetFocus(const ClientWindowId& window_id);
bool Embed(const ClientWindowId& window_id,
- mojom::WindowTreeClientPtr client,
+ mojom::WindowTreeClientPtr window_tree_client,
uint32_t flags);
void DispatchInputEvent(ServerWindow* target, const ui::Event& event);
@@ -211,10 +217,12 @@ class WindowTree : public mojom::WindowTree,
// The following methods are invoked after the corresponding change has been
// processed. They do the appropriate bookkeeping and update the client as
// necessary.
- void ProcessWindowBoundsChanged(const ServerWindow* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds,
- bool originated_change);
+ void ProcessWindowBoundsChanged(
+ const ServerWindow* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ bool originated_change,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id);
void ProcessClientAreaChanged(
const ServerWindow* window,
const gfx::Insets& new_client_area,
@@ -244,7 +252,7 @@ class WindowTree : public mojom::WindowTree,
float new_opacity,
bool originated_change);
void ProcessCursorChanged(const ServerWindow* window,
- mojom::Cursor cursor_id,
+ mojom::CursorType cursor_id,
bool originated_change);
void ProcessFocusChanged(const ServerWindow* old_focused_window,
const ServerWindow* new_focused_window);
@@ -370,6 +378,15 @@ class WindowTree : public mojom::WindowTree,
void NotifyChangeCompleted(uint32_t change_id,
mojom::WindowManagerErrorCode error_code);
+ // Callback for when WmMoveDragImage completes. This sends off the next
+ // queued move under the image if the mouse had further moves while we were
+ // waiting for the last move to be acknowledged.
+ void OnWmMoveDragImageAck();
+
+ // Called from SetDisplayRoot(), see mojom for details.
+ bool ProcessSetDisplayRoot(int64_t display_id,
+ const ClientWindowId& client_window_id);
+
// WindowTree:
void NewWindow(uint32_t change_id,
Id transport_window_id,
@@ -389,7 +406,7 @@ class WindowTree : public mojom::WindowTree,
Id transient_window) override;
void RemoveTransientWindowFromParent(uint32_t change_id,
Id transient_window_id) override;
- void SetModal(uint32_t change_id, Id window_id) override;
+ void SetModalType(uint32_t change_id, Id window_id, ModalType type) override;
void ReorderWindow(uint32_t change_Id,
Id window_id,
Id relative_window_id,
@@ -402,9 +419,11 @@ class WindowTree : public mojom::WindowTree,
void ReleaseCapture(uint32_t change_id, Id window_id) override;
void StartPointerWatcher(bool want_moves) override;
void StopPointerWatcher() override;
- void SetWindowBounds(uint32_t change_id,
- Id window_id,
- const gfx::Rect& bounds) override;
+ void SetWindowBounds(
+ uint32_t change_id,
+ Id window_id,
+ const gfx::Rect& bounds,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) override;
void SetWindowVisibility(uint32_t change_id,
Id window_id,
bool visible) override;
@@ -430,7 +449,7 @@ class WindowTree : public mojom::WindowTree,
mojom::EventTargetingPolicy policy) override;
void SetPredefinedCursor(uint32_t change_id,
Id transport_window_id,
- ui::mojom::Cursor cursor_id) override;
+ ui::mojom::CursorType cursor_id) override;
void SetWindowTextInputState(Id transport_window_id,
mojo::TextInputStatePtr state) override;
void SetImeVisibility(Id transport_window_id,
@@ -456,8 +475,12 @@ class WindowTree : public mojom::WindowTree,
void PerformDragDrop(
uint32_t change_id,
Id source_window_id,
+ const gfx::Point& screen_location,
const std::unordered_map<std::string, std::vector<uint8_t>>& drag_data,
- uint32_t drag_operation) override;
+ const SkBitmap& drag_image,
+ const gfx::Vector2d& drag_image_offset,
+ uint32_t drag_operation,
+ ui::mojom::PointerKind source) override;
void CancelDragDrop(Id window_id) override;
void PerformWindowMove(uint32_t change_id,
Id window_id,
@@ -466,22 +489,30 @@ class WindowTree : public mojom::WindowTree,
void CancelWindowMove(Id window_id) override;
// mojom::WindowManagerClient:
- void AddAccelerators(std::vector<mojom::AcceleratorPtr> accelerators,
+ void AddAccelerators(std::vector<mojom::WmAcceleratorPtr> accelerators,
const AddAcceleratorsCallback& callback) override;
void RemoveAccelerator(uint32_t id) override;
void AddActivationParent(Id transport_window_id) override;
void RemoveActivationParent(Id transport_window_id) override;
void ActivateNextWindow() override;
void SetExtendedHitArea(Id window_id, const gfx::Insets& hit_area) override;
+ void SetDisplayRoot(int64_t display_id,
+ Id window_id,
+ const SetDisplayRootCallback& callback) override;
void WmResponse(uint32_t change_id, bool response) override;
+ void WmSetBoundsResponse(uint32_t change_id) override;
void WmRequestClose(Id transport_window_id) override;
void WmSetFrameDecorationValues(
mojom::FrameDecorationValuesPtr values) override;
void WmSetNonClientCursor(uint32_t window_id,
- mojom::Cursor cursor_id) override;
+ mojom::CursorType cursor_id) override;
void OnWmCreatedTopLevelWindow(uint32_t change_id,
Id transport_window_id) override;
- void OnAcceleratorAck(uint32_t event_id, mojom::EventResult result) override;
+ void OnAcceleratorAck(
+ uint32_t event_id,
+ mojom::EventResult result,
+ const std::unordered_map<std::string, std::vector<uint8_t>>& properties)
+ override;
// AccessPolicyDelegate:
bool HasRootForAccessPolicy(const ServerWindow* window) const override;
@@ -492,6 +523,7 @@ class WindowTree : public mojom::WindowTree,
const ServerWindow* window) const override;
// 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(
@@ -569,15 +601,28 @@ class WindowTree : public mojom::WindowTree,
std::queue<std::unique_ptr<TargetedEvent>> event_queue_;
+ // TODO(sky): move all window manager specific state into struct to make it
+ // clear what applies only to the window manager.
std::unique_ptr<mojo::AssociatedBinding<mojom::WindowManagerClient>>
window_manager_internal_client_binding_;
mojom::WindowManager* window_manager_internal_;
std::unique_ptr<WindowManagerState> window_manager_state_;
+ // See mojom for details.
+ bool automatically_create_display_roots_ = true;
std::unique_ptr<WaitingForTopLevelWindowInfo>
waiting_for_top_level_window_info_;
bool embedder_intercepts_events_ = false;
+ // State kept while we're waiting for the window manager to ack a
+ // WmMoveDragImage. Non-null while we're waiting for a response.
+ struct DragMoveState;
+ std::unique_ptr<DragMoveState> drag_move_state_;
+
+ // A weak ptr factory for callbacks from the window manager for when we send
+ // a image move. All weak ptrs are invalidated when a drag is completed.
+ base::WeakPtrFactory<WindowTree> drag_weak_factory_;
+
DISALLOW_COPY_AND_ASSIGN(WindowTree);
};
diff --git a/chromium/services/ui/ws/window_tree_client_unittest.cc b/chromium/services/ui/ws/window_tree_client_unittest.cc
index dbdbc4bc887..06f676217fc 100644
--- a/chromium/services/ui/ws/window_tree_client_unittest.cc
+++ b/chromium/services/ui/ws/window_tree_client_unittest.cc
@@ -11,10 +11,11 @@
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/stringprintf.h"
+#include "cc/surfaces/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/interface_factory.h"
-#include "services/service_manager/public/cpp/interface_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"
@@ -23,7 +24,6 @@
#include "services/ui/ws/test_change_tracker.h"
#include "services/ui/ws/window_server_service_test_base.h"
-using service_manager::Connection;
using mojo::InterfaceRequest;
using service_manager::Service;
using ui::mojom::WindowDataPtr;
@@ -236,7 +236,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
return WaitForChangeCompleted(change_id);
}
- bool SetPredefinedCursor(Id window_id, mojom::Cursor cursor) {
+ bool SetPredefinedCursor(Id window_id, mojom::CursorType cursor) {
const uint32_t change_id = GetAndAdvanceChangeId();
tree()->SetPredefinedCursor(change_id, window_id, cursor);
return WaitForChangeCompleted(change_id);
@@ -273,18 +273,21 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
}
// WindowTreeClient:
- void OnEmbed(ClientSpecificId client_id,
- WindowDataPtr root,
- mojom::WindowTreePtr tree,
- int64_t display_id,
- Id focused_window_id,
- bool drawn) override {
+ void OnEmbed(
+ ClientSpecificId client_id,
+ WindowDataPtr root,
+ mojom::WindowTreePtr tree,
+ int64_t display_id,
+ Id focused_window_id,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::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);
client_id_ = client_id;
- tracker()->OnEmbed(client_id, std::move(root), drawn);
+ tracker()->OnEmbed(client_id, std::move(root), drawn, frame_sink_id);
if (embed_run_loop_)
embed_run_loop_->Quit();
}
@@ -296,21 +299,30 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
Id old_capture_window_id) override {
tracker()->OnCaptureChanged(new_capture_window_id, old_capture_window_id);
}
- void OnTopLevelCreated(uint32_t change_id,
- mojom::WindowDataPtr data,
- int64_t display_id,
- bool drawn) override {
- tracker()->OnTopLevelCreated(change_id, std::move(data), drawn);
- }
- void OnWindowBoundsChanged(Id window_id,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) override {
+ void OnFrameSinkIdAllocated(Id window_id,
+ const cc::FrameSinkId& frame_sink_id) override {}
+ void OnTopLevelCreated(
+ uint32_t change_id,
+ mojom::WindowDataPtr data,
+ int64_t display_id,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) override {
+ tracker()->OnTopLevelCreated(change_id, std::move(data), drawn,
+ frame_sink_id);
+ }
+ void OnWindowBoundsChanged(
+ Id window_id,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds,
+ const base::Optional<cc::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);
+ tracker()->OnWindowBoundsChanged(window_id, old_bounds, new_bounds,
+ local_surface_id);
}
void OnClientAreaChanged(
uint32_t window_id,
@@ -374,7 +386,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
// TODO(sky): add testing coverage.
void OnWindowFocused(uint32_t focused_window_id) override {}
void OnWindowPredefinedCursorChanged(uint32_t window_id,
- mojom::Cursor cursor_id) override {
+ mojom::CursorType cursor_id) override {
tracker_.OnWindowPredefinedCursorChanged(window_id, cursor_id);
}
@@ -437,9 +449,12 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
// mojom::WindowManager:
void OnConnect(uint16_t client_id) override {}
- void WmNewDisplayAdded(const display::Display& display,
- mojom::WindowDataPtr root_data,
- bool drawn) override {
+ void WmNewDisplayAdded(
+ const display::Display& display,
+ mojom::WindowDataPtr root_data,
+ bool drawn,
+ const cc::FrameSinkId& frame_sink_id,
+ const base::Optional<cc::LocalSurfaceId>& local_surface_id) override {
NOTIMPLEMENTED();
}
void WmDisplayRemoved(int64_t display_id) override { NOTIMPLEMENTED(); }
@@ -458,6 +473,7 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
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,
@@ -470,6 +486,15 @@ class TestWindowTreeClient : public mojom::WindowTreeClient,
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,
@@ -641,6 +666,9 @@ class WindowTreeClientTest : public WindowServerServiceTestBase {
}
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()));
if (client_id)
@@ -649,14 +677,16 @@ class WindowTreeClientTest : public WindowServerServiceTestBase {
}
// WindowServerServiceTestBase:
- bool OnConnect(const service_manager::Identity& remote_identity,
- service_manager::InterfaceRegistry* registry) override {
- registry->AddInterface(client_factory_.get());
- return true;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
void SetUp() override {
client_factory_ = base::MakeUnique<WindowTreeClientFactory>();
+ registry_.AddInterface(client_factory_.get());
WindowServerServiceTestBase::SetUp();
@@ -707,6 +737,7 @@ class WindowTreeClientTest : public WindowServerServiceTestBase {
int client_id_1_;
int client_id_2_;
Id root_window_id_;
+ service_manager::BinderRegistry registry_;
DISALLOW_COPY_AND_ASSIGN(WindowTreeClientTest);
};
@@ -1321,17 +1352,21 @@ TEST_F(WindowTreeClientTest, SetWindowBounds) {
wt_client2_->set_track_root_bounds_changes(true);
- wt1()->SetWindowBounds(10, window_1_1, gfx::Rect(0, 0, 100, 100));
+ cc::LocalSurfaceIdAllocator allocator;
+ cc::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);
EXPECT_EQ("BoundsChanged window=" + IdToString(window_1_1) +
- " old_bounds=0,0 0x0 new_bounds=0,0 100x100",
+ " 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, window_1_1, gfx::Rect(0, 0, 0, 0));
+ wt2()->SetWindowBounds(11, window_1_1, gfx::Rect(0, 0, 0, 0), base::nullopt);
ASSERT_FALSE(wt_client2()->WaitForChangeCompleted(11));
}
@@ -1604,7 +1639,7 @@ TEST_F(WindowTreeClientTest, SetCursor) {
changes2()->clear();
ASSERT_TRUE(
- wt_client1()->SetPredefinedCursor(window_1_1, mojom::Cursor::IBEAM));
+ wt_client1()->SetPredefinedCursor(window_1_1, mojom::CursorType::IBEAM));
wt_client2_->WaitForChangeCount(1u);
EXPECT_EQ("CursorChanged id=" + IdToString(window_1_1) + " cursor_id=4",
@@ -1720,7 +1755,9 @@ TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications2) {
// Establish the second client at 1,2.
ASSERT_NO_FATAL_FAILURE(EstablishSecondClientWithRoot(window_1_2));
- EXPECT_EQ("OnEmbed drawn=true", SingleChangeToDescription2(*changes2()));
+ EXPECT_EQ(
+ base::StringPrintf("OnEmbed FrameSinkId(%d, 0) drawn=true", window_1_2),
+ SingleChangeToDescription2(*changes2()));
changes2()->clear();
// Show 1,2 from client 1. Client 2 should see this.
@@ -1744,8 +1781,13 @@ TEST_F(WindowTreeClientTest, SetWindowVisibilityNotifications3) {
ASSERT_TRUE(wt_client1()->AddWindow(window_1_1, window_1_2));
// Establish the second client at 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));
- EXPECT_EQ("OnEmbed drawn=false", SingleChangeToDescription2(*changes2()));
+ EXPECT_EQ(
+ base::StringPrintf("OnEmbed FrameSinkId(%d, 0) drawn=false", window_1_2),
+ SingleChangeToDescription2(*changes2()));
changes2()->clear();
// Show 1,1, drawn should be true for 1,2 (as that is all the child sees).
@@ -2068,12 +2110,14 @@ TEST_F(WindowTreeClientTest, Ids) {
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));
+ 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",
- SingleChangeToDescription(*changes1()));
+ 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.
@@ -2175,6 +2219,7 @@ TEST_F(WindowTreeClientTest, SurfaceIdPropagation) {
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 = cc::BeginFrameAck(0, 1, 1, true);
cc::LocalSurfaceId local_surface_id(1, base::UnguessableToken::Create());
surface_ptr->SubmitCompositorFrame(local_surface_id,
std::move(compositor_frame));
diff --git a/chromium/services/ui/ws/window_tree_host_factory.cc b/chromium/services/ui/ws/window_tree_host_factory.cc
index 1a2170b0a67..1efbf9b5a42 100644
--- a/chromium/services/ui/ws/window_tree_host_factory.cc
+++ b/chromium/services/ui/ws/window_tree_host_factory.cc
@@ -4,6 +4,7 @@
#include "services/ui/ws/window_tree_host_factory.h"
+#include "services/ui/display/viewport_metrics.h"
#include "services/ui/ws/display.h"
#include "services/ui/ws/display_binding.h"
#include "services/ui/ws/window_server.h"
@@ -13,12 +14,7 @@ namespace ws {
WindowTreeHostFactory::WindowTreeHostFactory(WindowServer* window_server,
const UserId& user_id)
- : window_server_(window_server), user_id_(user_id) {
- platform_display_init_params_.metrics.bounds.set_width(1024);
- platform_display_init_params_.metrics.bounds.set_height(768);
- platform_display_init_params_.metrics.pixel_size.SetSize(1024, 768);
- platform_display_init_params_.metrics.device_scale_factor = 1.0f;
-}
+ : window_server_(window_server), user_id_(user_id) {}
WindowTreeHostFactory::~WindowTreeHostFactory() {}
@@ -30,11 +26,22 @@ void WindowTreeHostFactory::AddBinding(
void WindowTreeHostFactory::CreateWindowTreeHost(
mojom::WindowTreeHostRequest host,
mojom::WindowTreeClientPtr tree_client) {
- Display* display = new Display(window_server_);
+ Display* ws_display = new Display(window_server_);
+
std::unique_ptr<DisplayBindingImpl> display_binding(
- new DisplayBindingImpl(std::move(host), display, user_id_,
+ new DisplayBindingImpl(std::move(host), ws_display, user_id_,
std::move(tree_client), window_server_));
- display->Init(platform_display_init_params_, std::move(display_binding));
+
+ // Provide an initial size for the WindowTreeHost.
+ display::ViewportMetrics metrics;
+ metrics.bounds_in_pixels = gfx::Rect(1024, 768);
+ metrics.device_scale_factor = 1.0f;
+ metrics.ui_scale_factor = 1.0f;
+
+ display::Display display(1, metrics.bounds_in_pixels);
+ ws_display->SetDisplay(display);
+
+ ws_display->Init(metrics, std::move(display_binding));
}
} // namespace ws
diff --git a/chromium/services/ui/ws/window_tree_host_factory.h b/chromium/services/ui/ws/window_tree_host_factory.h
index 0fa3d514e69..f1461744b8b 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.mojom.h"
-#include "services/ui/ws/platform_display_init_params.h"
#include "services/ui/ws/user_id.h"
namespace ui {
@@ -31,7 +30,6 @@ class WindowTreeHostFactory : public mojom::WindowTreeHostFactory {
WindowServer* window_server_;
const UserId user_id_;
- PlatformDisplayInitParams platform_display_init_params_;
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 c10a22b9f16..9bea9469b86 100644
--- a/chromium/services/ui/ws/window_tree_unittest.cc
+++ b/chromium/services/ui/ws/window_tree_unittest.cc
@@ -21,7 +21,6 @@
#include "services/ui/ws/ids.h"
#include "services/ui/ws/platform_display.h"
#include "services/ui/ws/platform_display_factory.h"
-#include "services/ui/ws/platform_display_init_params.h"
#include "services/ui/ws/server_window.h"
#include "services/ui/ws/test_change_tracker.h"
#include "services/ui/ws/test_server_window_delegate.h"
@@ -59,13 +58,15 @@ ClientWindowId BuildClientWindowId(WindowTree* tree,
// -----------------------------------------------------------------------------
ui::PointerEvent CreatePointerDownEvent(int x, int y) {
- return ui::PointerEvent(ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(x, y),
- 1, ui::EventTimeForNow()));
+ return ui::PointerEvent(ui::TouchEvent(
+ ui::ET_TOUCH_PRESSED, gfx::Point(x, y), ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
}
ui::PointerEvent CreatePointerUpEvent(int x, int y) {
return ui::PointerEvent(ui::TouchEvent(
- ui::ET_TOUCH_RELEASED, gfx::Point(x, y), 1, ui::EventTimeForNow()));
+ ui::ET_TOUCH_RELEASED, gfx::Point(x, y), ui::EventTimeForNow(),
+ ui::PointerDetails(ui::EventPointerType::POINTER_TYPE_TOUCH, 1)));
}
ui::PointerEvent CreatePointerWheelEvent(int x, int y) {
@@ -128,7 +129,7 @@ class WindowTreeTest : public testing::Test {
WindowTreeTest() {}
~WindowTreeTest() override {}
- ui::mojom::Cursor cursor_id() {
+ ui::mojom::CursorType cursor_id() {
return window_event_targeting_helper_.cursor();
}
Display* display() { return window_event_targeting_helper_.display(); }
@@ -146,7 +147,8 @@ class WindowTreeTest : public testing::Test {
}
void DispatchEventWithoutAck(const ui::Event& event) {
- DisplayTestApi(display()).OnEvent(event);
+ std::unique_ptr<Event> tmp = ui::Event::Clone(event);
+ DisplayTestApi(display()).OnEvent(tmp.get());
}
void set_window_manager_internal(WindowTree* tree,
@@ -473,11 +475,11 @@ TEST_F(WindowTreeTest, CursorChangesWhenMouseOverWindowAndWindowSetsCursor) {
DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
// Set the cursor on the parent as that is where the cursor is picked up from.
- window->parent()->SetPredefinedCursor(mojom::Cursor::IBEAM);
+ window->parent()->SetPredefinedCursor(mojom::CursorType::IBEAM);
// Because the cursor is over the window when SetCursor was called, we should
// have immediately changed the cursor.
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
+ EXPECT_EQ(mojom::CursorType::IBEAM, cursor_id());
}
TEST_F(WindowTreeTest, CursorChangesWhenEnteringWindowWithDifferentCursor) {
@@ -490,11 +492,11 @@ TEST_F(WindowTreeTest, CursorChangesWhenEnteringWindowWithDifferentCursor) {
// inside.
DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
// Set the cursor on the parent as that is where the cursor is picked up from.
- window->parent()->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::POINTER, cursor_id());
+ window->parent()->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ EXPECT_EQ(mojom::CursorType::POINTER, cursor_id());
DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
+ EXPECT_EQ(mojom::CursorType::IBEAM, cursor_id());
}
TEST_F(WindowTreeTest, TouchesDontChangeCursor) {
@@ -506,12 +508,12 @@ TEST_F(WindowTreeTest, TouchesDontChangeCursor) {
// Let's create a pointer event outside the window and then move the pointer
// inside.
DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
- window->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::POINTER, cursor_id());
+ window->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ EXPECT_EQ(mojom::CursorType::POINTER, cursor_id());
// With a touch event, we shouldn't update the cursor.
DispatchEventAndAckImmediately(CreatePointerDownEvent(21, 22));
- EXPECT_EQ(mojom::Cursor::POINTER, cursor_id());
+ EXPECT_EQ(mojom::CursorType::POINTER, cursor_id());
}
TEST_F(WindowTreeTest, DragOutsideWindow) {
@@ -524,25 +526,25 @@ TEST_F(WindowTreeTest, DragOutsideWindow) {
// change the cursor.
DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
// Set the cursor on the parent as that is where the cursor is picked up from.
- window->parent()->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::POINTER, cursor_id());
+ window->parent()->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ EXPECT_EQ(mojom::CursorType::POINTER, cursor_id());
// Move the pointer to the inside of the window
DispatchEventAndAckImmediately(CreateMouseMoveEvent(21, 22));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
+ EXPECT_EQ(mojom::CursorType::IBEAM, cursor_id());
// Start the drag.
DispatchEventAndAckImmediately(CreateMouseDownEvent(21, 22));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
+ EXPECT_EQ(mojom::CursorType::IBEAM, cursor_id());
// Move the cursor (mouse is still down) outside the window.
DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
+ EXPECT_EQ(mojom::CursorType::IBEAM, cursor_id());
// Release the cursor. We should now adapt the cursor of the window
// underneath the pointer.
DispatchEventAndAckImmediately(CreateMouseUpEvent(5, 5));
- EXPECT_EQ(mojom::Cursor::POINTER, cursor_id());
+ EXPECT_EQ(mojom::CursorType::POINTER, cursor_id());
}
TEST_F(WindowTreeTest, ChangingWindowBoundsChangesCursor) {
@@ -554,17 +556,17 @@ TEST_F(WindowTreeTest, ChangingWindowBoundsChangesCursor) {
// Put the cursor just outside the bounds of the window.
DispatchEventAndAckImmediately(CreateMouseMoveEvent(41, 41));
// Sets the cursor on the root as that is where the cursor is picked up from.
- window->parent()->SetPredefinedCursor(mojom::Cursor::IBEAM);
- EXPECT_EQ(mojom::Cursor::POINTER, cursor_id());
+ window->parent()->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ EXPECT_EQ(mojom::CursorType::POINTER, cursor_id());
// Expand the bounds of the window so they now include where the cursor now
// is.
window->SetBounds(gfx::Rect(20, 20, 25, 25));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
+ EXPECT_EQ(mojom::CursorType::IBEAM, cursor_id());
// Contract the bounds again.
window->SetBounds(gfx::Rect(20, 20, 20, 20));
- EXPECT_EQ(mojom::Cursor::POINTER, cursor_id());
+ EXPECT_EQ(mojom::CursorType::POINTER, cursor_id());
}
TEST_F(WindowTreeTest, WindowReorderingChangesCursor) {
@@ -581,14 +583,14 @@ TEST_F(WindowTreeTest, WindowReorderingChangesCursor) {
mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
embed_window2->set_event_targeting_policy(
mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
- embed_window1->SetPredefinedCursor(mojom::Cursor::IBEAM);
- embed_window2->SetPredefinedCursor(mojom::Cursor::CROSS);
+ embed_window1->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ embed_window2->SetPredefinedCursor(mojom::CursorType::CROSS);
DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
// Cursor should match that of top-most window, which is |embed_window2|.
- EXPECT_EQ(mojom::Cursor::CROSS, cursor_id());
+ EXPECT_EQ(mojom::CursorType::CROSS, cursor_id());
// Move |embed_window1| on top, cursor should now match it.
embed_window1->parent()->StackChildAtTop(embed_window1);
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
+ EXPECT_EQ(mojom::CursorType::IBEAM, cursor_id());
}
// Assertions around moving cursor between trees with roots.
@@ -606,9 +608,9 @@ TEST_F(WindowTreeTest, CursorMultipleTrees) {
mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
embed_window2->parent()->set_event_targeting_policy(
mojom::EventTargetingPolicy::TARGET_AND_DESCENDANTS);
- embed_window1->SetPredefinedCursor(mojom::Cursor::IBEAM);
- embed_window2->SetPredefinedCursor(mojom::Cursor::CROSS);
- embed_window1->parent()->SetPredefinedCursor(mojom::Cursor::COPY);
+ embed_window1->SetPredefinedCursor(mojom::CursorType::IBEAM);
+ embed_window2->SetPredefinedCursor(mojom::CursorType::CROSS);
+ embed_window1->parent()->SetPredefinedCursor(mojom::CursorType::COPY);
// Create a child of |embed_window1|.
ServerWindow* embed_window1_child = NewWindowInTreeWithParent(
@@ -619,15 +621,15 @@ TEST_F(WindowTreeTest, CursorMultipleTrees) {
// Move mouse into |embed_window1|.
DispatchEventAndAckImmediately(CreateMouseMoveEvent(5, 5));
- EXPECT_EQ(mojom::Cursor::IBEAM, cursor_id());
+ EXPECT_EQ(mojom::CursorType::IBEAM, cursor_id());
// Move mouse into |embed_window2|.
DispatchEventAndAckImmediately(CreateMouseMoveEvent(25, 25));
- EXPECT_EQ(mojom::Cursor::CROSS, cursor_id());
+ EXPECT_EQ(mojom::CursorType::CROSS, cursor_id());
// Move mouse into area between, which should use cursor set on parent.
DispatchEventAndAckImmediately(CreateMouseMoveEvent(15, 15));
- EXPECT_EQ(mojom::Cursor::COPY, cursor_id());
+ EXPECT_EQ(mojom::CursorType::COPY, cursor_id());
}
TEST_F(WindowTreeTest, EventAck) {
@@ -663,6 +665,34 @@ TEST_F(WindowTreeTest, EventAck) {
ChangesToDescription1(*wm_client()->tracker()->changes())[0]);
}
+// Establish client, call Embed() in WM, make sure to get FrameSinkId.
+TEST_F(WindowTreeTest, Embed) {
+ const ClientWindowId embed_window_id = BuildClientWindowId(wm_tree(), 1);
+ EXPECT_TRUE(
+ wm_tree()->NewWindow(embed_window_id, ServerWindow::Properties()));
+ ServerWindow* embed_window = wm_tree()->GetWindowByClientId(embed_window_id);
+ ASSERT_TRUE(embed_window);
+ const ClientWindowId wm_root_id = FirstRootId(wm_tree());
+ EXPECT_TRUE(wm_tree()->AddWindow(wm_root_id, embed_window_id));
+ ServerWindow* wm_root = FirstRoot(wm_tree());
+ ASSERT_TRUE(wm_root);
+ mojom::WindowTreeClientPtr client;
+ mojom::WindowTreeClientRequest client_request(&client);
+ wm_client()->Bind(std::move(client_request));
+ const uint32_t embed_flags = 0;
+ wm_tree()->Embed(embed_window_id, std::move(client), embed_flags);
+ ASSERT_EQ(1u, wm_client()->tracker()->changes()->size())
+ << SingleChangeToDescription(*wm_client()->tracker()->changes());
+ // The window manager should be told about the FrameSinkId of the embedded
+ // window.
+ EXPECT_EQ(
+ base::StringPrintf(
+ "OnFrameSinkIdAllocated window=%s %s",
+ WindowIdToString(WindowIdFromTransportId(embed_window_id.id)).c_str(),
+ embed_window->frame_sink_id().ToString().c_str()),
+ SingleChangeToDescription(*wm_client()->tracker()->changes()));
+}
+
// Establish client, call NewTopLevelWindow(), make sure get id, and make
// sure client paused.
TEST_F(WindowTreeTest, NewTopLevelWindow) {
@@ -699,19 +729,36 @@ TEST_F(WindowTreeTest, NewTopLevelWindow) {
child_binding->client()->tracker()->changes()->clear();
static_cast<mojom::WindowManagerClient*>(wm_tree())
->OnWmCreatedTopLevelWindow(wm_change_id, embed_window_id2.id);
+
+ ServerWindow* embed_window = wm_tree()->GetWindowByClientId(embed_window_id2);
+ ASSERT_TRUE(embed_window);
+ ASSERT_EQ(1u, wm_client()->tracker()->changes()->size())
+ << SingleChangeToDescription(*wm_client()->tracker()->changes());
+ // The window manager should be told about the FrameSinkId of the embedded
+ // window.
+ EXPECT_EQ(base::StringPrintf(
+ "OnFrameSinkIdAllocated window=%s %s",
+ WindowIdToString(WindowIdFromTransportId(embed_window_id2.id))
+ .c_str(),
+ embed_window->frame_sink_id().ToString().c_str()),
+ SingleChangeToDescription(*wm_client()->tracker()->changes()));
EXPECT_FALSE(child_binding->is_paused());
- EXPECT_EQ("TopLevelCreated id=17 window_id=" +
- WindowIdToString(
- WindowIdFromTransportId(embed_window_id2_in_child.id)) +
- " drawn=true",
- SingleChangeToDescription(
- *child_binding->client()->tracker()->changes()));
+ // 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(
+ base::StringPrintf(
+ "TopLevelCreated id=17 FrameSinkId(%d, 0) window_id=%s drawn=true",
+ WindowIdToTransportId(embed_window->id()),
+ WindowIdToString(
+ WindowIdFromTransportId(embed_window_id2_in_child.id))
+ .c_str()),
+ SingleChangeToDescription(
+ *child_binding->client()->tracker()->changes()));
child_binding->client()->tracker()->changes()->clear();
// Change the visibility of the window from the owner and make sure the
// client sees the right id.
- ServerWindow* embed_window = wm_tree()->GetWindowByClientId(embed_window_id2);
- ASSERT_TRUE(embed_window);
EXPECT_TRUE(embed_window->visible());
ASSERT_TRUE(wm_tree()->SetWindowVisibility(
ClientWindowIdForWindow(wm_tree(), embed_window), false));
@@ -802,7 +849,7 @@ TEST_F(WindowTreeTest, ShowModalWindowWithDescendantCapture) {
w2->SetBounds(gfx::Rect(50, 10, 10, 10));
ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
+ ASSERT_TRUE(tree->SetModalType(w2_id, MODAL_TYPE_WINDOW));
// Set capture to |w11|.
DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
@@ -855,7 +902,7 @@ TEST_F(WindowTreeTest, VisibleWindowToModalWithDescendantCapture) {
// Set |w2| modal to |w1|. This should release the capture as the capture is
// set to a descendant of the modal parent.
ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
+ ASSERT_TRUE(tree->SetModalType(w2_id, MODAL_TYPE_WINDOW));
EXPECT_EQ(nullptr, GetCaptureWindow(display));
}
@@ -874,14 +921,14 @@ TEST_F(WindowTreeTest, ShowModalWindowWithNonDescendantCapture) {
Display* display = tree->GetDisplay(w1);
// Create |w2| as a child of |root_window| and modal to |w1| and leave it
- // hidden..
+ // hidden.
ClientWindowId w2_id = BuildClientWindowId(tree, 2);
ASSERT_TRUE(tree->NewWindow(w2_id, ServerWindow::Properties()));
ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
w2->SetBounds(gfx::Rect(50, 10, 10, 10));
ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
+ ASSERT_TRUE(tree->SetModalType(w2_id, MODAL_TYPE_WINDOW));
// Create |w3| as a child of |root_window| and make it visible.
ClientWindowId w3_id = BuildClientWindowId(tree, 3);
@@ -941,7 +988,7 @@ TEST_F(WindowTreeTest, VisibleWindowToModalWithNonDescendantCapture) {
// Set |w2| modal to |w1|. This should not release the capture as the capture
// is not set to a descendant of the modal parent.
ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
+ ASSERT_TRUE(tree->SetModalType(w2_id, MODAL_TYPE_WINDOW));
EXPECT_EQ(w3, GetCaptureWindow(display));
}
@@ -965,7 +1012,7 @@ TEST_F(WindowTreeTest, ShowSystemModalWindowWithCapture) {
ServerWindow* w2 = tree->GetWindowByClientId(w2_id);
w2->SetBounds(gfx::Rect(30, 10, 10, 10));
ASSERT_TRUE(tree->AddWindow(root_window_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
+ ASSERT_TRUE(tree->SetModalType(w2_id, MODAL_TYPE_SYSTEM));
// Set capture to |w1|.
DispatchEventWithoutAck(CreatePointerDownEvent(15, 15));
@@ -1007,7 +1054,7 @@ TEST_F(WindowTreeTest, VisibleWindowToSystemModalWithCapture) {
AckPreviousEvent();
// Make |w2| modal to system. This should release capture.
- ASSERT_TRUE(tree->SetModal(w2_id));
+ ASSERT_TRUE(tree->SetModalType(w2_id, MODAL_TYPE_SYSTEM));
EXPECT_EQ(nullptr, GetCaptureWindow(display));
}
@@ -1042,7 +1089,7 @@ TEST_F(WindowTreeTest, MoveCaptureWindowToModalParent) {
// Set |w2| modal to |w1|.
ASSERT_TRUE(tree->AddTransientWindow(w1_id, w2_id));
- ASSERT_TRUE(tree->SetModal(w2_id));
+ ASSERT_TRUE(tree->SetModalType(w2_id, MODAL_TYPE_WINDOW));
// Set capture to |w3|.
DispatchEventWithoutAck(CreatePointerDownEvent(25, 25));
@@ -1393,6 +1440,39 @@ TEST_F(WindowTreeTest, CaptureNotifiesWm) {
ChangesToDescription1(*embed_client->tracker()->changes())[0]);
}
+TEST_F(WindowTreeTest, SetModalTypeForwardedToWindowManager) {
+ TestWindowManager wm_internal;
+ set_window_manager_internal(wm_tree(), &wm_internal);
+
+ TestWindowTreeBinding* child_binding = nullptr;
+ WindowTree* child_tree = CreateNewTree(wm_tree()->user_id(), &child_binding);
+
+ // Create a new top level window.
+ std::unordered_map<std::string, std::vector<uint8_t>> properties;
+ const uint32_t initial_change_id = 17;
+ // Explicitly use an id that does not contain the client id.
+ const ClientWindowId embed_window_id2_in_child(45 << 16 | 27);
+ static_cast<mojom::WindowTree*>(child_tree)
+ ->NewTopLevelWindow(initial_change_id, embed_window_id2_in_child.id,
+ properties);
+
+ // Create the window for |embed_window_id2_in_child|.
+ const ClientWindowId embed_window_id2 = BuildClientWindowId(wm_tree(), 2);
+ EXPECT_TRUE(
+ wm_tree()->NewWindow(embed_window_id2, ServerWindow::Properties()));
+ EXPECT_TRUE(wm_tree()->SetWindowVisibility(embed_window_id2, true));
+ EXPECT_TRUE(wm_tree()->AddWindow(FirstRootId(wm_tree()), embed_window_id2));
+
+ // Ack the change, which should resume the binding.
+ static_cast<mojom::WindowManagerClient*>(wm_tree())
+ ->OnWmCreatedTopLevelWindow(0u, embed_window_id2.id);
+
+ // Change modal type to MODAL_TYPE_SYSTEM and check that it is forwarded to
+ // the window manager.
+ child_tree->SetModalType(embed_window_id2_in_child, MODAL_TYPE_SYSTEM);
+ EXPECT_TRUE(wm_internal.on_set_modal_type_called());
+}
+
using WindowTreeShutdownTest = testing::Test;
// Makes sure WindowTreeClient doesn't get any messages during shutdown.
@@ -1425,6 +1505,85 @@ TEST_F(WindowTreeShutdownTest, DontSendMessagesDuringShutdown) {
EXPECT_TRUE(client->tracker()->changes()->empty());
}
+// Used to test the window manager configured to manually create displays roots.
+class WindowTreeManualDisplayTest : public testing::Test {
+ public:
+ WindowTreeManualDisplayTest() {}
+ ~WindowTreeManualDisplayTest() override {}
+
+ WindowServer* window_server() { return ws_test_helper_.window_server(); }
+ DisplayManager* display_manager() {
+ return window_server()->display_manager();
+ }
+ TestWindowServerDelegate* window_server_delegate() {
+ return ws_test_helper_.window_server_delegate();
+ }
+ TestScreenManager& screen_manager() { return screen_manager_; }
+
+ protected:
+ // testing::Test:
+ void SetUp() override {
+ screen_manager_.Init(window_server()->display_manager());
+ window_server()->user_id_tracker()->AddUserId(kTestUserId1);
+ }
+
+ private:
+ WindowServerTestHelper ws_test_helper_;
+ TestScreenManager screen_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(WindowTreeManualDisplayTest);
+};
+
+TEST_F(WindowTreeManualDisplayTest, ClientCreatesDisplayRoot) {
+ const bool automatically_create_display_roots = false;
+ AddWindowManager(window_server(), kTestUserId1,
+ automatically_create_display_roots);
+ const int64_t display_id =
+ screen_manager().AddDisplay(MakeDisplay(0, 0, 1024, 768, 1.0f));
+ WindowManagerState* window_manager_state =
+ window_server()->GetWindowManagerStateForUser(kTestUserId1);
+ ASSERT_TRUE(window_manager_state);
+ WindowTree* window_manager_tree = window_manager_state->window_tree();
+ EXPECT_TRUE(window_manager_tree->roots().empty());
+ TestWindowManager* test_window_manager =
+ window_server_delegate()->last_binding()->window_manager();
+ EXPECT_EQ(1, test_window_manager->connect_count());
+ EXPECT_EQ(0, test_window_manager->display_added_count());
+
+ // Add another display and make sure WindowManager is not updated.
+ screen_manager().AddDisplay(MakeDisplay(0, 0, 1024, 768, 1.0f));
+ EXPECT_EQ(0, test_window_manager->display_added_count());
+
+ // Create a window for the windowmanager and set it as the root.
+ ClientWindowId display_root_id = BuildClientWindowId(window_manager_tree, 10);
+ ASSERT_TRUE(window_manager_tree->NewWindow(display_root_id,
+ ServerWindow::Properties()));
+ ServerWindow* display_root =
+ window_manager_tree->GetWindowByClientId(display_root_id);
+ ASSERT_TRUE(display_root);
+ ASSERT_TRUE(WindowTreeTestApi(window_manager_tree)
+ .ProcessSetDisplayRoot(display_id, display_root_id));
+ EXPECT_TRUE(display_root->parent());
+ EXPECT_TRUE(window_server_delegate()
+ ->last_binding()
+ ->client()
+ ->tracker()
+ ->changes()
+ ->empty());
+ ASSERT_EQ(1u, window_manager_tree->roots().size());
+ EXPECT_EQ(display_root, *window_manager_tree->roots().begin());
+ ASSERT_EQ(2u, WindowManagerStateTestApi(window_manager_state)
+ .window_manager_display_roots()
+ .size());
+
+ // Delete the root, which should delete the WindowManagerDisplayRoot.
+ EXPECT_TRUE(window_manager_tree->DeleteWindow(display_root_id));
+ ASSERT_TRUE(window_manager_tree->roots().empty());
+ ASSERT_EQ(1u, WindowManagerStateTestApi(window_manager_state)
+ .window_manager_display_roots()
+ .size());
+}
+
} // namespace test
} // namespace ws
} // namespace ui
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 a83a1d1ed8d..70292d4e67f 100644
--- a/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc
+++ b/chromium/services/video_capture/receiver_mojo_to_media_adapter.cc
@@ -41,6 +41,10 @@ void ReceiverMojoToMediaAdapter::OnStarted() {
receiver_->OnStarted();
}
+void ReceiverMojoToMediaAdapter::OnStartedUsingGpuDecode() {
+ NOTIMPLEMENTED();
+}
+
void ReceiverMojoToMediaAdapter::OnBufferRetired(int buffer_id) {
NOTIMPLEMENTED();
}
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 5ed9b9e2294..e70358dd74a 100644
--- a/chromium/services/video_capture/receiver_mojo_to_media_adapter.h
+++ b/chromium/services/video_capture/receiver_mojo_to_media_adapter.h
@@ -33,6 +33,7 @@ class ReceiverMojoToMediaAdapter : public media::VideoFrameReceiver {
void OnError() override;
void OnLog(const std::string& message) override;
void OnStarted() override;
+ void OnStartedUsingGpuDecode() override;
private:
mojom::ReceiverPtr receiver_;
diff --git a/chromium/services/video_capture/service_impl.cc b/chromium/services/video_capture/service_impl.cc
index a1fc4336f06..bd3d05017da 100644
--- a/chromium/services/video_capture/service_impl.cc
+++ b/chromium/services/video_capture/service_impl.cc
@@ -10,7 +10,7 @@
#include "media/capture/video/video_capture_buffer_pool.h"
#include "media/capture/video/video_capture_buffer_tracker.h"
#include "media/capture/video/video_capture_jpeg_decoder.h"
-#include "services/service_manager/public/cpp/interface_registry.h"
+#include "services/service_manager/public/cpp/service_info.h"
#include "services/video_capture/device_factory_media_to_mojo_adapter.h"
namespace {
@@ -25,14 +25,18 @@ std::unique_ptr<media::VideoCaptureJpegDecoder> CreateJpegDecoder() {
namespace video_capture {
-ServiceImpl::ServiceImpl() = default;
+ServiceImpl::ServiceImpl() {
+ registry_.AddInterface<mojom::Service>(this);
+}
ServiceImpl::~ServiceImpl() = default;
-bool ServiceImpl::OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) {
- registry->AddInterface<mojom::Service>(this);
- return true;
+void ServiceImpl::OnBindInterface(
+ const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) {
+ registry_.BindInterface(source_info.identity, interface_name,
+ std::move(interface_pipe));
}
void ServiceImpl::Create(const service_manager::Identity& remote_identity,
diff --git a/chromium/services/video_capture/service_impl.h b/chromium/services/video_capture/service_impl.h
index 0b7a611f744..a4aef2add3d 100644
--- a/chromium/services/video_capture/service_impl.h
+++ b/chromium/services/video_capture/service_impl.h
@@ -8,6 +8,7 @@
#include <memory>
#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/interface_factory.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/video_capture/public/interfaces/service.mojom.h"
@@ -25,8 +26,9 @@ class ServiceImpl : public service_manager::Service,
~ServiceImpl() override;
// service_manager::Service:
- bool OnConnect(const service_manager::ServiceInfo& remote_info,
- service_manager::InterfaceRegistry* registry) override;
+ void OnBindInterface(const service_manager::ServiceInfo& source_info,
+ const std::string& interface_name,
+ mojo::ScopedMessagePipeHandle interface_pipe) override;
// service_manager::InterfaceFactory<video_capture::mojom::Service>:
void Create(const service_manager::Identity& remote_identity,
@@ -40,6 +42,7 @@ class ServiceImpl : public service_manager::Service,
void LazyInitializeDeviceFactory();
void LazyInitializeFakeDeviceFactory();
+ service_manager::BinderRegistry registry_;
mojo::BindingSet<mojom::Service> service_bindings_;
mojo::BindingSet<mojom::DeviceFactory> factory_bindings_;
mojo::BindingSet<mojom::DeviceFactory> fake_factory_bindings_;
diff --git a/chromium/services/viz/OWNERS b/chromium/services/viz/OWNERS
new file mode 100644
index 00000000000..0119364bab9
--- /dev/null
+++ b/chromium/services/viz/OWNERS
@@ -0,0 +1,6 @@
+file://gpu/OWNERS
+fsamuel@chromium.org
+rjkroege@chromium.org
+sadrul@chromium.org
+
+# COMPONENT: Internals>GPU>Internals